From c0df8be83237e323c2c9a5bd02507430a86a00cc Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 4 Jun 2026 23:24:29 +0800 Subject: [PATCH 01/19] =?UTF-8?q?perf(settings):=20=E6=96=B0=E5=A2=9ENO=5F?= =?UTF-8?q?PROXY=E4=BB=A3=E7=90=86=E6=8E=92=E9=99=A4=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/basic/src/utils/util.request.test.ts | 124 ++++++++++- packages/core/basic/src/utils/util.request.ts | 202 +++++++++++++++--- .../src/system/settings/service/models.ts | 1 + .../settings/service/sys-settings-service.ts | 1 + .../locales/langs/en-US/certd/sys-settings.ts | 3 + .../locales/langs/zh-CN/certd/sys-settings.ts | 3 + .../src/store/settings/api.basic.ts | 1 + .../src/views/sys/settings/tabs/network.vue | 5 + 8 files changed, 311 insertions(+), 29 deletions(-) diff --git a/packages/core/basic/src/utils/util.request.test.ts b/packages/core/basic/src/utils/util.request.test.ts index cf66ef4cb..6617fe1b8 100644 --- a/packages/core/basic/src/utils/util.request.test.ts +++ b/packages/core/basic/src/utils/util.request.test.ts @@ -1,8 +1,9 @@ import { expect } from "chai"; -import { createAxiosService, HttpClient, setGlobalHeaders } from "./util.request.js"; +import { createAgent, createAxiosService, getGlobalAgents, HttpClient, isNoProxyMatched, setGlobalHeaders, setGlobalProxy } from "./util.request.js"; import { ILogger } from "./util.log.js"; const testLogger = { + debug() {}, info() {}, error() {}, } as unknown as ILogger; @@ -10,6 +11,9 @@ const testLogger = { describe("util.request", () => { afterEach(() => { setGlobalHeaders({}); + setGlobalProxy({}); + delete process.env.NO_PROXY; + delete process.env.no_proxy; }); it("should merge global headers without overriding request headers", async () => { @@ -50,4 +54,122 @@ describe("util.request", () => { request: "request", }); }); + + it("should set no_proxy environment variables", () => { + setGlobalProxy({ + httpProxy: "http://127.0.0.1:1080", + httpsProxy: "http://127.0.0.1:1080", + noProxy: "localhost,*.internal.example.com", + }); + + expect(process.env.NO_PROXY).to.equal("localhost,*.internal.example.com"); + expect(process.env.no_proxy).to.equal("localhost,*.internal.example.com"); + }); + + it("should normalize multiline no_proxy environment variables", () => { + setGlobalProxy({ + noProxy: "localhost\n127.0.0.1, 192.168.*\n*.internal.example.com", + }); + + expect(process.env.NO_PROXY).to.equal("localhost,127.0.0.1,192.168.*,*.internal.example.com"); + expect(process.env.no_proxy).to.equal("localhost,127.0.0.1,192.168.*,*.internal.example.com"); + }); + + it("should not change environment variables when creating agents", () => { + process.env.HTTP_PROXY = "http://old-http-proxy"; + process.env.HTTPS_PROXY = "http://old-https-proxy"; + process.env.NO_PROXY = "old.local"; + + createAgent({ + httpProxy: "http://127.0.0.1:1080", + httpsProxy: "http://127.0.0.1:1081", + }); + + expect(process.env.HTTP_PROXY).to.equal("http://old-http-proxy"); + expect(process.env.HTTPS_PROXY).to.equal("http://old-https-proxy"); + expect(process.env.NO_PROXY).to.equal("old.local"); + }); + + it("should bypass global proxy when request host matches no_proxy", async () => { + setGlobalProxy({ + httpProxy: "http://127.0.0.1:1080", + httpsProxy: "http://127.0.0.1:1080", + noProxy: "localhost,.internal.example.com", + }); + + const globalAgents = getGlobalAgents(); + const http = createAxiosService({ logger: testLogger }) as HttpClient; + const res = await http.request({ + url: "https://api.internal.example.com", + method: "get", + logReq: false, + logRes: false, + adapter: async config => { + return { + config, + data: { + usesGlobalHttpAgent: config.httpAgent === globalAgents.httpAgent, + usesGlobalHttpsAgent: config.httpsAgent === globalAgents.httpsAgent, + }, + headers: {}, + status: 200, + statusText: "OK", + }; + }, + }); + + expect(res).to.deep.equal({ + usesGlobalHttpAgent: false, + usesGlobalHttpsAgent: false, + }); + }); + + it("should bypass custom request proxy when request host matches no_proxy", async () => { + setGlobalProxy({ + noProxy: ".internal.example.com", + }); + + const http = createAxiosService({ logger: testLogger }) as HttpClient; + const res = await http.request({ + url: "https://api.internal.example.com", + method: "get", + httpProxy: "http://127.0.0.1:1080", + logReq: false, + logRes: false, + adapter: async config => { + return { + config, + data: { + httpAgent: config.httpAgent?.constructor?.name, + httpsAgent: config.httpsAgent?.constructor?.name, + }, + headers: {}, + status: 200, + statusText: "OK", + }; + }, + }); + + expect(res).to.deep.equal({ + httpAgent: "Agent", + httpsAgent: "Agent", + }); + }); + + it("should match no_proxy rules", () => { + expect(isNoProxyMatched("*", { hostname: "api.example.com", port: "" })).to.equal(true); + expect(isNoProxyMatched("api.example.com", { hostname: "api.example.com", port: "" })).to.equal(true); + expect(isNoProxyMatched("example.com", { hostname: "api.example.com", port: "" })).to.equal(true); + expect(isNoProxyMatched(".example.com", { hostname: "api.example.com", port: "" })).to.equal(true); + expect(isNoProxyMatched("*.example.com", { hostname: "api.example.com", port: "" })).to.equal(true); + expect(isNoProxyMatched("127.0.0.1", { hostname: "127.0.0.1", port: "" })).to.equal(true); + expect(isNoProxyMatched("192.168.*", { hostname: "192.168.1.10", port: "" })).to.equal(true); + expect(isNoProxyMatched("192.168.*", { hostname: "192.169.1.10", port: "" })).to.equal(false); + expect(isNoProxyMatched("[::1]", { hostname: "::1", port: "" })).to.equal(true); + expect(isNoProxyMatched("[::1]:8443", { hostname: "::1", port: "8443" })).to.equal(true); + expect(isNoProxyMatched("api.example.com:8443", { hostname: "api.example.com", port: "8443" })).to.equal(true); + expect(isNoProxyMatched("api.example.com:8443", { hostname: "api.example.com", port: "443" })).to.equal(false); + expect(isNoProxyMatched("127.0.0.1", { hostname: "127.0.0.2", port: "" })).to.equal(false); + expect(isNoProxyMatched(".example.com", { hostname: "example.org", port: "" })).to.equal(false); + }); }); diff --git a/packages/core/basic/src/utils/util.request.ts b/packages/core/basic/src/utils/util.request.ts index 5c3d81be3..93c800140 100644 --- a/packages/core/basic/src/utils/util.request.ts +++ b/packages/core/basic/src/utils/util.request.ts @@ -82,11 +82,24 @@ export class HttpError extends Error { export const HttpCommonError = HttpError; let defaultAgents = createAgent(); +const directAgents = createAgent(); +let defaultProxyOptions: GlobalProxyOptions = {}; let defaultHeaders: Record = {}; -export function setGlobalProxy(opts: { httpProxy?: string; httpsProxy?: string }) { +export type GlobalProxyOptions = { + httpProxy?: string; + httpsProxy?: string; + noProxy?: string; +}; + +export function setGlobalProxy(opts: GlobalProxyOptions) { logger.info("setGlobalProxy:", opts); - defaultAgents = createAgent(opts); + defaultProxyOptions = { ...opts }; + defaultAgents = createAgent({ + httpProxy: opts.httpProxy, + httpsProxy: opts.httpsProxy, + }); + setProxyEnvironment(opts); } export function getGlobalAgents() { @@ -137,21 +150,25 @@ export function createAxiosService({ logger }: { logger: ILogger }) { if (config.timeout == null) { config.timeout = 15000; } - let agents = defaultAgents; - if (config.skipSslVerify || config.httpProxy) { - let rejectUnauthorized = true; + const bypassProxy = shouldBypassProxy(config, defaultProxyOptions.noProxy); + const useCustomProxy = !!config.httpProxy && !bypassProxy; + let agents = bypassProxy ? directAgents : defaultAgents; + if (bypassProxy) { + logger.info("命中no_proxy配置,跳过代理:", config.url); + } + if (config.skipSslVerify || useCustomProxy) { + const agentOptions: any = {}; if (config.skipSslVerify) { logger.info("忽略接口请求的SSL校验"); - rejectUnauthorized = false; + agentOptions.rejectUnauthorized = false; } - const proxy: any = {}; - if (config.httpProxy) { + if (useCustomProxy) { logger.info("使用自定义http代理:", config.httpProxy); - proxy.httpProxy = config.httpProxy; - proxy.httpsProxy = config.httpProxy; + agentOptions.httpProxy = config.httpProxy; + agentOptions.httpsProxy = config.httpProxy; } - agents = createAgent({ rejectUnauthorized, ...proxy } as any); + agents = createAgent(agentOptions); } delete config.skipSslVerify; @@ -354,7 +371,7 @@ export type CreateAgentOptions = { httpsProxy?: string; } & nodeHttp.AgentOptions; export function createAgent(opts: CreateAgentOptions = {}) { - opts = merge( + const { httpProxy, httpsProxy, ...agentOptions } = merge( { autoSelectFamily: true, autoSelectFamilyAttemptTimeout: 1000, @@ -364,29 +381,19 @@ export function createAgent(opts: CreateAgentOptions = {}) { ); let httpAgent, httpsAgent; - const httpProxy = opts.httpProxy; if (httpProxy) { - process.env.HTTP_PROXY = httpProxy; - process.env.http_proxy = httpProxy; logger.info("use httpProxy:", httpProxy); - httpAgent = new HttpProxyAgent(httpProxy, opts as any); - merge(httpAgent.options, opts); + httpAgent = new HttpProxyAgent(httpProxy, agentOptions as any); + merge(httpAgent.options, agentOptions); } else { - process.env.HTTP_PROXY = ""; - process.env.http_proxy = ""; - httpAgent = new nodeHttp.Agent(opts); + httpAgent = new nodeHttp.Agent(agentOptions); } - const httpsProxy = opts.httpsProxy; if (httpsProxy) { - process.env.HTTPS_PROXY = httpsProxy; - process.env.https_proxy = httpsProxy; logger.info("use httpsProxy:", httpsProxy); - httpsAgent = new HttpsProxyAgent(httpsProxy, opts as any); - merge(httpsAgent.options, opts); + httpsAgent = new HttpsProxyAgent(httpsProxy, agentOptions as any); + merge(httpsAgent.options, agentOptions); } else { - process.env.HTTPS_PROXY = ""; - process.env.https_proxy = ""; - httpsAgent = new https.Agent(opts); + httpsAgent = new https.Agent(agentOptions); } return { httpAgent, @@ -394,6 +401,145 @@ export function createAgent(opts: CreateAgentOptions = {}) { }; } +function setProxyEnvironment(opts: GlobalProxyOptions = {}) { + setEnvValue("HTTP_PROXY", opts.httpProxy); + setEnvValue("http_proxy", opts.httpProxy); + setEnvValue("HTTPS_PROXY", opts.httpsProxy); + setEnvValue("https_proxy", opts.httpsProxy); + const noProxy = normalizeNoProxyText(opts.noProxy); + setEnvValue("NO_PROXY", noProxy); + setEnvValue("no_proxy", noProxy); +} + +function setEnvValue(key: string, value?: string) { + process.env[key] = value || ""; +} + +function shouldBypassProxy(config: AxiosRequestConfig, noProxy?: string) { + if (!noProxy) { + return false; + } + const target = getRequestTarget(config); + if (!target) { + return false; + } + return splitNoProxyRules(noProxy).some(item => isNoProxyMatched(item, target)); +} + +function getRequestTarget(config: AxiosRequestConfig) { + try { + const baseURL = config.baseURL || undefined; + const url = new URL(config.url || "", baseURL); + return { + hostname: normalizeHost(url.hostname), + port: url.port, + }; + } catch (e) { + return null; + } +} + +export function isNoProxyMatched(rule: string, target: { hostname: string; port: string }) { + if (rule === "*") { + return true; + } + + const normalizedRule = normalizeNoProxyRule(rule); + if (!normalizedRule.host) { + return false; + } + if (normalizedRule.port && normalizedRule.port !== target.port) { + return false; + } + + const host = normalizeHost(target.hostname); + if (normalizedRule.host.includes("*")) { + return wildcardHostMatched(normalizedRule.host, host); + } + if (normalizedRule.host.startsWith("*.")) { + const suffix = normalizedRule.host.substring(1); + return host.endsWith(suffix); + } + if (normalizedRule.host.startsWith(".")) { + return host === normalizedRule.host.substring(1) || host.endsWith(normalizedRule.host); + } + return host === normalizedRule.host || host.endsWith(`.${normalizedRule.host}`); +} + +function normalizeNoProxyRule(rule: string) { + let value = rule.trim().toLowerCase(); + if (value.includes("://")) { + try { + const url = new URL(value); + return { + host: normalizeHost(url.hostname), + port: url.port, + }; + } catch (e) { + return { + host: "", + port: "", + }; + } + } + + let port = ""; + if (value.startsWith("[")) { + const closeIndex = value.indexOf("]"); + const host = value.substring(1, closeIndex); + const rest = value.substring(closeIndex + 1); + if (rest.startsWith(":")) { + port = rest.substring(1); + } + return { + host: normalizeHost(host), + port, + }; + } + + const colonCount = (value.match(/:/g) || []).length; + const portIndex = value.lastIndexOf(":"); + if (colonCount === 1 && portIndex > -1) { + port = value.substring(portIndex + 1); + value = value.substring(0, portIndex); + } + return { + host: normalizeHost(value), + port, + }; +} + +function normalizeHost(host: string) { + let value = host.trim().toLowerCase(); + if (value.startsWith("[") && value.endsWith("]")) { + value = value.substring(1, value.length - 1); + } + return value; +} + +function wildcardHostMatched(rule: string, host: string) { + const pattern = rule.split("*").map(escapeRegExp).join(".*"); + return new RegExp(`^${pattern}$`).test(host); +} + +function escapeRegExp(value: string) { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +function normalizeNoProxyText(noProxy?: string) { + return splitNoProxyRules(noProxy).join(","); +} + +function splitNoProxyRules(noProxy?: string) { + if (!noProxy) { + return []; + } + return noProxy + .split(/[,\s]+/) + .map(item => item.trim()) + .filter(Boolean); +} + export async function download(req: { http: HttpClient; config: HttpRequestConfig; savePath: string; logger: ILogger }) { const { http, config, savePath, logger } = req; return safePromise((resolve, reject) => { diff --git a/packages/libs/lib-server/src/system/settings/service/models.ts b/packages/libs/lib-server/src/system/settings/service/models.ts index 58ecf6434..13f701ac4 100644 --- a/packages/libs/lib-server/src/system/settings/service/models.ts +++ b/packages/libs/lib-server/src/system/settings/service/models.ts @@ -81,6 +81,7 @@ export class SysPrivateSettings extends BaseSettings { httpsProxy? = ''; httpProxy? = ''; + noProxy? = ''; commonHeaders?: string = ''; reverseProxies?: Record = {}; diff --git a/packages/libs/lib-server/src/system/settings/service/sys-settings-service.ts b/packages/libs/lib-server/src/system/settings/service/sys-settings-service.ts index 7fa835a9c..b76450e4d 100644 --- a/packages/libs/lib-server/src/system/settings/service/sys-settings-service.ts +++ b/packages/libs/lib-server/src/system/settings/service/sys-settings-service.ts @@ -165,6 +165,7 @@ export class SysSettingsService extends BaseService { const opts = { httpProxy: privateSetting.httpProxy, httpsProxy: privateSetting.httpsProxy, + noProxy: privateSetting.noProxy, }; setGlobalProxy(opts); setGlobalHeaders(this.parseKeyValueText(privateSetting.commonHeaders)); diff --git a/packages/ui/certd-client/src/locales/langs/en-US/certd/sys-settings.ts b/packages/ui/certd-client/src/locales/langs/en-US/certd/sys-settings.ts index cb0089c0f..5a9deec92 100644 --- a/packages/ui/certd-client/src/locales/langs/en-US/certd/sys-settings.ts +++ b/packages/ui/certd-client/src/locales/langs/en-US/certd/sys-settings.ts @@ -111,6 +111,9 @@ export default { httpsProxyPlaceholder: "http://192.168.1.2:18010/", saveThenTestTitle: "Save first, then click test", httpsProxyHelper: "Usually both proxies are the same, save first then test", + noProxy: "Proxy Bypass", + noProxyPlaceholder: "localhost,127.0.0.1,.example.com,192.168.*", + noProxyHelper: "Configure NO_PROXY. Separate entries with commas, spaces, or line breaks; matched requests bypass the proxy. \nExample: localhost,127.0.0.1,.example.com,192.168.*", dualStackNetwork: "Dual Stack Network", ipv4Priority: "IPv4 Priority", ipv6Priority: "IPv6 Priority", diff --git a/packages/ui/certd-client/src/locales/langs/zh-CN/certd/sys-settings.ts b/packages/ui/certd-client/src/locales/langs/zh-CN/certd/sys-settings.ts index 2d1f30028..22a3832cb 100644 --- a/packages/ui/certd-client/src/locales/langs/zh-CN/certd/sys-settings.ts +++ b/packages/ui/certd-client/src/locales/langs/zh-CN/certd/sys-settings.ts @@ -108,6 +108,9 @@ export default { httpsProxyPlaceholder: "http://192.168.1.2:18010/", saveThenTestTitle: "保存后,再点击测试", httpsProxyHelper: "一般这两个代理填一样的,保存后再测试", + noProxy: "代理排除", + noProxyPlaceholder: "localhost,127.0.0.1,.example.com,192.168.*", + noProxyHelper: "配置NO_PROXY,多个地址可用英文逗号、空格或换行分隔,命中的请求将不走代理\n例如:localhost,127.0.0.1,.example.com,192.168.*", dualStackNetwork: "双栈网络", ipv4Priority: "IPV4优先", ipv6Priority: "IPV6优先", diff --git a/packages/ui/certd-client/src/store/settings/api.basic.ts b/packages/ui/certd-client/src/store/settings/api.basic.ts index c6ada0f37..ffc5d2057 100644 --- a/packages/ui/certd-client/src/store/settings/api.basic.ts +++ b/packages/ui/certd-client/src/store/settings/api.basic.ts @@ -105,6 +105,7 @@ export type InviteSetting = { export type SysPrivateSetting = { httpProxy?: string; httpsProxy?: string; + noProxy?: string; commonHeaders?: string; reverseProxies?: any; dnsResultOrder?: string; diff --git a/packages/ui/certd-client/src/views/sys/settings/tabs/network.vue b/packages/ui/certd-client/src/views/sys/settings/tabs/network.vue index b9946267a..6fb163365 100644 --- a/packages/ui/certd-client/src/views/sys/settings/tabs/network.vue +++ b/packages/ui/certd-client/src/views/sys/settings/tabs/network.vue @@ -14,6 +14,11 @@
{{ t("certd.httpsProxyHelper") }}
+ + +
{{ t("certd.noProxyHelper") }}
+
+
{{ t("certd.sys.setting.environmentVarsHelper") }}
From 99fd3083f259cdb96fd656f04858dd708d1251c7 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Thu, 4 Jun 2026 23:43:25 +0800 Subject: [PATCH 02/19] =?UTF-8?q?perf:=20=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E3=80=81=E7=9B=91=E6=8E=A7=E7=AB=99=E7=82=B9=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .trae/skills/fast-crud-page-dev/SKILL.md | 78 +++++++++++ .../src/locales/langs/en-US/certd/common.ts | 1 + .../src/locales/langs/en-US/certd/pipeline.ts | 1 + .../src/locales/langs/zh-CN/certd/common.ts | 1 + .../src/locales/langs/zh-CN/certd/pipeline.ts | 1 + .../src/views/certd/pipeline/crud.tsx | 126 ++++++++++++++++-- .../src/views/sys/pipeline/crud.tsx | 102 ++++++++++++-- .../plugin/cert-plugin/base-convert.ts | 1 + 8 files changed, 285 insertions(+), 26 deletions(-) diff --git a/.trae/skills/fast-crud-page-dev/SKILL.md b/.trae/skills/fast-crud-page-dev/SKILL.md index 43b7bbed4..81c96e0f9 100644 --- a/.trae/skills/fast-crud-page-dev/SKILL.md +++ b/.trae/skills/fast-crud-page-dev/SKILL.md @@ -77,6 +77,84 @@ container:{}, //容器配置 ,对应fs-container - 有固定操作栏、统计区、说明区时,这些区域应 `flex: none`,把剩余空间交给表格区域。 - 修改嵌入式 Fast Crud 页面后,要检查空数据、少量数据和多页数据时表格高度、分页器和空状态是否仍在预期区域内。 +## 列表导出 + +- 列表需要导出时,优先使用 Fast Crud 工具栏导出能力,不要另写一套导出按钮或后端接口,除非数据必须跨权限、跨分页或异步生成文件。 +- 导出当前搜索条件下的数据时,在 `toolbar.export` 中设置 `dataFrom: "search"`,并显式打开导出按钮。 +- 导出列必须输出 Excel 可读的纯文本或数字;不要直接导出对象、数组、VNode、进度条组件、开关组件、时间戳毫秒值等。 +- 有隐藏但业务上需要导出的字段时,把字段定义为普通列并设置 `column.show: false`,再在 `columnFilter` 中对该字段返回 `true`。例如证书域名这类只用于导出的辅助列。 +- 嵌套字段可以使用 `lastVars.certDomains` 这类 key;导出格式化时用安全取值函数读取嵌套值。 +- `dataFormatter` 中统一格式化特殊字段:时间字段转 `YYYY-MM-DD HH:mm:ss`,日期类有效期转业务文案或 `YYYY-MM-DD`,枚举/开关转字典 label,数组转逗号分隔字符串,对象转明确的业务摘要。 + +```typescript +import { ColumnProps, DataFormatterContext } from "@fast-crud/fast-crud"; +import dayjs from "dayjs"; + +function getRecordValue(row: any, key: string) { + return key.split(".").reduce((target, item) => target?.[item], row); +} + +function formatListValue(value: any) { + if (Array.isArray(value)) { + return value.join(","); + } + return value ?? ""; +} + +function exportColumnFilter(col: ColumnProps) { + if (!col.key || ["_index", "_selection", "rowHandle"].includes(col.key)) { + return false; + } + if (col.key === "lastVars.certDomains") { + return true; + } + return col.show !== false; +} + +function exportDataFormatter(opts: DataFormatterContext) { + const { row, originalRow, col, exportCol } = opts; + const key = col.key; + const value = getRecordValue(originalRow, key); + + if (key === "lastVars.certDomains") { + row[key] = formatListValue(value); + } else if (key.includes("Time") && value) { + row[key] = dayjs(value).format("YYYY-MM-DD HH:mm:ss"); + } + + if (col.width) { + exportCol.width = col.width / 10; + } +} + +return { + crudOptions: { + toolbar: { + buttons: { + export: { show: true }, + }, + export: { + dataFrom: "search", + columnFilter: exportColumnFilter, + dataFormatter: exportDataFormatter, + }, + }, + columns: { + "lastVars.certDomains": { + title: "证书域名", + type: "text", + column: { + show: false, + width: 260, + ellipsis: true, + }, + form: { show: false }, + }, + }, + }, +}; +``` + ## 内置 CRUD 按钮 只要在 `request` 中配置了 `addRequest`、`editRequest`、`delRequest`,Fast Crud 会自动在 `rowHandle` 渲染新增、编辑、删除按钮并完成对应操作,**不需要手写 `openDeleteConfirm`、`openEditDialog` 等方法**。 diff --git a/packages/ui/certd-client/src/locales/langs/en-US/certd/common.ts b/packages/ui/certd-client/src/locales/langs/en-US/certd/common.ts index 39c78dac4..8b5aa3fdd 100644 --- a/packages/ui/certd-client/src/locales/langs/en-US/certd/common.ts +++ b/packages/ui/certd-client/src/locales/langs/en-US/certd/common.ts @@ -82,6 +82,7 @@ export default { pipelineContent: "Pipeline Content", scheduledTaskCount: "Scheduled Task Count", deployTaskCount: "Deployment Task Count", + certDomains: "Certificate Domains", remainingValidity: "Remaining Validity", effectiveTime: "Effective time", expiryTime: "Expiry Time", diff --git a/packages/ui/certd-client/src/locales/langs/en-US/certd/pipeline.ts b/packages/ui/certd-client/src/locales/langs/en-US/certd/pipeline.ts index 90d30c820..df7b9aa88 100644 --- a/packages/ui/certd-client/src/locales/langs/en-US/certd/pipeline.ts +++ b/packages/ui/certd-client/src/locales/langs/en-US/certd/pipeline.ts @@ -41,6 +41,7 @@ export default { pi: { validTime: "Piepline Valid Time", validTimeHelper: "Not filled in means permanent validity", + permanentValid: "Permanent", }, types: { certApply: "Cert Apply", diff --git a/packages/ui/certd-client/src/locales/langs/zh-CN/certd/common.ts b/packages/ui/certd-client/src/locales/langs/zh-CN/certd/common.ts index c68b5d3fb..0569139c1 100644 --- a/packages/ui/certd-client/src/locales/langs/zh-CN/certd/common.ts +++ b/packages/ui/certd-client/src/locales/langs/zh-CN/certd/common.ts @@ -86,6 +86,7 @@ export default { pipelineContent: "流水线内容", scheduledTaskCount: "定时任务数", deployTaskCount: "部署任务数", + certDomains: "证书域名", remainingValidity: "到期剩余", effectiveTime: "生效时间", expiryTime: "过期时间", diff --git a/packages/ui/certd-client/src/locales/langs/zh-CN/certd/pipeline.ts b/packages/ui/certd-client/src/locales/langs/zh-CN/certd/pipeline.ts index cb27a9976..d70654a86 100644 --- a/packages/ui/certd-client/src/locales/langs/zh-CN/certd/pipeline.ts +++ b/packages/ui/certd-client/src/locales/langs/zh-CN/certd/pipeline.ts @@ -41,6 +41,7 @@ export default { pi: { validTime: "流水线有效期", validTimeHelper: "不填则为永久有效", + permanentValid: "永久有效", }, types: { certApply: "证书申请", diff --git a/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx b/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx index 70fb8dc5a..6377a13d0 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx @@ -1,4 +1,4 @@ -import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes, useUi } from "@fast-crud/fast-crud"; +import { AddReq, ColumnProps, CreateCrudOptionsProps, CreateCrudOptionsRet, DataFormatterContext, DelReq, dict, EditReq, UserPageQuery, UserPageRes, useUi } from "@fast-crud/fast-crud"; import { Modal, notification } from "ant-design-vue"; import dayjs from "dayjs"; import { computed, ref } from "vue"; @@ -75,6 +75,17 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply const projectStore = useProjectStore(); const { myProjectDict } = useDicts(); const DEFAULT_WILL_EXPIRE_DAYS = settingStore.sysPublic.defaultWillExpireDays || settingStore.sysPublic.defaultCertRenewDays || 15; + const pipelineTypeDictData = [ + { value: "cert", label: t("certd.types.certApply") }, + { value: "cert_upload", label: t("certd.types.certUpload") }, + { value: "custom", label: t("certd.types.custom") }, + { value: "template", label: t("certd.types.template") }, + { value: "cert_auto", label: t("certd.types.certApply") }, + ]; + const disabledDictData = [ + { value: false, label: t("certd.fields.enabledLabel") }, + { value: true, label: t("certd.fields.disabledLabel") }, + ]; function onDialogOpen(opt: any) { const searchForm = crudExpose.getSearchValidatedFormData(); @@ -84,6 +95,79 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply }; } + function getRecordValue(row: any, key: string) { + return key.split(".").reduce((target, item) => target?.[item], row); + } + + function findDictLabel(data: any[], value: any) { + return data.find(item => item.value === value)?.label ?? value; + } + + function formatValidTime(value: any) { + if (!value || value <= 0) { + return t("certd.pi.permanentValid"); + } + if (value < Date.now()) { + return t("certd.hasExpired"); + } + return dayjs(value).format("YYYY-MM-DD"); + } + + function formatRemainingValidity(lastVars: any) { + const expiresTime = lastVars?.certExpiresTime; + if (!expiresTime) { + return "-"; + } + const leftDays = dayjs(expiresTime).diff(dayjs(), "day"); + if (leftDays < 0) { + return t("certd.hasExpired"); + } + return `${leftDays}${t("certd.days")}`; + } + + function formatListValue(value: any) { + if (Array.isArray(value)) { + return value.join(","); + } + return value ?? ""; + } + + function exportColumnFilter(col: ColumnProps) { + if (!col.key || ["_index", "_selection", "rowHandle"].includes(col.key)) { + return false; + } + if (col.key === "lastVars.certDomains") { + return true; + } + return col.show !== false; + } + + function exportDataFormatter(opts: DataFormatterContext) { + const { row, originalRow, col, exportCol } = opts; + const key = col.key; + const value = getRecordValue(originalRow, key); + + if (key === "validTime") { + row[key] = formatValidTime(value); + } else if (key === "lastVars") { + row[key] = formatRemainingValidity(value); + } else if (key === "lastVars.certDomains") { + row[key] = formatListValue(value); + } else if (key === "status") { + row[key] = statusUtil.get(value)?.label ?? value; + } else if (key === "disabled") { + row[key] = findDictLabel(disabledDictData, value); + } else if (key === "type") { + row[key] = findDictLabel(pipelineTypeDictData, value); + } else if (key.includes("Time") && value) { + row[key] = dayjs(value).format("YYYY-MM-DD HH:mm:ss"); + } + + if (col.width) { + exportCol.width = col.width / 10; + } + } + return { crudOptions: { request: { @@ -178,6 +262,18 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply confirmMessage: t("certd.table.confirmDeleteMessage"), }, }, + toolbar: { + buttons: { + export: { + show: true, + }, + }, + export: { + dataFrom: "search", + columnFilter: exportColumnFilter, + dataFormatter: exportDataFormatter, + }, + }, tabs: { name: "groupId", show: true, @@ -419,6 +515,19 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply width: 150, }, }, + "lastVars.certDomains": { + title: t("certd.fields.certDomains"), + type: "text", + form: { + show: false, + }, + column: { + width: 260, + show: false, + ellipsis: true, + showTitle: true, + }, + }, "lastVars.certEffectiveTime": { title: t("certd.fields.effectiveTime"), search: { @@ -503,10 +612,7 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply }, }, dict: dict({ - data: [ - { value: false, label: t("certd.fields.enabledLabel") }, - { value: true, label: t("certd.fields.disabledLabel") }, - ], + data: disabledDictData, }), form: { value: false, @@ -563,13 +669,7 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply col: { span: 2 }, }, dict: dict({ - data: [ - { value: "cert", label: t("certd.types.certApply") }, - { value: "cert_upload", label: t("certd.types.certUpload") }, - { value: "custom", label: t("certd.types.custom") }, - { value: "template", label: t("certd.types.template") }, - { value: "cert_auto", label: t("certd.types.certApply") }, - ], + data: pipelineTypeDictData, }), form: { show: false, @@ -650,7 +750,7 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply align: "center", cellRender({ value }) { if (!value || value <= 0) { - return "-"; + return t("certd.pi.permanentValid"); } if (value < Date.now()) { return t("certd.hasExpired"); diff --git a/packages/ui/certd-client/src/views/sys/pipeline/crud.tsx b/packages/ui/certd-client/src/views/sys/pipeline/crud.tsx index 956f2bdc5..dba04a87e 100644 --- a/packages/ui/certd-client/src/views/sys/pipeline/crud.tsx +++ b/packages/ui/certd-client/src/views/sys/pipeline/crud.tsx @@ -1,5 +1,5 @@ import createCrudOptionsUser from "/@/views/sys/authority/user/crud"; -import { CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; +import { ColumnProps, CreateCrudOptionsProps, CreateCrudOptionsRet, DataFormatterContext, DelReq, dict, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; import { message, Modal } from "ant-design-vue"; import dayjs from "dayjs"; import { ref } from "vue"; @@ -18,6 +18,77 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }; const selectedRowKeys = ref([]); + const pipelineTypeDictData = [ + { value: "cert", label: "证书申请" }, + { value: "cert_upload", label: "证书上传" }, + { value: "custom", label: "自定义" }, + { value: "template", label: "模板" }, + { value: "cert_auto", label: "证书申请" }, + ]; + const disabledDictData = [ + { label: "启用", value: false, color: "green" }, + { label: "禁用", value: true, color: "red" }, + ]; + + function findDictLabel(data: any[], value: any) { + return data.find(item => item.value === value)?.label ?? value; + } + + function formatValidTime(value: any) { + if (!value || value <= 0) { + return "永久有效"; + } + if (value < Date.now()) { + return "已过期"; + } + return dayjs(value).format("YYYY-MM-DD"); + } + + function getRecordValue(row: any, key: string) { + return key.split(".").reduce((target, item) => target?.[item], row); + } + + function formatListValue(value: any) { + if (Array.isArray(value)) { + return value.join(","); + } + return value ?? ""; + } + + function exportColumnFilter(col: ColumnProps) { + if (!col.key || ["_index", "_selection", "rowHandle"].includes(col.key)) { + return false; + } + if (col.key === "lastVars.certDomains") { + return true; + } + return col.show !== false; + } + + function exportDataFormatter(opts: DataFormatterContext) { + const { row, originalRow, col, exportCol } = opts; + const key = col.key; + const value = getRecordValue(originalRow, key); + + if (key === "validTime") { + row[key] = formatValidTime(value); + } else if (key === "lastVars.certDomains") { + row[key] = formatListValue(value); + } else if (key === "status") { + row[key] = statusUtil.get(value)?.label ?? value; + } else if (key === "disabled") { + row[key] = findDictLabel(disabledDictData, value); + } else if (key === "type") { + row[key] = findDictLabel(pipelineTypeDictData, value); + } else if (key.includes("Time") && value) { + row[key] = dayjs(value).format("YYYY-MM-DD HH:mm:ss"); + } + + if (col.width) { + exportCol.width = col.width / 10; + } + } + const handleBatchDelete = () => { if (!selectedRowKeys.value?.length) { message.error("请先选择要删除的记录"); @@ -54,6 +125,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }, export: { dataFrom: "search", + columnFilter: exportColumnFilter, + dataFormatter: exportDataFormatter, }, }, pagination: { @@ -185,13 +258,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }, }, dict: dict({ - data: [ - { value: "cert", label: "证书申请" }, - { value: "cert_upload", label: "证书上传" }, - { value: "custom", label: "自定义" }, - { value: "template", label: "模板" }, - { value: "cert_auto", label: "证书申请" }, - ], + data: pipelineTypeDictData, }), column: { width: 110, @@ -236,10 +303,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }, }, dict: dict({ - data: [ - { label: "启用", value: false, color: "green" }, - { label: "禁用", value: true, color: "red" }, - ], + data: disabledDictData, }), column: { width: 90, @@ -273,6 +337,18 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat show: false, }, }, + "lastVars.certDomains": { + title: "证书域名", + type: "text", + column: { + width: 260, + show: false, + ellipsis: true, + }, + form: { + show: false, + }, + }, lastHistoryTime: { title: "最后执行时间", type: "datetime", @@ -306,7 +382,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat align: "center", cellRender({ value }) { if (!value || value <= 0) { - return "-"; + return "永久有效"; } if (value < Date.now()) { return 已过期; diff --git a/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/base-convert.ts b/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/base-convert.ts index d2335c44c..a1990434a 100644 --- a/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/base-convert.ts +++ b/packages/ui/certd-server/src/plugins/plugin-cert/plugin/cert-plugin/base-convert.ts @@ -102,6 +102,7 @@ export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin { this._result.pipelineVars.certEffectiveTime = dayjs(certReader.detail.notBefore).valueOf(); this._result.pipelineVars.certExpiresTime = dayjs(certReader.detail.notAfter).valueOf(); + this._result.pipelineVars.certDomains = certReader.getAllDomains(); if (!this._result.pipelinePrivateVars) { this._result.pipelinePrivateVars = {}; } From 5546af518e92c765513787ccaf8e856be789bcf9 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 5 Jun 2026 00:23:08 +0800 Subject: [PATCH 03/19] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E9=A1=B5=E9=9D=A2=E8=AF=B7=E6=B1=82=E4=B8=A4=E6=AC=A1?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .trae/skills/fast-crud-page-dev/SKILL.md | 2 +- .../ui/certd-client/src/router/source/modules/certd.ts | 3 +++ packages/ui/certd-client/src/router/source/modules/sys.ts | 4 ++-- packages/ui/certd-client/src/views/certd/access/index.vue | 2 +- packages/ui/certd-client/src/views/certd/addon/index.vue | 2 +- .../ui/certd-client/src/views/certd/basic/group/index.vue | 2 +- .../src/views/certd/cert/apply-template/index.vue | 2 +- .../src/views/certd/cert/dns-persist/index.vue | 2 +- .../ui/certd-client/src/views/certd/cert/domain/index.vue | 2 +- .../certd-client/src/views/certd/cname/record/index.vue | 2 +- .../ui/certd-client/src/views/certd/history/index.vue | 2 +- .../certd-client/src/views/certd/monitor/cert/index.vue | 2 +- .../src/views/certd/monitor/history/index.vue | 2 +- .../certd-client/src/views/certd/monitor/site/index.vue | 2 +- .../src/views/certd/monitor/site/ip/index.vue | 2 +- .../certd-client/src/views/certd/notification/index.vue | 2 +- .../certd-client/src/views/certd/open/openkey/index.vue | 2 +- .../certd-client/src/views/certd/pipeline/group/index.vue | 2 +- .../ui/certd-client/src/views/certd/pipeline/index.vue | 2 +- .../src/views/certd/pipeline/sub-domain/index.vue | 4 ++-- .../src/views/certd/pipeline/template/index.vue | 2 +- .../certd-client/src/views/certd/project/detail/index.vue | 2 +- .../ui/certd-client/src/views/certd/project/index.vue | 2 +- .../ui/certd-client/src/views/certd/suite/mine/index.vue | 6 +++--- packages/ui/certd-client/src/views/certd/trade/index.vue | 2 +- packages/ui/certd-client/src/views/sys/access/index.vue | 2 +- .../src/views/sys/authority/permission/index.vue | 4 ++-- .../certd-client/src/views/sys/authority/role/index.vue | 2 +- .../certd-client/src/views/sys/authority/user/index.vue | 2 +- .../certd-client/src/views/sys/cname/provider/index.vue | 4 ++-- .../certd-client/src/views/sys/enterprise/audit/index.vue | 2 +- .../src/views/sys/enterprise/project/detail/index.vue | 2 +- .../src/views/sys/enterprise/project/index.vue | 2 +- .../ui/certd-client/src/views/sys/monitor/site/index.vue | 2 +- packages/ui/certd-client/src/views/sys/pipeline/index.vue | 2 +- .../src/views/sys/settings/header-menus/index.vue | 2 +- packages/ui/certd-client/src/views/sys/site/index.vue | 8 ++++++++ .../src/views/sys/suite/activation-code/index.vue | 4 ++-- .../ui/certd-client/src/views/sys/suite/invite/level.vue | 2 +- .../src/views/sys/suite/invite/user-level.vue | 2 +- .../certd-client/src/views/sys/suite/invite/withdraw.vue | 2 +- .../ui/certd-client/src/views/sys/suite/trade/index.vue | 8 ++++---- .../certd-client/src/views/sys/suite/user-suite/index.vue | 2 +- 43 files changed, 62 insertions(+), 51 deletions(-) diff --git a/.trae/skills/fast-crud-page-dev/SKILL.md b/.trae/skills/fast-crud-page-dev/SKILL.md index 81c96e0f9..43b2d950b 100644 --- a/.trae/skills/fast-crud-page-dev/SKILL.md +++ b/.trae/skills/fast-crud-page-dev/SKILL.md @@ -25,7 +25,7 @@ version: 1.0.0 ## 实现流程 1. 先在 `packages/ui/certd-client/src/views` 下找 1-2 个相近 Fast Crud 页面,沿用它们的导入、布局、命名和权限写法。 -2. 在 `index.vue` 中使用 `fs-crud ref="crudRef" v-bind="crudBinding"`,并在 `onMounted` / `onActivated` 时调用 `crudExpose.doRefresh()`。 +2. 在 `index.vue` 中使用 `fs-crud ref="crudRef" v-bind="crudBinding"`,并在 `onMounted` 或 `onActivated` 时调用 `crudExpose.doRefresh()`;两个生命周期同时存在时只保留一个刷新入口,避免首次进入页面请求两次。 3. 在 `crud.tsx` 中配置 `request.pageRequest`、`columns`、`search`、`form`、`rowHandle`、`actionbar`、`toolbar` 等,接口分页参数和返回值按现有页面适配。 4. 操作按钮优先放在 Fast Crud 的 `rowHandle.buttons` 或 `actionbar.buttons` 中;审核、保存设置、批量操作等复杂交互可通过 `context` 调用 `index.vue` 中的方法。 5. 金额、状态、时间、枚举等字段优先复用项目已有组件、字典和格式化工具;避免在模板里重复堆格式化逻辑。 diff --git a/packages/ui/certd-client/src/router/source/modules/certd.ts b/packages/ui/certd-client/src/router/source/modules/certd.ts index 9fe104818..973bbe4cf 100644 --- a/packages/ui/certd-client/src/router/source/modules/certd.ts +++ b/packages/ui/certd-client/src/router/source/modules/certd.ts @@ -82,6 +82,7 @@ export const certdResources = [ isMenu: true, icon: "ion:duplicate-outline", auth: true, + keepAlive: true, }, }, { @@ -282,6 +283,7 @@ export const certdResources = [ meta: { icon: "ion:barcode-outline", auth: true, + keepAlive: true, isMenu: true, }, }, @@ -350,6 +352,7 @@ export const certdResources = [ }, icon: "ion:gift-outline", auth: true, + keepAlive: true, }, }, { diff --git a/packages/ui/certd-client/src/router/source/modules/sys.ts b/packages/ui/certd-client/src/router/source/modules/sys.ts index 766135d24..06c756892 100644 --- a/packages/ui/certd-client/src/router/source/modules/sys.ts +++ b/packages/ui/certd-client/src/router/source/modules/sys.ts @@ -112,7 +112,7 @@ export const sysResources = [ }, { title: "certd.sysResources.headerMenus", - name: "HeaderMenus", + name: "SettingsHeaderMenus", path: "/sys/settings/header-menus", component: "/sys/settings/header-menus/index.vue", meta: { @@ -128,7 +128,7 @@ export const sysResources = [ }, { title: "certd.sysResources.sysAccess", - name: "SysAccess", + name: "SysAccessManager", path: "/sys/access", component: "/sys/access/index.vue", meta: { diff --git a/packages/ui/certd-client/src/views/certd/access/index.vue b/packages/ui/certd-client/src/views/certd/access/index.vue index 2079c4040..16cf15356 100644 --- a/packages/ui/certd-client/src/views/certd/access/index.vue +++ b/packages/ui/certd-client/src/views/certd/access/index.vue @@ -26,7 +26,7 @@ export default defineComponent({ // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/addon/index.vue b/packages/ui/certd-client/src/views/certd/addon/index.vue index 6ab6cd736..25f9997e2 100644 --- a/packages/ui/certd-client/src/views/certd/addon/index.vue +++ b/packages/ui/certd-client/src/views/certd/addon/index.vue @@ -29,7 +29,7 @@ export default defineComponent({ // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/basic/group/index.vue b/packages/ui/certd-client/src/views/certd/basic/group/index.vue index 8dd866783..7d3282634 100644 --- a/packages/ui/certd-client/src/views/certd/basic/group/index.vue +++ b/packages/ui/certd-client/src/views/certd/basic/group/index.vue @@ -27,7 +27,7 @@ export default defineComponent({ // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/cert/apply-template/index.vue b/packages/ui/certd-client/src/views/certd/cert/apply-template/index.vue index 61031a83c..f58053998 100644 --- a/packages/ui/certd-client/src/views/certd/cert/apply-template/index.vue +++ b/packages/ui/certd-client/src/views/certd/cert/apply-template/index.vue @@ -27,7 +27,7 @@ const { crudBinding, crudRef, crudExpose } = useFs({ }); onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { diff --git a/packages/ui/certd-client/src/views/certd/cert/dns-persist/index.vue b/packages/ui/certd-client/src/views/certd/cert/dns-persist/index.vue index a877357cb..01dd95ba2 100644 --- a/packages/ui/certd-client/src/views/certd/cert/dns-persist/index.vue +++ b/packages/ui/certd-client/src/views/certd/cert/dns-persist/index.vue @@ -25,7 +25,7 @@ const context: any = { const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context }); onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/cert/domain/index.vue b/packages/ui/certd-client/src/views/certd/cert/domain/index.vue index 0a366f8e7..1b40f43e4 100644 --- a/packages/ui/certd-client/src/views/certd/cert/domain/index.vue +++ b/packages/ui/certd-client/src/views/certd/cert/domain/index.vue @@ -62,7 +62,7 @@ const handleBatchDelete = () => { // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/cname/record/index.vue b/packages/ui/certd-client/src/views/certd/cname/record/index.vue index 5f4f49522..77d35ff24 100644 --- a/packages/ui/certd-client/src/views/certd/cname/record/index.vue +++ b/packages/ui/certd-client/src/views/certd/cname/record/index.vue @@ -62,7 +62,7 @@ const handleBatchDelete = () => { // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/history/index.vue b/packages/ui/certd-client/src/views/certd/history/index.vue index 74e298830..e21262064 100644 --- a/packages/ui/certd-client/src/views/certd/history/index.vue +++ b/packages/ui/certd-client/src/views/certd/history/index.vue @@ -55,7 +55,7 @@ const handleBatchDelete = () => { // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/monitor/cert/index.vue b/packages/ui/certd-client/src/views/certd/monitor/cert/index.vue index 6c04a8314..3f7a76463 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/cert/index.vue +++ b/packages/ui/certd-client/src/views/certd/monitor/cert/index.vue @@ -25,7 +25,7 @@ const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/monitor/history/index.vue b/packages/ui/certd-client/src/views/certd/monitor/history/index.vue index b7e8f2b9f..eb8db7058 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/history/index.vue +++ b/packages/ui/certd-client/src/views/certd/monitor/history/index.vue @@ -40,7 +40,7 @@ const handleBatchDelete = context.handleBatchDelete; // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/index.vue b/packages/ui/certd-client/src/views/certd/monitor/site/index.vue index 5acc1db55..53672d2c6 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/site/index.vue +++ b/packages/ui/certd-client/src/views/certd/monitor/site/index.vue @@ -45,7 +45,7 @@ const handleBatchDelete = context.handleBatchDelete; // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); 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 c3434a669..e61813ece 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 @@ -24,7 +24,7 @@ const { crudBinding, crudRef, crudExpose } = useFs({ // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/notification/index.vue b/packages/ui/certd-client/src/views/certd/notification/index.vue index 614e08c27..cdf741462 100644 --- a/packages/ui/certd-client/src/views/certd/notification/index.vue +++ b/packages/ui/certd-client/src/views/certd/notification/index.vue @@ -26,7 +26,7 @@ export default defineComponent({ // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/open/openkey/index.vue b/packages/ui/certd-client/src/views/certd/open/openkey/index.vue index 1c4a425ac..4fd6da621 100644 --- a/packages/ui/certd-client/src/views/certd/open/openkey/index.vue +++ b/packages/ui/certd-client/src/views/certd/open/openkey/index.vue @@ -23,7 +23,7 @@ const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/pipeline/group/index.vue b/packages/ui/certd-client/src/views/certd/pipeline/group/index.vue index d83be9422..8d9a9bc97 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/group/index.vue +++ b/packages/ui/certd-client/src/views/certd/pipeline/group/index.vue @@ -27,7 +27,7 @@ export default defineComponent({ // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/pipeline/index.vue b/packages/ui/certd-client/src/views/certd/pipeline/index.vue index c86388cf2..db13ba6e6 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/index.vue +++ b/packages/ui/certd-client/src/views/certd/pipeline/index.vue @@ -129,7 +129,7 @@ const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { diff --git a/packages/ui/certd-client/src/views/certd/pipeline/sub-domain/index.vue b/packages/ui/certd-client/src/views/certd/pipeline/sub-domain/index.vue index 27135d4d8..ffa017c99 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/sub-domain/index.vue +++ b/packages/ui/certd-client/src/views/certd/pipeline/sub-domain/index.vue @@ -37,7 +37,7 @@ import { useCrudPermission } from "/@/plugin/permission"; const { t } = useI18n(); defineOptions({ - name: "CnameRecord", + name: "SubDomain", }); const context: any = { permission: { @@ -68,7 +68,7 @@ const handleBatchDelete = () => { // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/pipeline/template/index.vue b/packages/ui/certd-client/src/views/certd/pipeline/template/index.vue index 2c3e3edbc..c10048fc5 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/template/index.vue +++ b/packages/ui/certd-client/src/views/certd/pipeline/template/index.vue @@ -30,7 +30,7 @@ const { crudBinding, crudRef, crudExpose } = useFs({ const { t } = useI18n(); // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/project/detail/index.vue b/packages/ui/certd-client/src/views/certd/project/detail/index.vue index c2bb178cc..0d3221f23 100644 --- a/packages/ui/certd-client/src/views/certd/project/detail/index.vue +++ b/packages/ui/certd-client/src/views/certd/project/detail/index.vue @@ -117,7 +117,7 @@ onMounted(async () => { return; } await loadProjectDetail(); - await crudExpose.doRefresh(); + // await crudExpose.doRefresh(); if (migrate === "true") { openTransferDialog(); diff --git a/packages/ui/certd-client/src/views/certd/project/index.vue b/packages/ui/certd-client/src/views/certd/project/index.vue index 3830104e7..16e164289 100644 --- a/packages/ui/certd-client/src/views/certd/project/index.vue +++ b/packages/ui/certd-client/src/views/certd/project/index.vue @@ -53,7 +53,7 @@ const handleBatchDelete = () => { // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/certd/suite/mine/index.vue b/packages/ui/certd-client/src/views/certd/suite/mine/index.vue index 8b11383c4..f62295758 100644 --- a/packages/ui/certd-client/src/views/certd/suite/mine/index.vue +++ b/packages/ui/certd-client/src/views/certd/suite/mine/index.vue @@ -40,10 +40,10 @@ async function loadSuiteDetail() { // 页面打开后获取列表数据 onMounted(async () => { + // await crudExpose.doRefresh(); +}); +onActivated(async () => { await loadSuiteDetail(); await crudExpose.doRefresh(); }); -onActivated(() => { - crudExpose.doRefresh(); -}); diff --git a/packages/ui/certd-client/src/views/certd/trade/index.vue b/packages/ui/certd-client/src/views/certd/trade/index.vue index a0a2fd8da..631468cf3 100644 --- a/packages/ui/certd-client/src/views/certd/trade/index.vue +++ b/packages/ui/certd-client/src/views/certd/trade/index.vue @@ -19,7 +19,7 @@ const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions }); // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/access/index.vue b/packages/ui/certd-client/src/views/sys/access/index.vue index 919916f70..70f25bf01 100644 --- a/packages/ui/certd-client/src/views/sys/access/index.vue +++ b/packages/ui/certd-client/src/views/sys/access/index.vue @@ -24,7 +24,7 @@ export default defineComponent({ // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { diff --git a/packages/ui/certd-client/src/views/sys/authority/permission/index.vue b/packages/ui/certd-client/src/views/sys/authority/permission/index.vue index a42e6be72..92f4ee7a4 100644 --- a/packages/ui/certd-client/src/views/sys/authority/permission/index.vue +++ b/packages/ui/certd-client/src/views/sys/authority/permission/index.vue @@ -22,7 +22,7 @@ import { useFs, useUi } from "@fast-crud/fast-crud"; import { useI18n } from "/src/locales"; export default defineComponent({ - name: "AuthorityManager", + name: "PermissionManager", components: { FsPermissionTree }, setup() { // 此处传入permission进行通用按钮权限设置,会通过commonOptions去设置actionbar和rowHandle的按钮的show属性 @@ -32,7 +32,7 @@ export default defineComponent({ // 页面打开后获取列表数据 onMounted(async () => { - await crudExpose.doRefresh(); + // await crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/authority/role/index.vue b/packages/ui/certd-client/src/views/sys/authority/role/index.vue index 56d8880f1..69382d711 100644 --- a/packages/ui/certd-client/src/views/sys/authority/role/index.vue +++ b/packages/ui/certd-client/src/views/sys/authority/role/index.vue @@ -107,7 +107,7 @@ export default defineComponent({ // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { diff --git a/packages/ui/certd-client/src/views/sys/authority/user/index.vue b/packages/ui/certd-client/src/views/sys/authority/user/index.vue index ef87f2b4d..2a2770453 100644 --- a/packages/ui/certd-client/src/views/sys/authority/user/index.vue +++ b/packages/ui/certd-client/src/views/sys/authority/user/index.vue @@ -21,7 +21,7 @@ export default defineComponent({ // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/cname/provider/index.vue b/packages/ui/certd-client/src/views/sys/cname/provider/index.vue index e1f2427df..a0807a9a5 100644 --- a/packages/ui/certd-client/src/views/sys/cname/provider/index.vue +++ b/packages/ui/certd-client/src/views/sys/cname/provider/index.vue @@ -32,7 +32,7 @@ import { useI18n } from "/src/locales"; const { t } = useI18n(); defineOptions({ - name: "CnameProvider", + name: "CnameSetting", }); const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions }); @@ -56,7 +56,7 @@ const handleBatchDelete = () => { // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/enterprise/audit/index.vue b/packages/ui/certd-client/src/views/sys/enterprise/audit/index.vue index e1f2427df..f508d032c 100644 --- a/packages/ui/certd-client/src/views/sys/enterprise/audit/index.vue +++ b/packages/ui/certd-client/src/views/sys/enterprise/audit/index.vue @@ -56,7 +56,7 @@ const handleBatchDelete = () => { // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/enterprise/project/detail/index.vue b/packages/ui/certd-client/src/views/sys/enterprise/project/detail/index.vue index 84f8e6d3e..b28a31709 100644 --- a/packages/ui/certd-client/src/views/sys/enterprise/project/detail/index.vue +++ b/packages/ui/certd-client/src/views/sys/enterprise/project/detail/index.vue @@ -62,7 +62,7 @@ const handleBatchDelete = () => { // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/enterprise/project/index.vue b/packages/ui/certd-client/src/views/sys/enterprise/project/index.vue index b953b8b71..78f1b6b5d 100644 --- a/packages/ui/certd-client/src/views/sys/enterprise/project/index.vue +++ b/packages/ui/certd-client/src/views/sys/enterprise/project/index.vue @@ -53,7 +53,7 @@ const handleBatchDelete = () => { // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/monitor/site/index.vue b/packages/ui/certd-client/src/views/sys/monitor/site/index.vue index 55fa612e9..353f72550 100644 --- a/packages/ui/certd-client/src/views/sys/monitor/site/index.vue +++ b/packages/ui/certd-client/src/views/sys/monitor/site/index.vue @@ -27,7 +27,7 @@ const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context const handleBatchDelete = context.handleBatchDelete; onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/pipeline/index.vue b/packages/ui/certd-client/src/views/sys/pipeline/index.vue index 58bdb647b..6b8cfeee9 100644 --- a/packages/ui/certd-client/src/views/sys/pipeline/index.vue +++ b/packages/ui/certd-client/src/views/sys/pipeline/index.vue @@ -27,7 +27,7 @@ const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context const handleBatchDelete = context.handleBatchDelete; onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/settings/header-menus/index.vue b/packages/ui/certd-client/src/views/sys/settings/header-menus/index.vue index 399b6e759..e87304a6a 100644 --- a/packages/ui/certd-client/src/views/sys/settings/header-menus/index.vue +++ b/packages/ui/certd-client/src/views/sys/settings/header-menus/index.vue @@ -21,7 +21,7 @@ const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions const settingStore = useSettingStore(); // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/site/index.vue b/packages/ui/certd-client/src/views/sys/site/index.vue index 62719a267..7fdb8b4f8 100644 --- a/packages/ui/certd-client/src/views/sys/site/index.vue +++ b/packages/ui/certd-client/src/views/sys/site/index.vue @@ -123,4 +123,12 @@ const loginLogoCropperOptions = ref({ border-radius: 0 !important; margin-top: 0 !important; } + +.page-sys-site { + .sys-settings-form { + width: 900px; + max-width: 100%; + padding: 20px; + } +} diff --git a/packages/ui/certd-client/src/views/sys/suite/activation-code/index.vue b/packages/ui/certd-client/src/views/sys/suite/activation-code/index.vue index 359112f35..a5af3d79d 100644 --- a/packages/ui/certd-client/src/views/sys/suite/activation-code/index.vue +++ b/packages/ui/certd-client/src/views/sys/suite/activation-code/index.vue @@ -16,13 +16,13 @@ import { useFs } from "@fast-crud/fast-crud"; import createCrudOptions from "./crud"; defineOptions({ - name: "ProductActivationCodeManager", + name: "SysProductActivationCode", }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions }); onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(async () => { await crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/suite/invite/level.vue b/packages/ui/certd-client/src/views/sys/suite/invite/level.vue index ae4f2cbea..a8cefe29b 100644 --- a/packages/ui/certd-client/src/views/sys/suite/invite/level.vue +++ b/packages/ui/certd-client/src/views/sys/suite/invite/level.vue @@ -94,7 +94,7 @@ function confirmRemove(opts: any) { } onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/suite/invite/user-level.vue b/packages/ui/certd-client/src/views/sys/suite/invite/user-level.vue index 6a35e5a3c..7cd77629a 100644 --- a/packages/ui/certd-client/src/views/sys/suite/invite/user-level.vue +++ b/packages/ui/certd-client/src/views/sys/suite/invite/user-level.vue @@ -17,7 +17,7 @@ defineOptions({ name: "SysInviteUserLevel" }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions }); onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/suite/invite/withdraw.vue b/packages/ui/certd-client/src/views/sys/suite/invite/withdraw.vue index 0fe14e43b..bdd87253d 100644 --- a/packages/ui/certd-client/src/views/sys/suite/invite/withdraw.vue +++ b/packages/ui/certd-client/src/views/sys/suite/invite/withdraw.vue @@ -17,7 +17,7 @@ defineOptions({ name: "SysInviteWithdraw" }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions }); onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); diff --git a/packages/ui/certd-client/src/views/sys/suite/trade/index.vue b/packages/ui/certd-client/src/views/sys/suite/trade/index.vue index b2b87c41b..aa0975e6f 100644 --- a/packages/ui/certd-client/src/views/sys/suite/trade/index.vue +++ b/packages/ui/certd-client/src/views/sys/suite/trade/index.vue @@ -16,16 +16,16 @@ import { useFs } from "@fast-crud/fast-crud"; import createCrudOptions from "./crud"; defineOptions({ - name: "TradeManager", + name: "OrderManager", }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions }); // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); -onActivated(async () => { - await crudExpose.doRefresh(); +onActivated(() => { + crudExpose.doRefresh(); }); diff --git a/packages/ui/certd-client/src/views/sys/suite/user-suite/index.vue b/packages/ui/certd-client/src/views/sys/suite/user-suite/index.vue index 341b8e459..f00230e42 100644 --- a/packages/ui/certd-client/src/views/sys/suite/user-suite/index.vue +++ b/packages/ui/certd-client/src/views/sys/suite/user-suite/index.vue @@ -22,7 +22,7 @@ const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: // 页面打开后获取列表数据 onMounted(() => { - crudExpose.doRefresh(); + // crudExpose.doRefresh(); }); onActivated(() => { crudExpose.doRefresh(); From 1175e1164b34084b198a5b69d4df80040156546e Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Jun 2026 00:50:59 +0800 Subject: [PATCH 04/19] =?UTF-8?q?refactor(ui):=20=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E4=BD=BF=E7=94=A8useMounted=E9=92=A9=E5=AD=90=E7=AE=80?= =?UTF-8?q?=E5=8C=96=E9=A1=B5=E9=9D=A2=E5=88=9D=E5=A7=8B=E5=8C=96=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 8 +++++-- .../src/router/source/modules/sys.ts | 2 +- .../ui/certd-client/src/use/use-mounted.ts | 24 +++++++++++++++++++ .../src/views/certd/access/index.vue | 12 +++------- .../src/views/certd/addon/index.vue | 12 +++------- .../src/views/certd/basic/group/index.vue | 12 +++------- .../views/certd/cert/apply-template/index.vue | 11 +++------ .../src/views/certd/history/index.vue | 15 ++++++------ .../src/views/certd/monitor/cert/index.vue | 12 ++++------ .../src/views/certd/monitor/history/index.vue | 12 ++++------ .../src/views/certd/monitor/site/index.vue | 12 ++++------ .../src/views/certd/monitor/site/ip/index.vue | 11 +++------ .../src/views/certd/notification/index.vue | 12 +++------- .../src/views/certd/open/openkey/index.vue | 12 ++++------ .../src/views/certd/pipeline/group/index.vue | 12 +++------- .../views/certd/pipeline/template/index.vue | 11 ++++----- .../src/views/certd/project/detail/index.vue | 4 ++-- .../src/views/certd/suite/mine/index.vue | 11 ++++----- .../src/views/sys/access/index.vue | 13 +++------- .../src/views/sys/authority/role/index.vue | 10 +------- .../src/views/sys/authority/user/index.vue | 9 +------ .../src/views/sys/monitor/site/index.vue | 10 +++----- .../src/views/sys/pipeline/index.vue | 10 +++----- .../src/views/sys/suite/invite/level.vue | 12 ++++------ .../src/views/sys/suite/invite/user-level.vue | 10 +++----- .../src/views/sys/suite/invite/withdraw.vue | 10 +++----- .../src/views/sys/suite/trade/index.vue | 10 ++------ .../src/views/sys/suite/user-suite/index.vue | 11 +++------ .../plugins/plugin-deploy-to-vke.ts | 10 ++++---- 29 files changed, 118 insertions(+), 202 deletions(-) create mode 100644 packages/ui/certd-client/src/use/use-mounted.ts diff --git a/.gitignore b/.gitignore index b9c2e515e..d9e59e533 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -./packages/core/lego +./packages/core/lego # IntelliJ project files node_modules/ npm-debug.log @@ -34,4 +34,8 @@ test.js /logs .pnpm-lock.yaml pnpm-lock.yaml -.studio/ \ No newline at end of file +.studio/ + +# Certd 推广报告,仅本地使用 +/popularize/ + diff --git a/packages/ui/certd-client/src/router/source/modules/sys.ts b/packages/ui/certd-client/src/router/source/modules/sys.ts index 06c756892..c042885ba 100644 --- a/packages/ui/certd-client/src/router/source/modules/sys.ts +++ b/packages/ui/certd-client/src/router/source/modules/sys.ts @@ -311,7 +311,7 @@ export const sysResources = [ }, icon: "ion:bag-check", permission: "sys:settings:edit", - keepAlive: true, + keepAlive: false, auth: true, }, }, diff --git a/packages/ui/certd-client/src/use/use-mounted.ts b/packages/ui/certd-client/src/use/use-mounted.ts new file mode 100644 index 000000000..047181f36 --- /dev/null +++ b/packages/ui/certd-client/src/use/use-mounted.ts @@ -0,0 +1,24 @@ +import { onActivated, onMounted } from "vue"; + +/** + * 可靠的页面刷新钩子: + * - 如果组件实际被 KeepAlive 缓存命中,由 onActivated 触发 init; + * - 如果没有被缓存,由 onMounted 兜底触发,避免不刷新也不触发 onActivated。 + */ +export function useMounted(init: () => void | Promise) { + let activated = false; + + onActivated(() => { + activated = true; + init(); + }); + + onMounted(() => { + // 让 onActivated 有机会先执行;组件未被 KeepAlive 缓存时 onActivated 不会触发,由这里兜底。 + setTimeout(() => { + if (!activated) { + init(); + } + }); + }); +} diff --git a/packages/ui/certd-client/src/views/certd/access/index.vue b/packages/ui/certd-client/src/views/certd/access/index.vue index 16cf15356..c577e8d37 100644 --- a/packages/ui/certd-client/src/views/certd/access/index.vue +++ b/packages/ui/certd-client/src/views/certd/access/index.vue @@ -11,7 +11,8 @@ diff --git a/packages/ui/certd-client/src/views/certd/history/index.vue b/packages/ui/certd-client/src/views/certd/history/index.vue index e21262064..bd56e930f 100644 --- a/packages/ui/certd-client/src/views/certd/history/index.vue +++ b/packages/ui/certd-client/src/views/certd/history/index.vue @@ -14,12 +14,18 @@ diff --git a/packages/ui/certd-client/src/views/certd/monitor/cert/index.vue b/packages/ui/certd-client/src/views/certd/monitor/cert/index.vue index 3f7a76463..2390de5b5 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/cert/index.vue +++ b/packages/ui/certd-client/src/views/certd/monitor/cert/index.vue @@ -11,9 +11,12 @@ diff --git a/packages/ui/certd-client/src/views/certd/monitor/history/index.vue b/packages/ui/certd-client/src/views/certd/monitor/history/index.vue index eb8db7058..43b805d6d 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/history/index.vue +++ b/packages/ui/certd-client/src/views/certd/monitor/history/index.vue @@ -21,9 +21,12 @@ diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/index.vue b/packages/ui/certd-client/src/views/certd/monitor/site/index.vue index 53672d2c6..d39b13db9 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/site/index.vue +++ b/packages/ui/certd-client/src/views/certd/monitor/site/index.vue @@ -26,9 +26,12 @@ 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 e61813ece..62191fb2c 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 @@ -5,7 +5,9 @@ diff --git a/packages/ui/certd-client/src/views/certd/notification/index.vue b/packages/ui/certd-client/src/views/certd/notification/index.vue index cdf741462..befc7efe0 100644 --- a/packages/ui/certd-client/src/views/certd/notification/index.vue +++ b/packages/ui/certd-client/src/views/certd/notification/index.vue @@ -11,7 +11,8 @@ diff --git a/packages/ui/certd-client/src/views/certd/pipeline/group/index.vue b/packages/ui/certd-client/src/views/certd/pipeline/group/index.vue index 8d9a9bc97..5a54f40e3 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/group/index.vue +++ b/packages/ui/certd-client/src/views/certd/pipeline/group/index.vue @@ -11,7 +11,8 @@ diff --git a/packages/ui/certd-client/src/views/certd/project/detail/index.vue b/packages/ui/certd-client/src/views/certd/project/detail/index.vue index 0d3221f23..37b7a6784 100644 --- a/packages/ui/certd-client/src/views/certd/project/detail/index.vue +++ b/packages/ui/certd-client/src/views/certd/project/detail/index.vue @@ -28,6 +28,7 @@ diff --git a/packages/ui/certd-client/src/views/certd/suite/mine/index.vue b/packages/ui/certd-client/src/views/certd/suite/mine/index.vue index f62295758..f3f64f7e9 100644 --- a/packages/ui/certd-client/src/views/certd/suite/mine/index.vue +++ b/packages/ui/certd-client/src/views/certd/suite/mine/index.vue @@ -15,14 +15,14 @@ diff --git a/packages/ui/certd-client/src/views/sys/pipeline/index.vue b/packages/ui/certd-client/src/views/sys/pipeline/index.vue index 6b8cfeee9..dd7654ee7 100644 --- a/packages/ui/certd-client/src/views/sys/pipeline/index.vue +++ b/packages/ui/certd-client/src/views/sys/pipeline/index.vue @@ -14,7 +14,9 @@ diff --git a/packages/ui/certd-client/src/views/sys/suite/invite/level.vue b/packages/ui/certd-client/src/views/sys/suite/invite/level.vue index a8cefe29b..7e2bfb8c6 100644 --- a/packages/ui/certd-client/src/views/sys/suite/invite/level.vue +++ b/packages/ui/certd-client/src/views/sys/suite/invite/level.vue @@ -46,11 +46,15 @@ diff --git a/packages/ui/certd-client/src/views/sys/suite/user-suite/index.vue b/packages/ui/certd-client/src/views/sys/suite/user-suite/index.vue index f00230e42..ecffddb91 100644 --- a/packages/ui/certd-client/src/views/sys/suite/user-suite/index.vue +++ b/packages/ui/certd-client/src/views/sys/suite/user-suite/index.vue @@ -11,7 +11,9 @@ diff --git a/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.ts b/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.ts index 35377e1b0..d314898a4 100644 --- a/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.ts +++ b/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.ts @@ -1,9 +1,10 @@ -import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; -import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; +import { utils } from "@certd/basic"; +import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; +import { AbstractPlusTaskPlugin } from "@certd/plugin-plus"; import { VolcengineAccess } from "../access.js"; import { VolcengineClient } from "../ve-client.js"; -import { utils } from "@certd/basic"; const regionOptions = [ { label: "北京", value: "cn-beijing" }, @@ -20,13 +21,14 @@ const regionOptions = [ icon: "svg:icon-volcengine", group: pluginGroups.volcengine.key, desc: "替换火山引擎VKE集群中的TLS Secret证书", + needPlus:true, default: { strategy: { runStrategy: RunStrategy.SkipWhenSucceed, }, }, }) -export class VolcengineDeployToVKE extends AbstractTaskPlugin { +export class VolcengineDeployToVKE extends AbstractPlusTaskPlugin { @TaskInput({ title: "域名证书", helper: "请选择前置任务输出的域名证书", From 77b802445322d576d54d194f7c505da49e0e824c Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Jun 2026 02:12:47 +0800 Subject: [PATCH 05/19] =?UTF-8?q?perf(volcengine-vke):=20=E7=81=AB?= =?UTF-8?q?=E5=B1=B1VKE=E9=9B=86=E7=BE=A4=E8=AF=81=E4=B9=A6=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E4=B8=A4=E7=A7=8D=E7=B1=BB=E5=9E=8B=E7=9A=84=E8=AF=81?= =?UTF-8?q?=E4=B9=A6=E4=BF=9D=E5=AF=86=E5=AD=97=E5=85=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../deploy_VolcengineDeployToVKE.yaml | 28 ++- .../plugins/plugin-deploy-to-vke.test.ts | 62 +++++++ .../plugins/plugin-deploy-to-vke.ts | 159 +++++++++++++++--- .../plugins/plugin-volcengine/ve-client.ts | 2 +- 4 files changed, 217 insertions(+), 34 deletions(-) diff --git a/packages/ui/certd-server/metadata/deploy_VolcengineDeployToVKE.yaml b/packages/ui/certd-server/metadata/deploy_VolcengineDeployToVKE.yaml index 628d0b716..fadb6625e 100644 --- a/packages/ui/certd-server/metadata/deploy_VolcengineDeployToVKE.yaml +++ b/packages/ui/certd-server/metadata/deploy_VolcengineDeployToVKE.yaml @@ -6,7 +6,7 @@ name: VolcengineDeployToVKE title: 火山引擎-替换VKE证书 icon: svg:icon-volcengine group: volcengine -desc: 替换火山引擎VKE集群中的TLS Secret证书 +desc: 将证书上传至火山引擎证书中心后,通过 cert_center 方式替换VKE集群中的Secret input: cert: title: 域名证书 @@ -15,6 +15,7 @@ input: name: output-selector from: - ':cert:' + - 'VolcengineUploadToCertCenter' required: true order: 0 certDomains: @@ -140,23 +141,38 @@ input: secretName: title: Secret名称 required: true - helper: 存储TLS证书的Secret名称,可填写多个 + helper: 选择要替换的Secret,可多选 component: - name: a-select + name: remote-select vModel: value mode: tags - open: false + type: plugin + action: onGetSecretList + search: false + pager: false + single: false + watches: + - certDomains + - accessId + - regionId + - clusterId + - kubeconfigType + - namespace mergeScript: |2- return { show: ctx.compute(({form}) => form.targetType === 'secret'), - required: ctx.compute(({form}) => form.targetType === 'secret') + required: ctx.compute(({form}) => form.targetType === 'secret'), + component: { + form: ctx.compute(({form}) => form) + } } order: 0 + createOnNotFound: title: Secret自动创建 - helper: 如果Secret不存在,则创建kubernetes.io/tls类型Secret + helper: 如果Secret不存在,则创建Opaque类型Secret value: false component: name: a-switch diff --git a/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.test.ts b/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.test.ts index 748ca73dc..32bd28a07 100644 --- a/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.test.ts +++ b/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.test.ts @@ -3,6 +3,7 @@ import assert from "node:assert/strict"; import { VolcengineDeployToVKE } from "./plugin-deploy-to-vke.js"; +import { CertInfo } from "@certd/plugin-cert"; describe("VolcengineDeployToVKE", () => { it("uses a single-select cluster field", () => { @@ -86,4 +87,65 @@ describe("VolcengineDeployToVKE", () => { /当前命名空间可用Ingress:app-web,api-web/ ); }); + + it("creates Secret with cert_center format for new non-tls secrets", async () => { + const plugin = new VolcengineDeployToVKE(); + plugin.namespace = "default"; + plugin.targetType = "secret"; + plugin.secretName = "test-tls"; + plugin.createOnNotFound = true; + plugin.logger = { info: () => undefined } as any; + plugin.appendTimeSuffix = (s: string) => s + "-test"; + + let secretBody: any; + await (plugin as any).patchCertSecret({ + certId: "cert-abc123", + k8sClient: { + patchSecret: async (opts: any) => { + secretBody = opts.body; + return {}; + }, + client: { + readNamespacedSecret: async () => { + throw Object.assign(new Error("Not Found"), { response: { body: { code: 404 } } }); + }, + }, + }, + secretNames: ["test-tls"], + }); + + assert.equal(secretBody.type, "Opaque"); + assert.equal(secretBody.data["cert_id"], Buffer.from("cert-abc123").toString("base64")); + assert.equal(secretBody.data["cert_source"], Buffer.from("cert_center").toString("base64")); + }); + + it("uses tls.crt/tls.key format for kubernetes.io/tls secrets", async () => { + const plugin = new VolcengineDeployToVKE(); + plugin.namespace = "default"; + plugin.targetType = "secret"; + plugin.secretName = "test-tls"; + plugin.logger = { info: () => undefined } as any; + plugin.appendTimeSuffix = (s: string) => s + "-test"; + plugin.cert = { crt: "MY_CRT", key: "MY_KEY" } as CertInfo; + + let secretBody: any; + await (plugin as any).patchCertSecret({ + certId: "cert-abc123", + k8sClient: { + patchSecret: async (opts: any) => { + secretBody = opts.body; + return {}; + }, + client: { + readNamespacedSecret: async () => ({ + body: { type: "kubernetes.io/tls" }, + }), + }, + }, + secretNames: ["test-tls"], + }); + + assert.equal(secretBody.data["tls.crt"], Buffer.from("MY_CRT").toString("base64")); + assert.equal(secretBody.data["tls.key"], Buffer.from("MY_KEY").toString("base64")); + }); }); diff --git a/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.ts b/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.ts index d314898a4..ae6246080 100644 --- a/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.ts +++ b/packages/ui/certd-server/src/plugins/plugin-volcengine/plugins/plugin-deploy-to-vke.ts @@ -34,11 +34,11 @@ export class VolcengineDeployToVKE extends AbstractPlusTaskPlugin { helper: "请选择前置任务输出的域名证书", component: { name: "output-selector", - from: [...CertApplyPluginNames], + from: [...CertApplyPluginNames, "VolcengineUploadToCertCenter"], }, required: true, }) - cert!: CertInfo; + cert!: CertInfo | string; @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) certDomains!: string[]; @@ -109,11 +109,11 @@ export class VolcengineDeployToVKE extends AbstractPlusTaskPlugin { component: { name: "a-select", options: [ - { label: "按Ingress替换", value: "ingress" }, { label: "按Secret替换", value: "secret" }, + { label: "按Ingress替换", value: "ingress" }, ], }, - value: "ingress", + value: "secret", required: true, }) targetType!: "ingress" | "secret"; @@ -134,17 +134,25 @@ export class VolcengineDeployToVKE extends AbstractPlusTaskPlugin { @TaskInput({ title: "Secret名称", required: true, - helper: "存储TLS证书的Secret名称,可填写多个", + helper: "选择要替换的Secret,可多选", component: { - name: "a-select", + name: "remote-select", vModel: "value", mode: "tags", - open: false, + type: "plugin", + action: "onGetSecretList", + search: false, + pager: false, + single: false, + watches: ["certDomains", "accessId", "regionId", "clusterId", "kubeconfigType", "namespace"], }, mergeScript: ` return { show: ctx.compute(({form}) => form.targetType === 'secret'), - required: ctx.compute(({form}) => form.targetType === 'secret') + required: ctx.compute(({form}) => form.targetType === 'secret'), + component: { + form: ctx.compute(({form}) => form) + } } `, }) @@ -152,7 +160,7 @@ export class VolcengineDeployToVKE extends AbstractPlusTaskPlugin { @TaskInput({ title: "Secret自动创建", - helper: "如果Secret不存在,则创建kubernetes.io/tls类型Secret", + helper: "如果Secret不存在,则创建Opaque类型Secret", value: false, component: { name: "a-switch", @@ -183,6 +191,23 @@ export class VolcengineDeployToVKE extends AbstractPlusTaskPlugin { this.logger.info("开始替换火山引擎VKE证书"); const access = await this.getAccess(this.accessId); const vkeService = await this.getVkeService(access); + + // 上传证书到证书中心 + let certId: string; + if (typeof this.cert !== "string") { + const certInfo = this.cert as CertInfo; + this.logger.info("开始上传证书到证书中心"); + const certService = await this.getCertService(access); + certId = await certService.ImportCertificate({ + certName: this.appendTimeSuffix("certd"), + cert: certInfo, + }); + this.logger.info("上传证书到证书中心成功:" + certId); + } else { + certId = this.cert; + this.logger.info("使用已有证书中心ID:" + certId); + } + const kubeconfigId = await this.createKubeconfig(vkeService); try { @@ -193,7 +218,7 @@ export class VolcengineDeployToVKE extends AbstractPlusTaskPlugin { skipTLSVerify: this.skipTLSVerify, }); const secretNames = await this.getTargetSecretNames(k8sClient); - await this.patchCertSecret({ cert: this.cert, k8sClient, secretNames }); + await this.patchCertSecret({ certId, k8sClient, secretNames }); } catch (e) { if (e.response?.body) { throw new Error(this.formatK8sError(e.response.body)); @@ -207,6 +232,15 @@ export class VolcengineDeployToVKE extends AbstractPlusTaskPlugin { this.logger.info("VKE证书替换完成"); } + private async getCertService(access: VolcengineAccess) { + const client = new VolcengineClient({ + logger: this.logger, + access, + http: this.http, + }); + return await client.getCertCenterService(); + } + private async getVkeService(access: VolcengineAccess) { const client = new VolcengineClient({ logger: this.logger, @@ -295,6 +329,11 @@ export class VolcengineDeployToVKE extends AbstractPlusTaskPlugin { } private formatK8sError(body: any) { + if (body?.code === 422 && body?.message?.includes("field is immutable")) { + const secretName = body.details?.name || "未知"; + return `Secret类型不可变:Secret ${secretName} 已是kubernetes.io/tls类型,type字段不可修改。\n请删除该Secret后重试,或选择正确的Secret。\n原始错误:${JSON.stringify(body)}`; + } + if (body?.code !== 403 || body?.reason !== "Forbidden") { return JSON.stringify(body); } @@ -336,34 +375,71 @@ export class VolcengineDeployToVKE extends AbstractPlusTaskPlugin { return secretNames; } - private async patchCertSecret(options: { cert: CertInfo; k8sClient: any; secretNames: string[] }) { - const { cert, k8sClient, secretNames } = options; + private async patchCertSecret(options: { certId: string; k8sClient: any; secretNames: string[] }) { + const { certId, k8sClient, secretNames } = options; if (!secretNames || secretNames.length === 0) { throw new Error("Secret名称不能为空"); } - const body: any = { - data: { - "tls.crt": Buffer.from(cert.crt).toString("base64"), - "tls.key": Buffer.from(cert.key).toString("base64"), - }, - metadata: { - labels: { - certd: this.appendTimeSuffix("certd"), - }, - }, - }; - for (const secretName of secretNames) { + let useTlsFormat = false; + try { + const res = await k8sClient.client.readNamespacedSecret(secretName, this.namespace); + useTlsFormat = res.body?.type === "kubernetes.io/tls"; + } catch (e) { + // Secret 不存在,将走创建逻辑 + } + + let body: any; + if (useTlsFormat) { + let crt: string; + let key: string; + if (typeof this.cert === "string") { + const access = await this.getAccess(this.accessId); + const certService = await this.getCertService(access); + const detail = await certService.GetCertificateDetail(this.cert); + crt = detail.CertificateChain || ""; + key = detail.PrivateKey || ""; + this.logger.info("从证书中心获取证书详情成功"); + } else { + crt = this.cert.crt; + key = this.cert.key; + } + body = { + data: { + "tls.crt": Buffer.from(crt).toString("base64"), + "tls.key": Buffer.from(key).toString("base64"), + }, + metadata: { + labels: { + certd: this.appendTimeSuffix("certd"), + }, + }, + }; + } else { + body = { + type: "Opaque", + data: { + cert_id: Buffer.from(certId).toString("base64"), + cert_source: Buffer.from("cert_center").toString("base64"), + }, + metadata: { + labels: { + certd: this.appendTimeSuffix("certd"), + }, + }, + }; + } + body.metadata.name = secretName; - this.logger.info(`开始更新VKE Secret:${secretName}`); + this.logger.info("开始更新VKE Secret:" + secretName); await k8sClient.patchSecret({ namespace: this.namespace, secretName, body, createOnNotFound: this.createOnNotFound, }); - this.logger.info(`VKE Secret已更新:${secretName}`); + this.logger.info("VKE Secret已更新:" + secretName); } if (this.targetType === "ingress" && this.ingressName) { @@ -391,6 +467,35 @@ export class VolcengineDeployToVKE extends AbstractPlusTaskPlugin { value: item.Id, })); } + async onGetSecretList() { + if (!this.accessId) { + throw new Error("请选择Access授权"); + } + if (!this.clusterId) { + throw new Error("请选择VKE集群"); + } + const access = await this.getAccess(this.accessId); + const vkeService = await this.getVkeService(access); + const kubeconfigId = await this.createKubeconfig(vkeService); + + try { + const kubeconfig = await this.getKubeconfig(vkeService, kubeconfigId); + const k8sClient = new this.K8sClient({ + kubeConfigStr: kubeconfig, + logger: this.logger, + skipTLSVerify: this.skipTLSVerify, + }); + const res = await k8sClient.getSecrets({ namespace: this.namespace || "default" }); + const list = res.body?.items || res.items || []; + return list.map((item: any) => ({ + label: item.metadata.name, + value: item.metadata.name, + })); + } finally { + await this.deleteKubeconfig(vkeService, kubeconfigId); + } + } + } -new VolcengineDeployToVKE(); +new VolcengineDeployToVKE(); \ No newline at end of file diff --git a/packages/ui/certd-server/src/plugins/plugin-volcengine/ve-client.ts b/packages/ui/certd-server/src/plugins/plugin-volcengine/ve-client.ts index c07bdf1f8..e3049e3c1 100644 --- a/packages/ui/certd-server/src/plugins/plugin-volcengine/ve-client.ts +++ b/packages/ui/certd-server/src/plugins/plugin-volcengine/ve-client.ts @@ -1,4 +1,4 @@ -import { VolcengineAccess } from "./access.js"; +import { VolcengineAccess } from "./access.js"; import { HttpClient, ILogger } from "@certd/basic"; export type VolcengineOpts = { From 73b3a29cfc07e3dc2d5f813070ba6f7de69a7464 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Jun 2026 02:15:39 +0800 Subject: [PATCH 06/19] build: prepare to build --- packages/core/basic/build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/basic/build.md b/packages/core/basic/build.md index e4394158c..bfdda0140 100644 --- a/packages/core/basic/build.md +++ b/packages/core/basic/build.md @@ -1 +1 @@ -12:22 +02:15 From 28bbea85f0fd7ac2e636b8b95c8e7dab37db5e36 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 6 Jun 2026 02:20:09 +0800 Subject: [PATCH 07/19] chore: 1 --- .../src/views/certd/cert/apply-template/index.vue | 1 - .../metadata/deploy_VolcengineDeployToVKE.yaml | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/ui/certd-client/src/views/certd/cert/apply-template/index.vue b/packages/ui/certd-client/src/views/certd/cert/apply-template/index.vue index 7a95db18e..592bf0498 100644 --- a/packages/ui/certd-client/src/views/certd/cert/apply-template/index.vue +++ b/packages/ui/certd-client/src/views/certd/cert/apply-template/index.vue @@ -11,7 +11,6 @@