perf: 输入证书域名时,支持点击导入域名

This commit is contained in:
xiaojunnuo
2026-01-25 22:57:59 +08:00
parent bca0eefc83
commit 40be42406c
8 changed files with 118 additions and 37 deletions
@@ -1,24 +1,35 @@
<template> <template>
<div class="domain-select"> <div class="domain-select">
<div class="flex flex-row"> <div class="flex flex-row">
<a-select class="domain-select-input" show-search :filter-option="filterOption" :options="optionsRef" :value="value" v-bind="attrs" @click="onClick" @update:value="emit('update:value', $event)"> <a-select
class="domain-select-input"
:dropdown-style="dropdownStyle"
show-search
:filter-option="filterOption"
:options="optionsRef"
:value="value"
v-bind="attrs"
@click="onClick"
@update:value="emit('update:value', $event)"
>
<template #dropdownRender="{ menuNode }"> <template #dropdownRender="{ menuNode }">
<template v-if="search"> <template v-if="search">
<div class="flex w-full" style="padding: 4px 8px"> <div class="flex w-full items-center justify-between flex-wrap" style="padding: 4px 8px">
<a-input <div class="flex-1 flex flex-row items-center">
ref="inputRef" <a-input
v-model:value="searchKeyRef" ref="inputRef"
class="flex-1" v-model:value="searchKeyRef"
allow-clear class="flex-1"
placeholder="这里可以搜索域名(数据来自设置->域名管理),列表中没有的域名可以直接在上面输入框输入" allow-clear
@keydown.enter="doSearch" placeholder="这里可以搜索域名(数据来自“设置->域名管理”),列表中没有的域名可以直接在上面输入框输入"
/> @keydown.enter="doSearch"
<a-button class="ml-2" :loading="loading" type="text" @click="doSearch"> />
<template #icon> <fs-button type="primary" class="m-1" :loading="loading" icon="mingcute:search-2-line" @click="doSearch"> 查询 </fs-button>
<search-outlined /> </div>
</template> <div class="manager flex flex-row items-center">
查询 <fs-button type="primary" class="m-1" icon="mingcute:vip-1-line" @click="openDomainImportDialog">导入域名</fs-button>
</a-button> <fs-button class="m-1" type="primary" icon="carbon:gui-management" @click="openDomainManager">管理域名</fs-button>
</div>
</div> </div>
<div v-if="hasError" class="helper p-2" :class="{ error: hasError }"> <div v-if="hasError" class="helper p-2" :class="{ error: hasError }">
{{ message }} {{ message }}
@@ -31,6 +42,15 @@
<a-pagination v-model:current="pagerRef.pageNo" simple :total="pagerRef.total" :page-size="pagerRef.pageSize" @change="onPageChange" /> <a-pagination v-model:current="pagerRef.pageNo" simple :total="pagerRef.total" :page-size="pagerRef.pageSize" @change="onPageChange" />
</div> </div>
</template> </template>
<template #option="scope">
<div class="flex flex-row items-center">
<span class="min-w-60">{{ scope.label }}</span>
<div>
<fs-values-format :model-value="scope.challengeType" :dict="challengeTypeDict"></fs-values-format>
<fs-values-format :model-value="scope.dnsProviderType" :dict="dnsProviderTypeDict"></fs-values-format>
</div>
</div>
</template>
</a-select> </a-select>
<div class="ml-5"> <div class="ml-5">
<fs-button :loading="loading" title="刷新我的域名列表" icon="ion:refresh-outline" @click="refreshOptions"></fs-button> <fs-button :loading="loading" title="刷新我的域名列表" icon="ion:refresh-outline" @click="refreshOptions"></fs-button>
@@ -44,6 +64,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, defineComponent, ref, Ref, useAttrs } from "vue"; import { computed, defineComponent, ref, Ref, useAttrs } from "vue";
import { request } from "/@/api/service"; import { request } from "/@/api/service";
import { Dicts } from "../lib/dicts";
import { useRouter } from "vue-router";
import { useDomainImport, useDomainImportManage } from "/@/views/certd/cert/domain/use";
defineOptions({ defineOptions({
name: "DomainSelector", name: "DomainSelector",
@@ -114,10 +137,14 @@ const getOptions = async () => {
options.push({ options.push({
value: item.domain, value: item.domain,
label: item.domain, label: item.domain,
dnsProviderType: item.dnsProviderType,
challengeType: item.challengeType,
}); });
options.push({ options.push({
value: `*.${item.domain}`, value: `*.${item.domain}`,
label: `*.${item.domain}`, label: `*.${item.domain}`,
dnsProviderType: item.dnsProviderType,
challengeType: item.challengeType,
}); });
} }
@@ -162,6 +189,29 @@ async function paginationClick(e: any) {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
} }
const dnsProviderTypeDict = Dicts.dnsProviderTypeDict;
const challengeTypeDict = Dicts.challengeTypeDict;
const router = useRouter();
function openDomainManager(e: any) {
e.preventDefault();
// router.push("/certd/cert/domain");
window.open(`${window.location.origin}/#/certd/cert/domain`);
}
const openDomainImportManageDialog = useDomainImportManage();
function openDomainImportDialog() {
openDomainImportManageDialog({
zIndex: 2060,
afterSubmit: res => {
refreshOptions();
},
});
}
const dropdownStyle = ref({
zIndex: 2000,
});
</script> </script>
<style lang="less"></style> <style lang="less"></style>
@@ -6,6 +6,7 @@ export type FormOptionReq = {
onSubmit?: any; onSubmit?: any;
body?: any; body?: any;
initialForm?: any; initialForm?: any;
zIndex?: number;
}; };
export function useFormDialog() { export function useFormDialog() {
@@ -19,6 +20,7 @@ export function useFormDialog() {
form: { form: {
initialForm: req.initialForm, initialForm: req.initialForm,
wrapper: { wrapper: {
zIndex: req.zIndex,
title: req.title, title: req.title,
saveRemind: false, saveRemind: false,
slots: { slots: {
@@ -3,11 +3,10 @@ import { Modal, notification } from "ant-design-vue";
import { Ref, ref } from "vue"; import { Ref, ref } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import * as api from "./api"; import * as api from "./api";
import DomainImportTaskStatus from "./import.vue"; import { useDomainImportManage } from "./use";
import { Dicts } from "/@/components/plugins/lib/dicts"; import { Dicts } from "/@/components/plugins/lib/dicts";
import { useSettingStore } from "/@/store/settings"; import { useSettingStore } from "/@/store/settings";
import { useUserStore } from "/@/store/user"; import { useUserStore } from "/@/store/user";
import { useFormDialog } from "/@/use/use-dialog";
import { createAccessApi } from "/@/views/certd/access/api"; import { createAccessApi } from "/@/views/certd/access/api";
import { useI18n } from "/src/locales"; import { useI18n } from "/src/locales";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
@@ -51,7 +50,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
url: "pi/dnsProvider/dnsProviderTypeDict", url: "pi/dnsProvider/dnsProviderTypeDict",
}); });
const { openFormDialog } = useFormDialog(); const openDomainImportManageDialog = useDomainImportManage();
return { return {
crudOptions: { crudOptions: {
settings: { settings: {
@@ -104,13 +103,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
color: "gold", color: "gold",
icon: "mingcute:vip-1-line", icon: "mingcute:vip-1-line",
click: async () => { click: async () => {
settingStore.checkPlus(); await openDomainImportManageDialog({
await openFormDialog({ afterSubmit: res => {
title: "从域名提供商导入域名",
body: () => {
return <DomainImportTaskStatus />;
},
onSubmit: async (form: any) => {
crudExpose.doRefresh(); crudExpose.doRefresh();
}, },
}); });
@@ -42,7 +42,7 @@
<div v-else>未执行</div> <div v-else>未执行</div>
</td> </td>
<td> <td>
<fs-button type="primary" icon="ion:play-outline" @click="startTask(item)">执行</fs-button> <fs-button type="primary" icon="ion:play-outline" :disabled="item.task?.status === 'running'" @click="startTask(item)">执行</fs-button>
<fs-button type="primary" class="ml-2" danger icon="ion:trash-outline" @click="deleteTask(item)">删除</fs-button> <fs-button type="primary" class="ml-2" danger icon="ion:trash-outline" @click="deleteTask(item)">删除</fs-button>
</td> </td>
</tr> </tr>
@@ -53,7 +53,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref } from "vue"; import { onMounted, onUnmounted, ref } from "vue";
import * as api from "./api"; import * as api from "./api";
import { Modal } from "ant-design-vue"; import { Modal } from "ant-design-vue";
import { useDomainImport } from "./use"; import { useDomainImport } from "./use";
@@ -90,7 +90,10 @@ const openDomainImportDialog = useDomainImport();
async function addTask() { async function addTask() {
await openDomainImportDialog({ await openDomainImportDialog({
afterSubmit: async () => { afterSubmit: async (res?: any) => {
if (res) {
await api.ImportTaskStart(res.key);
}
await loadImportTaskStatus(); await loadImportTaskStatus();
}, },
}); });
@@ -105,8 +108,16 @@ async function editTask(item: any) {
}); });
} }
const checkIntervalRef = ref();
onMounted(async () => { onMounted(async () => {
await loadImportTaskStatus(); await loadImportTaskStatus();
checkIntervalRef.value = setInterval(async () => {
await loadImportTaskStatus();
}, 3000);
});
onUnmounted(() => {
clearInterval(checkIntervalRef.value);
}); });
</script> </script>
@@ -3,7 +3,8 @@ import * as api from "./api";
import { useFormDialog } from "/@/use/use-dialog"; import { useFormDialog } from "/@/use/use-dialog";
import { compute } from "@fast-crud/fast-crud"; import { compute } from "@fast-crud/fast-crud";
import { Dicts } from "/@/components/plugins/lib/dicts"; import { Dicts } from "/@/components/plugins/lib/dicts";
import { useSettingStore } from "/@/store/settings";
import DomainImportTaskStatus from "./import.vue";
export function useDomainImport() { export function useDomainImport() {
const { openFormDialog } = useFormDialog(); const { openFormDialog } = useFormDialog();
@@ -49,7 +50,7 @@ export function useDomainImport() {
}, },
}; };
return function openDomainImportDialog(req: { afterSubmit?: () => void; form?: any }) { return function openDomainImportDialog(req: { afterSubmit?: (res?: any) => void; form?: any }) {
openFormDialog({ openFormDialog({
title: "从域名提供商导入域名", title: "从域名提供商导入域名",
columns: columns, columns: columns,
@@ -57,13 +58,33 @@ export function useDomainImport() {
...req.form, ...req.form,
}, },
onSubmit: async (form: any) => { onSubmit: async (form: any) => {
await api.ImportTaskSave({ const res = await api.ImportTaskSave({
key: form.key, key: form.key,
dnsProviderType: form.dnsProviderType, dnsProviderType: form.dnsProviderType,
dnsProviderAccessId: form.dnsProviderAccessId, dnsProviderAccessId: form.dnsProviderAccessId,
}); });
if (req.afterSubmit) { if (req.afterSubmit) {
req.afterSubmit(); req.afterSubmit(res);
}
},
});
};
}
export function useDomainImportManage() {
const { openFormDialog } = useFormDialog();
const settingStore = useSettingStore();
return async function openDomainImportManageDialog(req: { afterSubmit?: (res?: any) => void; form?: any; zIndex?: number }) {
settingStore.checkPlus();
await openFormDialog({
title: "从域名提供商导入域名",
body: () => {
return <DomainImportTaskStatus />;
},
zIndex: req.zIndex,
onSubmit: async (form: any) => {
if (req.afterSubmit) {
req.afterSubmit(form);
} }
}, },
}); });
@@ -261,7 +261,10 @@ export class DomainService extends BaseService<DomainEntity> {
const itemHandle = async (domainRecord: any) => { const itemHandle = async (domainRecord: any) => {
task.incrementCurrent() task.incrementCurrent()
const domain = domainRecord.domain let domain = domainRecord.domain
if (domain.endsWith(".")) {
domain = domain.slice(0, -1)
}
const old = await this.findOne({ const old = await this.findOne({
where: { where: {
@@ -410,7 +413,7 @@ export class DomainService extends BaseService<DomainEntity> {
await this.deleteDomainImportTask({userId,key}) await this.deleteDomainImportTask({userId,key})
} }
await this.addDomainImportTask({userId,dnsProviderType,dnsProviderAccessId,index}) return await this.addDomainImportTask({userId,dnsProviderType,dnsProviderAccessId,index})
} }
@@ -13,7 +13,7 @@ export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin {
vModel: "value", vModel: "value",
mode: "tags", mode: "tags",
// open: false, // open: false,
placeholder: "foo.com / *.foo.com / *.sub.foo.com / *.bar.com", placeholder: "请输入证书域名,比如:foo.com / *.foo.com / *.sub.foo.com / *.bar.com",
tokenSeparators: [",", " ", "", "、", "|"], tokenSeparators: [",", " ", "", "、", "|"],
search: true, search: true,
pager:true, pager:true,
@@ -192,7 +192,7 @@ export class HuaweiDnsProvider extends AbstractDnsProvider {
let list = ret.zones || [] let list = ret.zones || []
list = list.map((item: any) => ({ list = list.map((item: any) => ({
id: item.id, id: item.id,
domain: item.name, domain: item.name.endsWith(".") ? item.name.slice(0, -1) : item.name,
})); }));
return { return {
total:ret.metadata.total_count || list.length, total:ret.metadata.total_count || list.length,