perf: 域名导入

This commit is contained in:
xiaojunnuo
2026-01-21 18:24:03 +08:00
parent f75c73d739
commit ad64384891
8 changed files with 78 additions and 45 deletions

View File

@@ -31,8 +31,6 @@ export type DnsProviderContext = {
export type DomainRecord = {
id: string;
domain: string;
registrationDate: number;
expirationDate: number;
};
export interface IDnsProvider<T = any> {

View File

@@ -3,7 +3,7 @@ VITE_APP_API=api
VITE_APP_PM_ENABLED=true
VITE_APP_TITLE=Certd
VITE_APP_SLOGAN=让你的证书永不过期
VITE_APP_COPYRIGHT_YEAR=2021-2025
VITE_APP_COPYRIGHT_YEAR=2021-2026
VITE_APP_COPYRIGHT_NAME=handsfree.work
VITE_APP_COPYRIGHT_URL=https://certd.handsfree.work
VITE_APP_LOGO=static/images/logo/logo.svg

View File

@@ -28,4 +28,10 @@ export const Dicts = {
{ label: "SSH(已废弃请选择SFTP方式)", value: "ssh", disabled: true },
],
}),
domainFromTypeDict: dict({
data: [
{ value: "manual", label: "手动" },
{ value: "auto", label: "自动" },
],
}),
};

View File

