【修复】申请配置证书CA列表,授权api新增新增btdomain

This commit is contained in:
cai
2025-09-17 14:54:50 +08:00
parent 51548f6788
commit b91fd107ee
147 changed files with 19178 additions and 2123 deletions

View File

@@ -55,6 +55,7 @@ import type {
ConstellixAccessConfig,
WebhookAccessConfig,
SpaceshipAccessConfig,
BTDomainAccessConfig,
} from "@/types/access";
import type { VNode, Ref } from "vue";
import { testAccess, getPlugins } from "@/api/access";
@@ -494,7 +495,7 @@ export const useApiFormController = (
value: string,
callback: (error?: Error) => void
) => {
if (!value.length) {
if (!value || !value.length) {
const mapTips = {
cloudflare: $t("t_0_1747042966820"),
btpanel: $t("t_1_1747042969705"),
@@ -523,6 +524,25 @@ export const useApiFormController = (
const mapTips = {
godaddy: $t("t_1_1747984133312"),
spaceship: "请输入 Spaceship API Secret",
btdomain: "请输入 BTDomain Secret Key",
};
return callback(
new Error(mapTips[param.value.type as keyof typeof mapTips])
);
}
callback();
},
},
account_id: {
trigger: "input",
validator: (
rule: FormItemRule,
value: string,
callback: (error?: Error) => void
) => {
if (!value) {
const mapTips = {
btdomain: "请输入 BTDomain Account ID",
};
return callback(
new Error(mapTips[param.value.type as keyof typeof mapTips])
@@ -621,6 +641,7 @@ export const useApiFormController = (
volcengine: $t("t_3_1747365600828"),
qiniu: $t("t_3_1747984134586"),
doge: $t("t_0_1750320239265"),
btdomain: "请输入 BTDomain Access Key",
};
return callback(
new Error(mapTips[param.value.type as keyof typeof mapTips])
@@ -636,7 +657,7 @@ export const useApiFormController = (
value: string,
callback: (error?: Error) => void
) => {
if (!value.length) {
if (!value || !value.length) {
const mapTips = {
tencentcloud: $t("t_2_1747042967277"),
huawei: $t("t_3_1747042967608"),
@@ -644,6 +665,7 @@ export const useApiFormController = (
volcengine: $t("t_4_1747365600137"),
doge: $t("t_1_1750320241427"),
constellix: "请输入Secret Key",
btdomain: "请输入 BTDomain Secret Key",
};
return callback(
new Error(mapTips[param.value.type as keyof typeof mapTips])
@@ -1230,6 +1252,21 @@ export const useApiFormController = (
})
);
break;
case "btdomain":
items.push(
useFormInput("Access Key", "config.access_key", {
allowInput: noSideSpace,
}),
useFormInput("Secret Key", "config.secret_key", {
type: "password",
showPasswordOn: "click",
allowInput: noSideSpace,
}),
useFormInput("Account ID", "config.account_id", {
allowInput: noSideSpace,
})
);
break;
case "plugin":
items.push(
useFormCustom(() => {
@@ -1478,7 +1515,14 @@ export const useApiFormController = (
api_key: "",
api_secret: "",
} as SpaceshipAccessConfig;
break;
break;
case "btdomain":
param.value.config = {
access_key: "",
secret_key: "",
account_id: "",
} as BTDomainAccessConfig;
break;
case "plugin":
param.value.config = {
name: pluginList.value[0]?.value || "",

View File

@@ -77,7 +77,9 @@ export default defineComponent({
const caOptions = ref<
Array<{ label: string; value: string; icon: string }>
>([]);
const emailOptions = ref<string[]>([]);
const emailOptions = ref<
Array<{ label: string; value: string; id: number; email: string }>
>([]);
const isLoadingCA = ref(false);
const isLoadingEmails = ref(false);
const showEmailDropdown = ref(false);
@@ -88,7 +90,7 @@ export default defineComponent({
isLoadingCA.value = true;
try {
const { data } = await getEabList({
ca: param.value.ca,
ca: "",
p: 1,
limit: 1000,
}).fetch();
@@ -144,7 +146,14 @@ export default defineComponent({
try {
const { data } = await getEabList({ ca, p: 1, limit: 1000 }).fetch();
emailOptions.value =
data?.map((item) => item.email).filter(Boolean) || [];
data
?.map((item) => ({
label: item.email,
value: `${item.id}`, // 使用 id 作为 value 确保唯一性
id: item.id,
email: item.email,
}))
.filter((item) => item.email) || [];
// 检查是否为编辑模式且有外部传入的邮箱
if (isEdit.value && routeEmail.value) {
@@ -154,15 +163,19 @@ export default defineComponent({
// 非编辑模式:保持原有逻辑
if (!emailOptions.value.length) {
param.value.email = "";
param.value.eabId = "";
} else {
// 如果邮箱数组有内容,自动填充第一个邮箱地址
// 移除 !param.value.email 条件让切换CA时总是更新为第一个选项
if (emailOptions.value[0]) {
param.value.email = emailOptions.value[0].email;
param.value.eabId = emailOptions.value[0].id.toString();
}
}
// 如果邮箱数组有内容且当前邮箱为空,自动填充第一个邮箱地址
if (
emailOptions.value.length > 0 &&
emailOptions.value[0] &&
!param.value.email
) {
param.value.email = emailOptions.value[0];
}
}
if (example.value) {
example.value.restoreValidation();
}
} catch (error) {
console.error("加载邮件选项失败:", error);
@@ -239,17 +252,35 @@ export default defineComponent({
// 创建邮箱下拉选项
const emailDropdownOptions = computed(() => {
return emailOptions.value.map((email) => ({
label: email,
key: email,
return emailOptions.value.map((item) => ({
label: item.email,
key: item.email,
}));
});
// 计算输入框宽度用于下拉菜单
const inputWidth = computed(() => {
if (emailInputRef.value?.$el) {
return emailInputRef.value.$el.offsetWidth;
}
return 0;
});
// 判断是否需要输入框letsencrypt、buypass、zerossl
const shouldUseInputForEmail = computed(() => {
return ["letsencrypt", "buypass", "zerossl"].includes(param.value.ca);
});
// 计算当前选中的邮箱选项的 value用于 NSelect
const currentEmailValue = computed(() => {
if (!param.value.eabId) return null;
// 优先使用 eabId 来查找匹配的选项
const matchedOption = emailOptions.value.find(
(item) => item.id.toString() === param.value.eabId
);
return matchedOption ? matchedOption.value : null;
});
// 表单渲染配置
const config = computed(() => {
// 基本选项
@@ -343,7 +374,20 @@ export default defineComponent({
options={emailDropdownOptions.value}
onSelect={handleSelectEmail}
placement="bottom-start"
style="width: 100%"
menu-props={() => ({
style: {
width: `${inputWidth.value}px`,
maxHeight: "40rem",
overflowY: "auto",
},
})}
node-props={(option: any) => ({
style: {
padding: "8px 12px",
cursor: "pointer",
},
class: "hover:bg-gray-50",
})}
>
<NInput
ref={emailInputRef}
@@ -358,16 +402,26 @@ export default defineComponent({
</NDropdown>
) : (
<NSelect
v-model:value={param.value.email}
options={emailOptions.value.map((email) => ({
label: email,
value: email,
}))}
value={currentEmailValue.value}
options={emailOptions.value}
placeholder={$t("t_2_1748052862259")}
clearable
filterable
loading={isLoadingEmails.value}
class="w-full"
onUpdateValue={(value: string) => {
// 根据选择的 id 找到对应的邮箱地址和 eabId
const selectedOption = emailOptions.value.find(
(item) => item.value === value
);
if (selectedOption) {
param.value.email = selectedOption.email;
param.value.eabId = selectedOption.id.toString();
} else {
param.value.email = value;
param.value.eabId = "";
}
}}
/>
)}
</NFormItem>
@@ -545,6 +599,7 @@ export default defineComponent({
} else {
emailOptions.value = [];
param.value.email = "";
param.value.eabId = "";
showEmailDropdown.value = false;
}
}
@@ -564,14 +619,14 @@ export default defineComponent({
advancedOptions.value = false;
await loadCAOptions();
// 如果当前已经有CA值主动加载对应的邮件选项
if (param.value.ca) {
await loadEmailOptions(param.value.ca);
}
// 如果是编辑模式且有外部传入的邮箱,直接设置邮箱值
if (isEdit.value && routeEmail.value) {
param.value.email = routeEmail.value;
} else {
// 非编辑模式如果当前已经有CA值主动加载对应的邮件选项
if (param.value.ca) {
await loadEmailOptions(param.value.ca);
}
}
// 移除重复调用,让 watch 监听器处理 CA 值变化

View File

@@ -1,4 +1,4 @@
import { defineComponent, ref, computed, watch } from 'vue';
import { defineComponent, ref, computed, watch } from "vue";
import {
NForm,
NFormItem,
@@ -127,7 +127,7 @@ export default defineComponent({
const selectedRootCa = rootCaList.value.find(
(ca) => ca.id.toString() === newRootId
);
if (selectedRootCa) {
if (selectedRootCa && selectedRootCa.algorithm) {
addForm.value.algorithm = selectedRootCa.algorithm;
if (selectedRootCa.algorithm === "ecdsa") {
addForm.value.key_length = "256";
@@ -269,45 +269,43 @@ export default defineComponent({
</div>
</NDivider>
</div>
{showAdvancedConfig.value && (
<div class="space-y-4 mt-4">
<NFormItem label="组织(O)">
<NInput
v-model:value={addForm.value.o}
placeholder="请输入组织名称"
/>
</NFormItem>
<div class="mt-4" v-show={showAdvancedConfig.value}>
<NFormItem label="组织(O)">
<NInput
v-model:value={addForm.value.o}
placeholder="请输入组织名称"
/>
</NFormItem>
<NFormItem label="国家(C)" path="c" required>
<NSelect
v-model:value={addForm.value.c}
options={countryOptions}
placeholder="请选择国家"
/>
</NFormItem>
<NFormItem label="国家(C)" path="c" required>
<NSelect
v-model:value={addForm.value.c}
options={countryOptions}
placeholder="请选择国家"
/>
</NFormItem>
<NFormItem label="组织单位(OU)">
<NInput
v-model:value={addForm.value.ou}
placeholder="请输入组织单位"
/>
</NFormItem>
<NFormItem label="组织单位(OU)">
<NInput
v-model:value={addForm.value.ou}
placeholder="请输入组织单位"
/>
</NFormItem>
<NFormItem label="省份">
<NInput
v-model:value={addForm.value.province}
placeholder="请输入省份"
/>
</NFormItem>
<NFormItem label="省份">
<NInput
v-model:value={addForm.value.province}
placeholder="请输入省份"
/>
</NFormItem>
<NFormItem label="城市">
<NInput
v-model:value={addForm.value.locality}
placeholder="请输入城市"
/>
</NFormItem>
</div>
)}
<NFormItem label="城市">
<NInput
v-model:value={addForm.value.locality}
placeholder="请输入城市"
/>
</NFormItem>
</div>
</div>
<div class="flex justify-end gap-3 mt-6">
<NButton onClick={handleCancel}></NButton>

View File

@@ -251,8 +251,10 @@ export const useController = () => {
if (data.value?.status === true) {
rootCaList.value = data.value.data;
if (createType.value === 'intermediate' && rootCaList.value.length > 0 && rootCaList.value[0]) {
addForm.value.root_id = rootCaList.value[0].id.toString();
}
addForm.value.root_id = rootCaList.value[0].id.toString();
addForm.value.algorithm = rootCaList.value[0].algorithm;
addForm.value.key_length = rootCaList.value[0].key_length.toString();
}
}
} catch (error) {
console.error('获取根证书列表失败:', error);