mirror of
https://github.com/certd/certd.git
synced 2026-04-23 11:37:23 +08:00
pref: 支持子域名托管的域名证书申请
This commit is contained in:
+16
-5
@@ -1,6 +1,7 @@
|
||||
import { request } from "/src/api/service";
|
||||
|
||||
const apiPrefix = "/cname/record";
|
||||
const subDomainApiPrefix = "/pi/subDomain";
|
||||
|
||||
export type CnameRecord = {
|
||||
id?: number;
|
||||
@@ -18,7 +19,7 @@ export type DomainGroupItem = {
|
||||
export async function GetList() {
|
||||
return await request({
|
||||
url: apiPrefix + "/list",
|
||||
method: "post"
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,8 +29,8 @@ export async function GetByDomain(domain: string) {
|
||||
method: "post",
|
||||
data: {
|
||||
domain,
|
||||
createOnNotFound: true
|
||||
}
|
||||
createOnNotFound: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -38,7 +39,17 @@ export async function DoVerify(id: number) {
|
||||
url: apiPrefix + "/verify",
|
||||
method: "post",
|
||||
data: {
|
||||
id
|
||||
}
|
||||
id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function ParseDomain(fullDomain: string) {
|
||||
return await request({
|
||||
url: subDomainApiPrefix + "/parseDomain",
|
||||
method: "post",
|
||||
data: {
|
||||
fullDomain,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
+19
-37
@@ -32,26 +32,14 @@
|
||||
<div class="form-item">
|
||||
<span class="label">DNS类型:</span>
|
||||
<span class="input">
|
||||
<fs-dict-select
|
||||
v-model:value="item.dnsProviderType"
|
||||
size="small"
|
||||
:dict="dnsProviderTypeDict"
|
||||
placeholder="DNS提供商"
|
||||
@change="onPlanChanged"
|
||||
></fs-dict-select>
|
||||
<fs-dict-select v-model:value="item.dnsProviderType" size="small" :dict="dnsProviderTypeDict" placeholder="DNS提供商" @change="onPlanChanged"></fs-dict-select>
|
||||
</span>
|
||||
</div>
|
||||
<a-divider type="vertical" />
|
||||
<div class="form-item">
|
||||
<span class="label">DNS授权:</span>
|
||||
<span class="input">
|
||||
<access-selector
|
||||
v-model="item.dnsProviderAccessId"
|
||||
size="small"
|
||||
:type="item.dnsProviderType"
|
||||
placeholder="请选择"
|
||||
@change="onPlanChanged"
|
||||
></access-selector>
|
||||
<access-selector v-model="item.dnsProviderAccessId" size="small" :type="item.dnsProviderType" placeholder="请选择" @change="onPlanChanged"></access-selector>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -80,28 +68,27 @@ import { dict, FsDictSelect } from "@fast-crud/fast-crud";
|
||||
import AccessSelector from "/@/views/certd/access/access-selector/index.vue";
|
||||
import CnameVerifyPlan from "./cname-verify-plan.vue";
|
||||
import HttpVerifyPlan from "./http-verify-plan.vue";
|
||||
//@ts-ignore
|
||||
import psl from "psl";
|
||||
import { Form } from "ant-design-vue";
|
||||
import { DomainsVerifyPlanInput } from "./type";
|
||||
import { CnameRecord, DomainGroupItem } from "./api";
|
||||
import { DomainGroupItem, ParseDomain } from "./api";
|
||||
|
||||
defineOptions({
|
||||
name: "DomainsVerifyPlanEditor"
|
||||
name: "DomainsVerifyPlanEditor",
|
||||
});
|
||||
|
||||
const challengeTypeOptions = ref<any[]>([
|
||||
{
|
||||
label: "DNS验证",
|
||||
value: "dns"
|
||||
value: "dns",
|
||||
},
|
||||
{
|
||||
label: "CNAME验证",
|
||||
value: "cname"
|
||||
value: "cname",
|
||||
},
|
||||
{
|
||||
label: "HTTP验证",
|
||||
value: "http"
|
||||
}
|
||||
value: "http",
|
||||
},
|
||||
]);
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -122,7 +109,7 @@ function fullscreenExit() {
|
||||
}
|
||||
const planRef = ref<DomainsVerifyPlanInput>(props.modelValue || {});
|
||||
const dnsProviderTypeDict = dict({
|
||||
url: "pi/dnsProvider/dnsProviderTypeDict"
|
||||
url: "pi/dnsProvider/dnsProviderTypeDict",
|
||||
});
|
||||
|
||||
const formItemContext = Form.useInjectFormItemContext();
|
||||
@@ -139,7 +126,7 @@ function showError(error: string) {
|
||||
|
||||
type DomainGroup = Record<string, DomainGroupItem>;
|
||||
|
||||
function onDomainsChanged(domains: string[]) {
|
||||
async function onDomainsChanged(domains: string[]) {
|
||||
if (domains == null) {
|
||||
return;
|
||||
}
|
||||
@@ -147,12 +134,7 @@ function onDomainsChanged(domains: string[]) {
|
||||
const domainGroups: DomainGroup = {};
|
||||
for (let domain of domains) {
|
||||
const keyDomain = domain.replace("*.", "");
|
||||
const parsed = psl.parse(keyDomain);
|
||||
if (parsed.error) {
|
||||
showError(`域名${domain}解析失败: ${JSON.stringify(parsed.error)}`);
|
||||
continue;
|
||||
}
|
||||
const mainDomain = parsed.domain;
|
||||
const mainDomain = await ParseDomain(keyDomain);
|
||||
if (mainDomain == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -161,7 +143,7 @@ function onDomainsChanged(domains: string[]) {
|
||||
group = {
|
||||
domain: mainDomain,
|
||||
domains: [],
|
||||
keySubDomains: []
|
||||
keySubDomains: [],
|
||||
} as DomainGroupItem;
|
||||
domainGroups[mainDomain] = group;
|
||||
}
|
||||
@@ -180,7 +162,7 @@ function onDomainsChanged(domains: string[]) {
|
||||
//@ts-ignore
|
||||
cnameVerifyPlan: {},
|
||||
//@ts-ignore
|
||||
httpVerifyPlan: {}
|
||||
httpVerifyPlan: {},
|
||||
};
|
||||
planRef.value[domain] = planItem;
|
||||
}
|
||||
@@ -196,7 +178,7 @@ function onDomainsChanged(domains: string[]) {
|
||||
if (!cnameOrigin[subDomain]) {
|
||||
//@ts-ignore
|
||||
planItem.cnameVerifyPlan[subDomain] = {
|
||||
id: 0
|
||||
id: 0,
|
||||
};
|
||||
} else {
|
||||
planItem.cnameVerifyPlan[subDomain] = cnameOrigin[subDomain];
|
||||
@@ -205,14 +187,14 @@ function onDomainsChanged(domains: string[]) {
|
||||
if (!cnamePlan[subDomain]) {
|
||||
//@ts-ignore
|
||||
cnamePlan[subDomain] = {
|
||||
id: 0
|
||||
id: 0,
|
||||
};
|
||||
}
|
||||
|
||||
if (!httpOrigin[subDomain]) {
|
||||
//@ts-ignore
|
||||
planItem.httpVerifyPlan[subDomain] = {
|
||||
domain: subDomain
|
||||
domain: subDomain,
|
||||
};
|
||||
} else {
|
||||
planItem.httpVerifyPlan[subDomain] = httpOrigin[subDomain];
|
||||
@@ -221,7 +203,7 @@ function onDomainsChanged(domains: string[]) {
|
||||
if (!httpPlan[subDomain]) {
|
||||
//@ts-ignore
|
||||
httpPlan[subDomain] = {
|
||||
domain: subDomain
|
||||
domain: subDomain,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -255,7 +237,7 @@ watch(
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -98,6 +98,17 @@ export const certdResources = [
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "子域名托管设置",
|
||||
name: "SubDomain",
|
||||
path: "/certd/pipeline/subDomain",
|
||||
component: "/certd/pipeline/sub-domain/index.vue",
|
||||
meta: {
|
||||
icon: "ion:link-outline",
|
||||
auth: true,
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "流水线分组管理",
|
||||
name: "PipelineGroupManager",
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// @ts-ignore
|
||||
import { request } from "/src/api/service";
|
||||
|
||||
const apiPrefix = "/pi/subDomain";
|
||||
|
||||
export async function GetList(query: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/page",
|
||||
method: "post",
|
||||
data: query,
|
||||
});
|
||||
}
|
||||
|
||||
export async function AddObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/add",
|
||||
method: "post",
|
||||
data: obj,
|
||||
});
|
||||
}
|
||||
|
||||
export async function UpdateObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/update",
|
||||
method: "post",
|
||||
data: obj,
|
||||
});
|
||||
}
|
||||
|
||||
export async function DelObj(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/delete",
|
||||
method: "post",
|
||||
params: { id },
|
||||
});
|
||||
}
|
||||
|
||||
export async function GetObj(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/info",
|
||||
method: "post",
|
||||
params: { id },
|
||||
});
|
||||
}
|
||||
|
||||
export async function GetDetail(id: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/detail",
|
||||
method: "post",
|
||||
params: { id },
|
||||
});
|
||||
}
|
||||
|
||||
export async function DeleteBatch(ids: any[]) {
|
||||
return await request({
|
||||
url: apiPrefix + "/batchDelete",
|
||||
method: "post",
|
||||
data: { ids },
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import * as api from "./api";
|
||||
import { Ref, ref } from "vue";
|
||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
return await api.GetList(query);
|
||||
};
|
||||
const editRequest = async ({ form, row }: EditReq) => {
|
||||
form.id = row.id;
|
||||
const res = await api.UpdateObj(form);
|
||||
return res;
|
||||
};
|
||||
const delRequest = async ({ row }: DelReq) => {
|
||||
return await api.DelObj(row.id);
|
||||
};
|
||||
|
||||
const addRequest = async ({ form }: AddReq) => {
|
||||
const res = await api.AddObj(form);
|
||||
return res;
|
||||
};
|
||||
|
||||
const selectedRowKeys: Ref<any[]> = ref([]);
|
||||
context.selectedRowKeys = selectedRowKeys;
|
||||
|
||||
return {
|
||||
crudOptions: {
|
||||
settings: {
|
||||
plugins: {
|
||||
//这里使用行选择插件,生成行选择crudOptions配置,最终会与crudOptions合并
|
||||
rowSelection: {
|
||||
enabled: true,
|
||||
order: -2,
|
||||
before: true,
|
||||
// handle: (pluginProps,useCrudProps)=>CrudOptions,
|
||||
props: {
|
||||
multiple: true,
|
||||
crossPage: true,
|
||||
selectedRowKeys,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
request: {
|
||||
pageRequest,
|
||||
addRequest,
|
||||
editRequest,
|
||||
delRequest,
|
||||
},
|
||||
// tabs: {
|
||||
// name: "status",
|
||||
// show: true,
|
||||
// },
|
||||
rowHandle: {
|
||||
minWidth: 200,
|
||||
fixed: "right",
|
||||
},
|
||||
columns: {
|
||||
id: {
|
||||
title: "ID",
|
||||
key: "id",
|
||||
type: "number",
|
||||
column: {
|
||||
width: 80,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
domain: {
|
||||
title: "子域名",
|
||||
type: "text",
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
editForm: {
|
||||
component: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
disabled: {
|
||||
title: "是否禁用",
|
||||
type: "dict-switch",
|
||||
dict: dict({
|
||||
data: [
|
||||
{ value: false, label: "启用", color: "green" },
|
||||
{ value: true, label: "禁用", color: "gray" },
|
||||
],
|
||||
}),
|
||||
search: {
|
||||
show: true,
|
||||
},
|
||||
form: {
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
createTime: {
|
||||
title: "创建时间",
|
||||
type: "datetime",
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 160,
|
||||
align: "center",
|
||||
},
|
||||
},
|
||||
updateTime: {
|
||||
title: "更新时间",
|
||||
type: "datetime",
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
column: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<fs-page class="page-cert">
|
||||
<template #header>
|
||||
<div class="title">
|
||||
子域名托管
|
||||
<span class="sub"> 当你的域名设置了子域名托管,需要在此处创建记录,否则申请证书将失败 </span>
|
||||
</div>
|
||||
</template>
|
||||
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||
<template #pagination-left>
|
||||
<a-tooltip title="批量删除">
|
||||
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</fs-crud>
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onActivated, onMounted } from "vue";
|
||||
import { useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
import { DeleteBatch } from "./api";
|
||||
|
||||
defineOptions({
|
||||
name: "CnameRecord",
|
||||
});
|
||||
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions });
|
||||
|
||||
const selectedRowKeys = context.selectedRowKeys;
|
||||
const handleBatchDelete = () => {
|
||||
if (selectedRowKeys.value?.length > 0) {
|
||||
Modal.confirm({
|
||||
title: "确认",
|
||||
content: `确定要批量删除这${selectedRowKeys.value.length}条记录吗`,
|
||||
async onOk() {
|
||||
await DeleteBatch(selectedRowKeys.value);
|
||||
message.info("删除成功");
|
||||
crudExpose.doRefresh();
|
||||
selectedRowKeys.value = [];
|
||||
},
|
||||
});
|
||||
} else {
|
||||
message.error("请先勾选记录");
|
||||
}
|
||||
};
|
||||
|
||||
// 页面打开后获取列表数据
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
onActivated(async () => {
|
||||
await crudExpose.doRefresh();
|
||||
});
|
||||
</script>
|
||||
<style lang="less"></style>
|
||||
Reference in New Issue
Block a user