@@ -13,6 +13,12 @@ export default {
title: "Operation",
},
},
pipelinePage: {
addMore: "Add More Pipelines",
aliyunSubscriptionPipeline: "Aliyun Subscription Pipeline",
legoCertPipeline: "Lego Certificate Pipeline",
customPipeline: "Custom Pipeline",
},
order: {
confirmTitle: "Order Confirmation",
package: "Package",
@@ -833,6 +839,8 @@ export default {
disabled: "Disabled",
challengeSetting: "Challenge Setting",
gotoCnameTip: "Please go to CNAME Record Page",
fromType: "From Type",
expirationDate: "Expiration Date",
},
addonSelector: {
select: "Select",

View File

@@ -17,6 +17,12 @@ export default {
title: "操作列",
},
},
pipelinePage: {
addMore: "添加更多流水线",
aliyunSubscriptionPipeline: "阿里云订阅流水线",
legoCertPipeline: "Lego证书流水线",
customPipeline: "自定义流水线",
},
order: {
confirmTitle: "订单确认",
package: "套餐",
@@ -846,6 +852,8 @@ export default {
disabled: "禁用/启用",
challengeSetting: "校验配置",
gotoCnameTip: "CNAME域名配置请前往CNAME记录页面添加",
fromType: "来源类型",
expirationDate: "到期时间",
},
addonSelector: {
select: "选择",

View File

@@ -134,6 +134,10 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
sorter: true,
},
},
expirationDate: {
title: t("certd.domain.expirationDate"),
type: "date",
},
challengeType: {
title: t("certd.domain.challengeType"),
type: "dict-select",
@@ -300,6 +304,16 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
},
},
fromType: {
title: t("certd.domain.fromType"),
type: "dict-select",
dict: Dicts.domainFromTypeDict,
column: {
component: {
color: "auto",
},
},
},
disabled: {
title: t("certd.domain.disabled"),
type: "dict-switch",

View File

@@ -9,34 +9,22 @@
</template>
</a-alert> -->
<fs-crud ref="crudRef" v-bind="crudBinding">
<template #actionbar-right="scope">
<template #actionbar-right>
<a-dropdown class="ml-1">
<a-button type="primary" class="ant-dropdown-link" @click.prevent>
更多流水线
{{ t("certd.pipelinePage.addMore") }}
<DownOutlined />
</a-button>
<template #overlay>
<a-menu @click="openCertApplyDialog">
<a-menu @click="onActionbarMoreItemClick">
<!-- <a-menu-item key="CertApplyUpload" class="flex items-center">
<fs-icon icon="ion:business-outline" />
商用证书托管流水线
</a-menu-item> -->
<a-menu-item key="CertApplyGetFormAliyun">
<a-menu-item v-for="item in addMorePipelineBtns" :key="item.key" :title="item.title">
<div class="flex items-center">
<fs-icon icon="svg:icon-aliyun" />
<span class="ml-2">阿里云订阅证书流水线</span>
</div>
</a-menu-item>
<a-menu-item key="CertApplyLego">
<div class="flex items-center">
<fs-icon icon="cbi:lego" />
<span class="ml-2">Lego申请证书流水线</span>
</div>
</a-menu-item>
<a-menu-item key="AddPipeline">
<div class="flex items-center">
<fs-icon icon="ion:add-circle-outline" />
<span class="ml-2">自定义流水线</span>
<fs-icon :icon="item.icon" />
<span class="ml-2">{{ item.title }}</span>
</div>
</a-menu-item>
</a-menu>
@@ -85,6 +73,30 @@ const selectedRowKeys = ref([]);
const context: any = {
selectedRowKeys,
};
const { openAddCertdPipelineDialog } = useCertPipelineCreator();
const addMorePipelineBtns = computed(() => {
return [
{ key: "CertApplyGetFormAliyun", title: t("certd.pipelinePage.aliyunSubscriptionPipeline"), icon: "svg:icon-aliyun" },
{ key: "CertApplyLego", title: t("certd.pipelinePage.legoCertPipeline"), icon: "cbi:lego" },
{ key: "AddPipeline", title: t("certd.pipelinePage.customPipeline"), icon: "ion:add-circle-outline" },
];
});
function onActionbarMoreItemClick(req: { key: string; item: any }) {
openCertApplyDialog({ key: req.key, title: req.item?.title });
}
function openCertApplyDialog(req: { key: string; title: string }) {
if (req.key === "AddPipeline") {
crudExpose.openAdd({});
return;
}
const searchForm = crudExpose.getSearchValidatedFormData();
const defaultGroupId = searchForm.groupId;
openAddCertdPipelineDialog({ pluginName: req.key, defaultGroupId, title: req.title });
}
context.openCertApplyDialog = openCertApplyDialog;
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
// 页面打开后获取列表数据
@@ -115,25 +127,6 @@ function batchDelete() {
},
});
}
const { openAddCertdPipelineDialog } = useCertPipelineCreator();
const addMorePipelineBtns = computed(() => {
return [
{ key: "CertApplyGetFormAliyun", title: t("certd.aliyunSubscriptionPipeline"), icon: "svg:icon-aliyun" },
{ key: "CertApplyLego", title: t("certd.legoApplicationPipeline"), icon: "cbi:lego" },
{ key: "AddPipeline", title: t("certd.customPipeline"), icon: "ion:add-circle-outline" },
];
});
function openCertApplyDialog(req: { key: string; title: string }) {
if (req.key === "AddPipeline") {
crudExpose.openAdd({});
return;
}
const searchForm = crudExpose.getSearchValidatedFormData();
const defaultGroupId = searchForm.groupId;
openAddCertdPipelineDialog({ pluginName: req.key, defaultGroupId, title: req.title });
}
context.openCertApplyDialog = openCertApplyDialog;
</script>
<style lang="less">
.batch-actions {

View File

@@ -60,6 +60,9 @@ export class DomainService extends BaseService<DomainEntity> {
if (old) {
throw new Error(`域名(${param.domain})不能重复`);
}
if (!param.fromType) {
param.fromType = 'manual'
}
return await super.add(param);
}
@@ -219,6 +222,11 @@ export class DomainService extends BaseService<DomainEntity> {
const importDomain = async(domainRecord: any) =>{
const domain = domainRecord.domain
const certProps :any={
registrationDate: domainRecord.registrationDate,
expirationDate: domainRecord.expirationDate,
}
const old = await this.findOne({
where: {
domain,
@@ -228,8 +236,7 @@ export class DomainService extends BaseService<DomainEntity> {
if (old) {
const updateObj :any={
id: old.id,
registrationDate: domainRecord.registrationDate,
expirationDate: domainRecord.expirationDate,
...certProps
}
if (old.fromType !== 'manual'){
//如果不是手动的,更新校验配置
@@ -238,7 +245,7 @@ export class DomainService extends BaseService<DomainEntity> {
updateObj.challengeType = challengeType
}
//更新
await this.update(updateObj)
await super.update(updateObj)
} else {
//添加
await this.add({
@@ -249,8 +256,7 @@ export class DomainService extends BaseService<DomainEntity> {
challengeType,
disabled: false,
fromType: 'auto',
registrationDate: domainRecord.registrationDate,
expirationDate: domainRecord.expirationDate,
...certProps
})
}
}