【新增】部署类型七牛云oss、七牛云cdn、百度cdn、腾讯waf、腾讯edgeone、阿里云waf

【新增】解析类型godaddy
【新增】自定义CA授权管理
【调整】优化部署流程,减少代码冗余,提升类型添加效率
This commit is contained in:
chudong
2025-05-23 16:58:34 +08:00
parent 71de397e11
commit e5634d4992
263 changed files with 18348 additions and 14253 deletions

View File

@@ -1,47 +1,20 @@
import { defineComponent, PropType, VNode } from 'vue'
import { NButton, NFormItemGi, NGrid, NSelect, NText, NSpin, NFlex } from 'naive-ui'
import { useError } from '@baota/hooks/error'
// 类型导入
import type { DnsProviderSelectProps, DnsProviderOption, DnsProviderType, DnsProviderSelectEmits } from './types'
// 绝对内部导入 - Controller
import { useDnsProviderSelectController } from './useController'
// 绝对内部导入 - Components
import SvgIcon from '@components/SvgIcon'
// 绝对内部导入 - Utilities
import { $t } from '@locales/index'
import { useStore } from '@layout/useStore'
import SvgIcon from '@components/svgIcon'
interface DnsProviderOption {
label: string
value: string
type: string
}
type DnsProviderType =
| 'aliyun'
| 'tencentcloud'
| 'baidu'
| 'huaweicloud'
| 'cloudflare'
| 'dns'
| 'btpanel'
| '1panel'
| 'ssh'
| ''
interface DnsProviderSelectProps {
// 表单类型,用于获取不同的下拉列表
type: DnsProviderType
// 表单,用于绑定表单的值
path: string
// 表单的值
value: string
// 表单的值类型
valueType: 'value' | 'type'
// 是否为添加模式
isAddMode: boolean
// 是否禁用
disabled?: boolean
// 自定义样式
customClass?: string
}
/**
* @component DnsProviderSelect
* @description DNS提供商选择组件支持多种DNS提供商类型并提供刷新和跳转到授权页面的功能
* @description DNS提供商选择组件支持多种DNS提供商类型并提供刷新和跳转到授权页面的功能
* 遵循 MVC/MV* 模式,将业务逻辑、状态管理与视图渲染分离。
*
* @example 基础使用
* <DnsProviderSelect
@@ -52,129 +25,61 @@ interface DnsProviderSelectProps {
* :isAddMode="true"
* />
*
* @example 仅显示选择器(无添加按钮)
* <DnsProviderSelect
* type="aliyun"
* path="form.dnsProvider"
* v-model:value="formValue.dnsProvider"
* valueType="value"
* :isAddMode="false"
* />
* @property {DnsProviderType} type - DNS提供商类型。
* @property {string} path - 表单路径,用于表单校验。
* @property {string} value - 当前选中的值 (通过 v-model:value 绑定)。
* @property {'value' | 'type'} valueType - 表单值的类型,决定 emit 'update:value' 时传递的是选项的 'value' 还是 'type'。
* @property {boolean} isAddMode - 是否为添加模式,显示添加和刷新按钮。
* @property {boolean} [disabled=false] - 是否禁用。
* @property {string} [customClass] - 自定义CSS类名。
*
* @example 禁用状态
* <DnsProviderSelect
* type="dns"
* path="form.dnsProvider"
* v-model:value="formValue.dnsProvider"
* valueType="value"
* :isAddMode="true"
* :disabled="true"
* />
*
* @property {string} type - DNS提供商类型支持 'btpanel'|'aliyun'|'ssh'|'tencentcloud'|'1panel'|'dns'|''
* @property {string} path - 表单路径,用于绑定表单的值
* @property {string} value - 表单的值通过v-model:value绑定
* @property {string} valueType - 表单的值类型,可选值为 'value'(默认) 或 'type'
* @property {boolean} isAddMode - 是否显示添加和刷新按钮默认为true
* @property {boolean} disabled - 是否禁用选择器默认为false
* @property {string} customClass - 自定义CSS类名
*
* @emits update:value - 当选择的DNS提供商变更时触发
* @emits update:value - (value: DnsProviderOption) 当选择的DNS提供商变更时触发传递整个选项对象。
*/
export default defineComponent({
export default defineComponent<DnsProviderSelectProps>({
name: 'DnsProviderSelect',
props: {
// 表单类型,用于获取不同的下拉列表
type: {
type: String as PropType<DnsProviderType>,
default: '',
required: true,
},
// 表单,用于绑定表单的值
path: {
type: String,
default: '',
required: true,
},
// 表单的值
value: {
type: String,
default: '',
required: true,
},
// 表单的值类型
valueType: {
type: String,
type: String as PropType<'value' | 'type'>,
default: 'value',
},
// 是否为添加模式
isAddMode: {
type: Boolean,
default: true,
},
// 是否禁用
disabled: {
type: Boolean,
default: false,
},
// 自定义样式
customClass: {
type: String,
default: '',
},
},
emits: ['update:value'],
setup(props: DnsProviderSelectProps, { emit }) {
// 错误处理
const { handleError } = useError()
// 获取DNS提供商
const { fetchDnsProvider, resetDnsProvider, dnsProvider } = useStore()
// 表单的值
const param = ref<DnsProviderOption>({
label: '',
value: '',
type: '',
})
const dnsProviderRef = ref<DnsProviderOption[]>([])
// 加载状态
const isLoading = ref(false)
// 错误信息
const errorMessage = ref('')
emits: ['update:value'] as unknown as DnsProviderSelectEmits, // 类型断言以匹配严格的 emits 定义
console.log(props.type)
/**
* @description 跳转到DNS提供商授权页面
*/
const goToAddDnsProvider = () => {
window.open('/auth-api-manage', '_blank')
}
/**
* 渲染单选标签
* @param option - 选项
* @returns 渲染后的VNode
*/
const renderSingleSelectTag = ({ option }: Record<string, any>): VNode => {
return (
<div class="flex items-center">
{option.label ? (
renderLabel(option)
) : (
<NText class="text-[#aaa]">
{props.type === 'dns' ? $t('t_0_1747019621052', []) : $t('t_0_1746858920894')}
</NText>
)}
</div>
)
}
setup(props: DnsProviderSelectProps, { emit }: { emit: DnsProviderSelectEmits }) {
const controller = useDnsProviderSelectController(props, emit)
/**
* 渲染标签
* @param option - 选项
* @returns 渲染后的VNode
*/
const renderLabel = (option: { type: string; label: string }): VNode => {
const renderLabel = (option: DnsProviderOption): VNode => {
return (
<NFlex>
<NFlex align="center">
<SvgIcon icon={`resources-${option.type}`} size="2rem" />
<NText>{option.label}</NText>
</NFlex>
@@ -182,97 +87,26 @@ export default defineComponent({
}
/**
* @description 更新类型
* 渲染单选标签
* @param option - 选项 (Record<string, any> 来自 naive-ui 的类型)
* @returns 渲染后的VNode
*/
const handleUpdateType = async () => {
const items = dnsProvider.value.find((item) => {
return item.value === param.value.value
})
if (items) {
param.value = {
label: items.label,
value: items.value,
type: items.type,
}
}
if (dnsProvider.value.length > 0 && param.value.value === '') {
param.value = {
label: dnsProvider.value[0]?.label || '',
value: dnsProvider.value[0]?.value || '',
type: dnsProvider.value[0]?.type || '',
}
}
emit('update:value', param.value)
const renderSingleSelectTag = ({ option }: { option: DnsProviderOption }): VNode => {
return (
<div class="flex items-center">
{option.label ? (
renderLabel(option)
) : (
<NText class="text-[#aaa]">
{props.type === 'dns' ? $t('t_0_1747019621052') : $t('t_0_1746858920894')}
</NText>
)}
</div>
)
}
/**
* 更新表单的值
* @param value - 表单的值
*/
const handleUpdateValue = (value: string) => {
param.value.value = value
handleUpdateType()
}
/**
* @description 加载DNS提供商选项
*/
const loadDnsProviders = async (type: DnsProviderType = '') => {
isLoading.value = true
errorMessage.value = ''
try {
await fetchDnsProvider(type)
} catch (error) {
errorMessage.value = typeof error === 'string' ? error : $t('t_0_1746760933542')
handleError(error)
} finally {
isLoading.value = false
}
}
/**
* @description 搜索过滤函数
* @param pattern - 搜索文本
* @param option - 选项
*/
const handleFilter = (pattern: string, option: any) => {
return option.label.toLowerCase().includes(pattern.toLowerCase())
}
// 监听消息通知提供商
watch(
() => dnsProvider.value,
(newVal) => {
dnsProviderRef.value =
newVal.map((item) => ({
label: item.label,
value: props.valueType === 'value' ? item.value : item.type,
type: props.valueType === 'value' ? item.type : item.value,
})) || []
handleUpdateType()
},
)
// 监听父组件的值
watch(
() => props.value,
() => {
handleUpdateValue(props.value)
},
{ immediate: true },
)
onMounted(() => {
loadDnsProviders(props.type)
})
onUnmounted(() => {
resetDnsProvider()
})
return () => (
<NSpin show={isLoading.value}>
<NSpin show={controller.isLoading.value}>
<NGrid cols={24} class={props.customClass}>
<NFormItemGi
span={props.isAddMode ? 13 : 24}
@@ -281,20 +115,23 @@ export default defineComponent({
>
<NSelect
class="flex-1 w-full"
options={dnsProviderRef.value}
options={controller.dnsProviderRef.value}
renderLabel={renderLabel}
renderTag={renderSingleSelectTag}
renderTag={({ option }: { option: any }) =>
renderSingleSelectTag({ option: option as DnsProviderOption })
}
filterable
filter={handleFilter}
filter={(pattern: string, option: any) => controller.handleFilter(pattern, option as DnsProviderOption)}
placeholder={props.type === 'dns' ? $t('t_3_1745490735059') : $t('t_0_1746858920894')}
v-model:value={param.value.value}
onUpdateValue={handleUpdateValue}
value={controller.param.value.value} // 使用 controller 中的 param.value.value
onUpdateValue={controller.handleUpdateValue}
disabled={props.disabled}
v-slots={{
empty: () => {
return (
<span class="text-[1.4rem]">
{errorMessage.value || (props.type === 'dns' ? $t('t_1_1746858922914') : $t('t_2_1746858923964'))}
{controller.errorMessage.value ||
(props.type === 'dns' ? $t('t_1_1746858922914') : $t('t_2_1746858923964'))}
</span>
)
},
@@ -303,10 +140,14 @@ export default defineComponent({
</NFormItemGi>
{props.isAddMode && (
<NFormItemGi span={11}>
<NButton class="mx-[8px]" onClick={goToAddDnsProvider} disabled={props.disabled}>
<NButton class="mx-[8px]" onClick={controller.goToAddDnsProvider} disabled={props.disabled}>
{props.type === 'dns' ? $t('t_1_1746004861166') : $t('t_3_1746858920060')}
</NButton>
<NButton onClick={() => loadDnsProviders(props.type)} loading={isLoading.value} disabled={props.disabled}>
<NButton
onClick={() => controller.loadDnsProviders(props.type)}
loading={controller.isLoading.value}
disabled={props.disabled}
>
{$t('t_0_1746497662220')}
</NButton>
</NFormItemGi>

View File

@@ -0,0 +1,95 @@
// 类型导入 (如果需要)
// import type { SomeOtherType } from '@/types/someModule';
/**
* @interface DnsProviderOption
* @description DNS提供商选项的结构
*/
export interface DnsProviderOption {
label: string
value: string
type: string
}
/**
* @type DnsProviderType
* @description DNS提供商的具体类型
*/
export type DnsProviderType =
| 'aliyun'
| 'tencentcloud'
| 'baidu'
| 'qiniu'
| 'huaweicloud'
| 'cloudflare'
| 'dns'
| 'btpanel'
| '1panel'
| 'ssh'
| ''
/**
* @interface DnsProviderSelectProps
* @description DnsProviderSelect 组件的 Props 定义
*/
export interface DnsProviderSelectProps {
/**
* @property type
* @description 表单类型,用于获取不同的下拉列表
*/
type: DnsProviderType
/**
* @property path
* @description 表单路径,用于 naive-ui 表单校验
*/
path: string
/**
* @property value
* @description 当前选中的值
*/
value: string
/**
* @property valueType
* @description 表单值的类型,决定 emit 出去的是选项的 value 还是 type
*/
valueType: 'value' | 'type'
/**
* @property isAddMode
* @description 是否为添加模式,控制是否显示"添加"和"刷新"按钮
*/
isAddMode: boolean
/**
* @property disabled
* @description 是否禁用选择器
* @default false
*/
disabled?: boolean
/**
* @property customClass
* @description 自定义CSS类名应用于 NGrid 组件
*/
customClass?: string
}
/**
* @interface DnsProviderSelectEmits
* @description DnsProviderSelect 组件的 Emits 定义
*/
export interface DnsProviderSelectEmits {
(e: 'update:value', value: DnsProviderOption): void
}
/**
* @interface DnsProviderControllerExposes
* @description useDnsProviderSelectController 返回对象的类型接口
*/
export interface DnsProviderControllerExposes {
param: import('vue').Ref<DnsProviderOption>
dnsProviderRef: import('vue').Ref<DnsProviderOption[]>
isLoading: import('vue').Ref<boolean>
errorMessage: import('vue').Ref<string>
goToAddDnsProvider: () => void
handleUpdateValue: (value: string) => void
loadDnsProviders: (type?: DnsProviderType) => Promise<void>
handleFilter: (pattern: string, option: DnsProviderOption) => boolean
}

View File

@@ -0,0 +1,180 @@
import { ref, watch, onMounted, onUnmounted } from 'vue';
import type { DnsProviderSelectProps, DnsProviderOption, DnsProviderType, DnsProviderSelectEmits } from './types';
// 绝对内部导入 - Stores
import { useStore } from '@layout/useStore';
// 绝对内部导入 - Hooks
import { useError } from '@baota/hooks/error';
// 绝对内部导入 - Utilities
import { $t } from '@locales/index';
/**
* @function useDnsProviderSelectController
* @description DnsProviderSelect 组件的控制器逻辑
* @param props - 组件的 props
* @param emit - 组件的 emit 函数
* @returns {DnsProviderControllerExposes} 控制器暴露给视图的数据和方法
*/
export function useDnsProviderSelectController(
props: DnsProviderSelectProps,
emit: DnsProviderSelectEmits,
) {
const { handleError } = useError();
const { fetchDnsProvider, resetDnsProvider, dnsProvider } = useStore();
const param = ref<DnsProviderOption>({
label: '',
value: '',
type: '',
});
const dnsProviderRef = ref<DnsProviderOption[]>([]);
const isLoading = ref(false);
const errorMessage = ref('');
/**
* @function goToAddDnsProvider
* @description 跳转到DNS提供商授权页面
*/
const goToAddDnsProvider = () => {
window.open('/auth-api-manage', '_blank');
};
/**
* @function handleUpdateType
* @description 根据当前 param.value 更新 param 对象的 label 和 type并 emit 更新事件
*/
const handleUpdateType = () => {
const selectedProvider = dnsProvider.value.find((item) => {
// 根据 props.valueType 决定是比较 item.value 还是 item.type
const valueToCompare = props.valueType === 'value' ? item.value : item.type;
return valueToCompare === param.value.value;
});
if (selectedProvider) {
param.value = {
label: selectedProvider.label,
value: props.valueType === 'value' ? selectedProvider.value : selectedProvider.type,
type: props.valueType === 'value' ? selectedProvider.type : selectedProvider.value,
};
} else if (dnsProvider.value.length > 0 && param.value.value === '') {
// 如果 param.value 为空(例如初始状态或清空后),且 dnsProvider 列表不为空,则默认选中第一个
param.value = {
label: dnsProvider.value[0]?.label || '',
value: props.valueType === 'value' ? dnsProvider.value[0]?.value || '' : dnsProvider.value[0]?.type || '',
type: props.valueType === 'value' ? dnsProvider.value[0]?.type || '' : dnsProvider.value[0]?.value || '',
};
}
emit('update:value', { ...param.value });
};
/**
* @function handleUpdateValue
* @description 更新 param.value 并触发类型更新
* @param value - 新的选中值
*/
const handleUpdateValue = (value: string) => {
param.value.value = value;
handleUpdateType();
};
/**
* @function loadDnsProviders
* @description 加载DNS提供商选项
* @param type - DNS提供商类型默认为 props.type
*/
const loadDnsProviders = async (type: DnsProviderType = props.type) => {
isLoading.value = true;
errorMessage.value = '';
try {
await fetchDnsProvider(type);
// 数据加载后,如果 props.value 有值,尝试根据 props.value 初始化 param
// 否则 handleUpdateType 会尝试选择第一个或保持空
if (props.value) {
handleUpdateValue(props.value);
} else {
handleUpdateType(); // 确保在 dnsProvider 更新后param 也得到相应更新
}
} catch (error) {
errorMessage.value = typeof error === 'string' ? error : $t('t_0_1746760933542'); // '获取DNS提供商列表失败'
handleError(error);
} finally {
isLoading.value = false;
}
};
/**
* @function handleFilter
* @description NSelect 组件的搜索过滤函数
* @param pattern - 搜索文本
* @param option - 当前选项
* @returns {boolean} 是否匹配
*/
const handleFilter = (pattern: string, option: DnsProviderOption): boolean => {
return option.label.toLowerCase().includes(pattern.toLowerCase());
};
watch(
() => dnsProvider.value,
(newVal) => {
dnsProviderRef.value =
newVal.map((item) => ({
label: item.label,
value: props.valueType === 'value' ? item.value : item.type,
type: props.valueType === 'value' ? item.type : item.value, // 确保 type 也被正确映射
})) || [];
// 当 dnsProvider 列表更新后,重新评估 param 的值
// 如果当前 param.value 对应的项仍然存在,则更新 param 的 label 和 type
// 如果不存在(例如,列表刷新后原来的项没了),则尝试根据 props.value (如果存在) 或列表第一项来设定
const currentParamExists = dnsProviderRef.value.some(opt => opt.value === param.value.value);
if (currentParamExists) {
handleUpdateType();
} else if (props.value && dnsProviderRef.value.some(opt => opt.value === props.value)) {
handleUpdateValue(props.value);
} else {
// 如果 props.value 也不在新的列表里,或者 props.value 为空,则默认选择第一个或清空
param.value.value = dnsProviderRef.value?.[0]?.value || '';
handleUpdateType();
}
},
{ deep: true }, // 监听 dnsProvider 数组内部变化
);
watch(
() => props.value,
(newValue) => {
// 仅当外部 props.value 与内部 param.value.value 不一致时才更新
// 避免因子组件 emit('update:value') 导致父组件 props.value 更新,从而再次触发此 watch 造成的循环
if (newValue !== param.value.value) {
handleUpdateValue(newValue);
}
},
{ immediate: true },
);
watch(
() => props.type,
(newType) => {
loadDnsProviders(newType);
}
);
onMounted(() => {
loadDnsProviders(props.type);
});
onUnmounted(() => {
resetDnsProvider();
});
return {
param,
dnsProviderRef,
isLoading,
errorMessage,
goToAddDnsProvider,
handleUpdateValue,
loadDnsProviders,
handleFilter,
};
}