【修复】申请配置证书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

File diff suppressed because one or more lines are too long

View File

@@ -103,10 +103,9 @@ export default defineComponent({
language="custom-logs"
trim={false}
fontSize={14}
lineHeight={1.5}
class="h-full" // NLog 充满 NSpin
style={{
// height: '500px', // 改为 flex 布局后,由父容器控制高度
lineHeight: '1.5rem',
border: '1px solid var(--n-border-color)',
borderRadius: 'var(--n-border-radius)', // 使用 Naive UI 变量
padding: '10px',

View File

@@ -1,5 +1,11 @@
.flowContainer {
@apply flex relative box-border w-full h-[calc(100vh-19rem)] overflow-x-auto overflow-y-auto p-[1rem] justify-center;
@apply flex relative box-border w-full h-[calc(100vh-19rem)] overflow-hidden p-[1rem] justify-center;
user-select: none; /* 防止拖拽时选中文本 */
cursor: grab; /* 默认鼠标样式 */
}
.flowContainer:active {
cursor: grabbing; /* 拖拽时的鼠标样式 */
}
.flowProcess {
@@ -7,7 +13,7 @@
}
.flowZoom {
@apply flex fixed items-center justify-between h-[4rem] w-[12.5rem] bottom-[4rem] z-[99];
@apply flex fixed items-center justify-between h-[4rem] w-[16rem] bottom-[6rem] z-[99];
}
.flowZoomIcon {

View File

@@ -1,5 +1,5 @@
import { NButton, NIcon, NInput } from 'naive-ui'
import { SaveOutlined, ArrowLeftOutlined } from '@vicons/antd'
import { SaveOutlined, ArrowLeftOutlined, ReloadOutlined } from "@vicons/antd";
import { $t } from '@locales/index'
import SvgIcon from '@components/SvgIcon'
@@ -14,47 +14,188 @@ import type { FlowNode, FlowNodeProps } from './types'
import { useThemeCssVar } from '@baota/naive-ui/theme'
export default defineComponent({
name: 'FlowChart',
props: {
isEdit: {
type: Boolean,
default: false,
},
type: {
type: String as PropType<'quick' | 'advanced'>,
default: 'quick',
},
node: {
type: Object as PropType<FlowNode>,
default: () => ({}),
},
// 任务节点列表
taskComponents: {
type: Object as PropType<Record<string, Component>>,
default: () => ({}),
},
},
setup(props: FlowNodeProps, { slots }) {
const cssVars = useThemeCssVar([
'borderColor',
'dividerColor',
'textColor1',
'textColor2',
'primaryColor',
'primaryColorHover',
'bodyColor',
])
const { flowData, selectedNodeId, flowZoom, resetFlowData } = useStore()
const { initData, handleSaveConfig, handleZoom, goBack } = useController({
type: props?.type,
node: props?.node,
isEdit: props?.isEdit,
})
// 提供任务节点组件映射给后代组件使用
provide('taskComponents', props.taskComponents)
onMounted(initData)
onUnmounted(resetFlowData)
return () => (
name: "FlowChart",
props: {
isEdit: {
type: Boolean,
default: false,
},
type: {
type: String as PropType<"quick" | "advanced">,
default: "quick",
},
node: {
type: Object as PropType<FlowNode>,
default: () => ({}),
},
// 任务节点列表
taskComponents: {
type: Object as PropType<Record<string, Component>>,
default: () => ({}),
},
},
setup(props: FlowNodeProps, { slots }) {
const cssVars = useThemeCssVar([
"borderColor",
"dividerColor",
"textColor1",
"textColor2",
"primaryColor",
"primaryColorHover",
"bodyColor",
]);
const { flowData, selectedNodeId, flowZoom, resetFlowData, setZoomValue } =
useStore();
const { initData, handleSaveConfig, handleZoom, goBack } = useController({
type: props?.type,
node: props?.node,
isEdit: props?.isEdit,
});
// 拖拽状态管理
const dragState = reactive({
isDragging: false,
startX: 0,
startY: 0,
offsetX: 0,
offsetY: 0,
});
// 画布容器引用
const canvasRef = ref<HTMLElement | null>(null);
// 画布样式通过transform实现拖拽
const canvasStyle = computed(() => ({
transform: `translate(${dragState.offsetX}px, ${dragState.offsetY}px)`,
}));
// 鼠标按下事件
const handleMouseDown = (e: MouseEvent) => {
// 只有左键点击才触发拖拽
if (e.button !== 0) return;
dragState.isDragging = true;
dragState.startX = e.clientX;
dragState.startY = e.clientY;
// 添加鼠标样式反馈
document.body.style.cursor = "grabbing";
};
// 鼠标移动事件
const handleMouseMove = (e: MouseEvent) => {
if (!dragState.isDragging || !isComponentMounted.value) return;
try {
// 计算位移差
const deltaX = e.clientX - dragState.startX;
const deltaY = e.clientY - dragState.startY;
// 更新偏移量
dragState.offsetX += deltaX;
dragState.offsetY += deltaY;
// 更新起始位置(用于连续计算)
dragState.startX = e.clientX;
dragState.startY = e.clientY;
} catch (error) {
console.warn("拖拽移动处理出错:", error);
}
};
// 鼠标抬起事件
const handleMouseUp = () => {
if (dragState.isDragging) {
dragState.isDragging = false;
document.body.style.cursor = ""; // 恢复鼠标样式
}
};
// 重置缩放和位置
const handleReset = () => {
try {
// 重置缩放为100%
setZoomValue(100);
// 重置拖拽位置
dragState.offsetX = 0;
dragState.offsetY = 0;
} catch (error) {
console.warn("重置处理出错:", error);
}
};
// 滚轮缩放事件(带节流优化)
let wheelTimeout: number | null = null;
const isComponentMounted = ref(true);
const handleWheel = (e: WheelEvent) => {
// 阻止默认滚动行为
e.preventDefault();
// 如果组件已卸载,不处理事件
if (!isComponentMounted.value) {
return;
}
// 节流处理,避免频繁触发
if (wheelTimeout) {
clearTimeout(wheelTimeout);
}
wheelTimeout = window.setTimeout(() => {
// 再次检查组件是否仍然挂载
if (!isComponentMounted.value) {
return;
}
try {
const delta = e.deltaY > 0 ? -10 : 10; // 向下滚动缩小,向上滚动放大
const newZoom = Math.max(50, Math.min(300, flowZoom.value + delta));
if (newZoom !== flowZoom.value) {
setZoomValue(newZoom); // 直接设置缩放值
}
} catch (error) {
console.warn("滚轮缩放处理出错:", error);
}
}, 16);
};
// 提供任务节点组件映射给后代组件使用
provide("taskComponents", props.taskComponents);
onMounted(() => {
initData();
// 绑定全局事件
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
// 绑定滚轮事件到画布容器
if (canvasRef.value) {
canvasRef.value.addEventListener("wheel", handleWheel, {
passive: false,
});
}
});
onUnmounted(() => {
// 标记组件已卸载
isComponentMounted.value = false;
resetFlowData();
// 解绑事件,避免内存泄漏
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
// 解绑滚轮事件
if (canvasRef.value) {
canvasRef.value.removeEventListener("wheel", handleWheel);
}
// 清理定时器
if (wheelTimeout) {
clearTimeout(wheelTimeout);
wheelTimeout = null;
}
});
return () => (
<div class="flex flex-col w-full h-full" style={cssVars.value}>
<div class="w-full h-[6rem] px-[2rem] mb-[2rem] rounded-lg flex items-center gap-2 justify-between">
<div class="flex items-center">
@@ -85,13 +226,25 @@ export default defineComponent({
</NButton>
</div>
</div>
<div class={styles.flowContainer}>
<div
class={styles.flowContainer}
ref={canvasRef}
onMousedown={handleMouseDown}
onMouseleave={handleMouseUp}
>
{/* 左侧流程容器 */}
<div class="flex min-w-0">
{/* 流程容器*/}
<div
class={styles.flowProcess}
style={{ transform: `scale(${flowZoom.value / 100})` }}
style={{
transform: `scale(${flowZoom.value / 100}) ${
canvasStyle.value.transform
}`,
transition: dragState.isDragging
? "none"
: "transform 0.05s ease-out",
}}
>
{/* 渲染流程节点 */}
<NodeWrap node={flowData.value.childNode} />
@@ -117,10 +270,19 @@ export default defineComponent({
color="#5a5e66"
/>
</div>
<div
class={styles.flowZoomIcon}
onClick={handleReset}
title="重置视图"
>
<NIcon size="16" color="#5a5e66">
<ReloadOutlined />
</NIcon>
</div>
</div>
{/* 保留原有插槽 */}
{slots.default?.()}
</div>
);
},
})
},
});

View File

@@ -20,29 +20,29 @@ import { $t } from '@locales/index'
* 用于管理流程图的状态、缩放等数据
*/
export const useFlowStore = defineStore('flow-store', () => {
const flowData = ref<FlowNode>({
id: '',
name: '',
childNode: {
id: 'start-1',
name: '开始',
type: 'start',
config: {
exec_type: 'manual',
},
childNode: null,
},
}) // 流程图数据
const flowZoom = ref(100) // 流程图缩放比例
const advancedOptions = ref(false) // 高级选项
const addNodeSelectList = ref<NodeSelect[]>([]) // 添加节点选项列表
const excludeNodeSelectList = ref<NodeNum[]>([]) // 排除的节点选项列表
const addNodeBtnRef = ref<HTMLElement | null>(null) // 添加节点按钮
const addNodeSelectRef = ref<HTMLElement | null>(null) // 添加节点选择框
const addNodeSelectPostion = ref<number | null>(null) // 添加节点选择框位置
const selectedNodeId = ref<string | null>(null) // 当前选中的节点ID
const isRefreshNode = ref<string | null>(null) // 是否刷新节点
const startNodeSavedByUser = ref<boolean>(false); // 开始节点是否已被用户手动保存过
const flowData = ref<FlowNode>({
id: "",
name: "",
childNode: {
id: "start-1",
name: "开始",
type: "start",
config: {
exec_type: "manual",
},
childNode: null,
},
}); // 流程图数据
const flowZoom = ref(100); // 流程图缩放比例
const advancedOptions = ref(false); // 高级选项
const addNodeSelectList = ref<NodeSelect[]>([]); // 添加节点选项列表
const excludeNodeSelectList = ref<NodeNum[]>([]); // 排除的节点选项列表
const addNodeBtnRef = ref<HTMLElement | null>(null); // 添加节点按钮
const addNodeSelectRef = ref<HTMLElement | null>(null); // 添加节点选择框
const addNodeSelectPostion = ref<number | null>(null); // 添加节点选择框位置
const selectedNodeId = ref<string | null>(null); // 当前选中的节点ID
const isRefreshNode = ref<string | null>(null); // 是否刷新节点
const startNodeSavedByUser = ref<boolean>(false); // 开始节点是否已被用户手动保存过
// 计算添加节点选项列表,排除的节点选项列表
const nodeSelectList = computed(() => {
@@ -606,16 +606,30 @@ export const useFlowStore = defineStore('flow-store', () => {
/**
* 设置流程图缩放比例
* 控制流程图的显示大小
* @param {number} type - 缩放类型1 表示缩小2 表示放大
* @param {number} type - 缩放类型1 表示缩小2 表示放大或者直接传入缩放值0.5-3.0
*/
const setflowZoom = (type: number) => {
if (type === 1 && flowZoom.value > 50) {
// 如果传入的是小数0.5-3.0),直接设置缩放值
if (type < 1) {
const zoomValue = Math.round(type * 100);
flowZoom.value = Math.max(50, Math.min(300, zoomValue));
} else if (type === 1 && flowZoom.value > 50) {
// 缩小
flowZoom.value -= 10;
} else if (type === 2 && flowZoom.value < 300) {
// 放大
flowZoom.value += 10;
}
};
/**
* 直接设置缩放值(用于滚轮缩放)
* @param {number} zoomValue - 缩放值50-300
*/
const setZoomValue = (zoomValue: number) => {
flowZoom.value = Math.max(50, Math.min(300, zoomValue));
};
/**
* 设置开始节点已被用户保存的状态
* @param {boolean} saved - 是否已被保存
@@ -632,7 +646,7 @@ export const useFlowStore = defineStore('flow-store', () => {
startNodeSavedByUser.value = false;
};
return {
return {
// 数据
flowData, // 流程图数据
flowZoom, // 流程图缩放比例
@@ -649,6 +663,7 @@ export const useFlowStore = defineStore('flow-store', () => {
getResultData, // 获取流程图数据
updateFlowData, // 更新流程图数据
setflowZoom, // 设置流程图缩放比例
setZoomValue, // 直接设置缩放值(用于滚轮缩放)
setStartNodeSavedByUser, // 设置开始节点已被用户保存的状态
resetStartNodeSavedState, // 重置开始节点保存状态

View File

@@ -271,6 +271,13 @@ export const ApiProjectConfig: Record<string, ApiProjectType> = {
hostRelated: { default: { name: "Spaceship" } },
sort: 32,
},
btdomain: {
name: "BTDomain",
icon: "btdomain",
type: ["dns"],
hostRelated: { default: { name: "BTDomain" } },
sort: 33,
},
plugin: {
name: "插件",
icon: "plugin",

View File

@@ -65,6 +65,7 @@ export interface AddAccessParams<
| ConstellixAccessConfig
| WebhookAccessConfig
| SpaceshipAccessConfig
| BTDomainAccessConfig
> {
name: string;
type: string;
@@ -102,6 +103,7 @@ export interface UpdateAccessParams<
| ConstellixAccessConfig
| WebhookAccessConfig
| SpaceshipAccessConfig
| BTDomainAccessConfig
> extends AddAccessParams<T> {
id: string;
}
@@ -322,6 +324,12 @@ export interface SpaceshipAccessConfig {
api_secret: string;
}
export interface BTDomainAccessConfig {
access_key: string;
secret_key: string;
account_id: string;
}
/** 删除授权请求参数 */
export interface DeleteAccessParams {
id: string

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);