@@ -1,4 +1,17 @@
import { NButton , NCard , NStep , NSteps , NText , NTooltip } from 'naive-ui'
import {
NButton ,
NCard ,
NStep ,
NSteps ,
NText ,
NTooltip ,
NTabs ,
NTabPane ,
NInput ,
NDivider ,
NFormItem ,
NSwitch ,
} from 'naive-ui'
import { useForm , useFormHooks , useModalClose , useModalOptions , useMessage } from '@baota/naive-ui/hooks'
import { useThemeCssVar } from '@baota/naive-ui/theme'
import { useError } from '@baota/hooks/error'
@@ -7,6 +20,7 @@ import { DeployNodeConfig, DeployNodeInputsConfig } from '@components/flowChart/
import { $t } from '@locales/index'
import SvgIcon from '@components/svgIcon'
import DnsProviderSelect from '@/components/dnsProviderSelect'
import SearchOutlined from '@vicons/antd/es/SearchOutlined'
import styles from './index.module.css'
import verifyRules from './verify'
@@ -30,6 +44,7 @@ export default defineComponent({
fromNodeId : '' ,
name : '' ,
} ,
skip : 1 ,
} ,
} ) ,
} ,
@@ -51,47 +66,75 @@ export default defineComponent({
// 部署类型选项
const deployTypeOptions = [
{ label : $t ( 't_5 _1744958839222 ' ) , value : 'ssh' } ,
{ label : $t ( 't_10 _1745735765165 ' ) , value : 'btpanel ' } ,
{ label : $t ( 't_11 _1745735766456 ' ) , value : 'btpanel-site ' } ,
{ label : $t ( 't_12 _1745735765571 ' ) , value : '1 panel' } ,
{ label : $t ( 't_13 _1745735766084 ' ) , value : '1panel-site ' } ,
{ label : $t ( 't_14 _174573576612 1' ) , value : 'tencentcloud-cdn ' } ,
{ label : $t ( 't_15 _1745735768976 ' ) , value : 'tencentcloud-cos ' } ,
{ label : $t ( 't_16 _17457357667 12' ) , value : 'aliyun-cdn ' } ,
{ label : $t ( 't_2 _1746697487164 ' ) , value : 'aliyun-oss ' } ,
{ label : $t ( 't_6 _1747271296994 ' ) , value : 'localhost' , category : 'host' , icon : 'ssh' } ,
{ label : $t ( 't_5 _1744958839222 ' ) , value : 'ssh' , category : 'host' , icon : 'ssh ' } ,
{ label : $t ( 't_10 _1745735765165 ' ) , value : 'btpanel' , category : 'btpanel' , icon : 'btpanel ' } ,
{ label : $t ( 't_11 _1745735766456 ' ) , value : 'btpanel-site' , category : 'btpanel' , icon : 'bt panel' } ,
{ label : $t ( 't_0 _1747215751189 ' ) , value : 'btwaf-site' , category : 'btpanel' , icon : 'btpanel ' } ,
{ label : $t ( 't_12 _174573576557 1' ) , value : '1panel' , category : '1panel' , icon : '1panel ' } ,
{ label : $t ( 't_13 _1745735766084 ' ) , value : '1panel-site' , category : '1panel' , icon : '1panel ' } ,
{ label : $t ( 't_14 _1745735766121 ' ) , value : 'tencentcloud-cdn' , category : 'tencentcloud' , icon : 'tencentcloud ' } ,
{ label : $t ( 't_15 _1745735768976 ' ) , value : 'tencentcloud-cos' , category : 'tencentcloud' , icon : 'tencentcloud ' } ,
{ label : $t ( 't_16_1745735766712' ) , value : 'aliyun-cdn' , category : 'aliyun' , icon : 'aliyun' } ,
{ label : $t ( 't_2_1746697487164' ) , value : 'aliyun-oss' , category : 'aliyun' , icon : 'aliyun' } ,
]
const certOptions = ref < { label : string ; value : string } [ ] > ( [ ] ) // 证书选项
const current = ref ( 1 ) // 当前步骤
const next = ref ( true ) // 是否是下一步
const currentStatus = ref < StepStatus > ( 'process' ) // 当前步骤状态
const currentTab = ref ( 'all' ) // 当前选中的tab
const searchKeyword = ref ( '' ) // 搜索关键字
const param = ref ( deepClone ( props . node . config ) ) // 表单参数
const localProvider = ref ( [ { label : $t ( '本机部署' ) , value : 'localhost' } ] ) // 本地提供商
const provider = computed ( ( ) = > {
return param . value . provider
? $t ( 't_4_1746858917773' ) + ': ' + deployTypeOptions . find ( ( item ) = > item . value === param . value . provider ) ? . label
: $t ( 't_19_1745735766810' )
} )
// 过滤后的部署类型选项
const filteredDeployTypes = computed ( ( ) = > {
let filtered = deployTypeOptions
// 根据标签过滤
if ( currentTab . value !== 'all' ) {
filtered = filtered . filter ( ( item ) = > item . category === currentTab . value )
}
// 根据搜索关键词过滤
if ( searchKeyword . value ) {
const keyword = searchKeyword . value . toLowerCase ( )
filtered = filtered . filter (
( item ) = > item . label . toLowerCase ( ) . includes ( keyword ) || item . value . toLowerCase ( ) . includes ( keyword ) ,
)
}
return filtered
} )
// 表单配置
const formConfig = computed ( ( ) = > {
const config = [ ]
config . push (
. . . [
{
type : 'custom' as const ,
render : ( ) = > {
return (
< DnsProviderSelect
type = { param . value . p rovider}
path = " provider_id"
value = { param . value . provider_id}
onUpdate : value = { ( val : { value : number ; type : string } ) = > {
param . value . provider_id = val . value
} }
/ >
)
} ,
} ,
param . value . provider !== 'localhost'
? {
type : 'custom' as const ,
render : ( ) = > {
return (
< DnsP roviderSelect
type = { param . value . provider}
path = " provider_id"
value = { param . value . provider_id }
onUpdate : value = { ( val : { value : number ; type : string } ) = > {
param . value . provider_id = val . value
} }
/ >
)
} ,
}
: useFormSelect ( $t ( '主机提供商' ) , 'provider' , localProvider . value , { disabled : true } ) ,
] ,
useFormSelect ( $t ( 't_1_1745748290291' ) , 'inputs.fromNodeId' , certOptions . value , {
onUpdateValue : ( val , option : { label : string ; value : string } ) = > {
@@ -101,36 +144,38 @@ export default defineComponent({
} ) ,
)
switch ( param . value . provider ) {
case 'localhost' :
case 'ssh' :
config . push (
. . . [
useFormInput ( '证书文件路径( 仅支持PEM格式) ' , 'certPath' , {
useFormInput ( $t ( '证书文件路径( 仅支持PEM格式) ' ) , 'certPath' , {
placeholder : $t ( 't_30_1746667591892' ) ,
onInput : ( val : string ) = > ( param . value . certPath = val . trim ( ) ) ,
} ) ,
useFormInput ( '私钥文件路径' , 'keyPath' , {
useFormInput ( $t ( '私钥文件路径' ) , 'keyPath' , {
placeholder : $t ( 't_31_1746667593074' ) ,
onInput : ( val : string ) = > ( param . value . keyPath = val . trim ( ) ) ,
} ) ,
useFormTextarea (
'前置命令' ,
$t ( '前置命令(可选)' ) ,
'beforeCmd' ,
{ placeholder : $t ( 't_21_1745735769154' ) } ,
{ placeholder : $t ( 't_21_1745735769154' ) , rows : 2 } ,
{ showRequireMark : false } ,
) ,
useFormTextarea (
'后置命令' ,
$t ( '后置命令(可选)' ) ,
'afterCmd' ,
{ placeholder : $t ( 't_22_1745735767366' ) } ,
{ placeholder : $t ( 't_22_1745735767366' ) , rows : 2 } ,
{ showRequireMark : false } ,
) ,
] ,
)
break
case 'btwaf-site' :
case 'btpanel-site' :
config . push (
. . . [
useFormInput ( '站点名称' , 'siteName' , {
useFormInput ( $t ( '站点名称' ) , 'siteName' , {
placeholder : $t ( 't_23_1745735766455' ) ,
onInput : ( val : string ) = > ( param . value . siteName = val . trim ( ) ) ,
} ) ,
@@ -140,7 +185,7 @@ export default defineComponent({
case '1panel-site' :
config . push (
. . . [
useFormInput ( '站点ID' , 'site_id' , {
useFormInput ( $t ( '站点ID' ) , 'site_id' , {
placeholder : $t ( 't_24_1745735766826' ) ,
onInput : ( val : string ) = > ( param . value . site_id = val . trim ( ) ) ,
} ) ,
@@ -151,7 +196,7 @@ export default defineComponent({
case 'aliyun-cdn' :
config . push (
. . . [
useFormInput ( '域名' , 'domain' , {
useFormInput ( $t ( '域名' ) , 'domain' , {
placeholder : $t ( 't_0_1744958839535' ) ,
onInput : ( val : string ) = > ( param . value . domain = val . trim ( ) ) ,
} ) ,
@@ -162,7 +207,7 @@ export default defineComponent({
case 'aliyun-oss' :
config . push (
. . . [
useFormInput ( '域名' , 'domain' , {
useFormInput ( $t ( '域名' ) , 'domain' , {
placeholder : $t ( 't_0_1744958839535' ) ,
onInput : ( val : string ) = > ( param . value . domain = val . trim ( ) ) ,
} ) ,
@@ -170,7 +215,7 @@ export default defineComponent({
)
config . push (
. . . [
useFormInput ( '区域' , 'region' , {
useFormInput ( $t ( '区域' ) , 'region' , {
placeholder : $t ( 't_25_1745735766651' ) ,
onInput : ( val : string ) = > ( param . value . region = val . trim ( ) ) ,
} ) ,
@@ -178,7 +223,7 @@ export default defineComponent({
)
config . push (
. . . [
useFormInput ( '存储桶' , 'bucket' , {
useFormInput ( $t ( '存储桶' ) , 'bucket' , {
placeholder : $t ( 't_26_1745735767144' ) ,
onInput : ( val : string ) = > ( param . value . bucket = val . trim ( ) ) ,
} ) ,
@@ -186,6 +231,25 @@ export default defineComponent({
)
break
}
config . push ( {
type : 'custom' as const ,
render : ( ) = > {
return (
< NFormItem label = { $t ( '重复部署' ) } path = "skip" >
< NText > { $t ( '当与上次部署的证书相同且上次部署成功时' ) } < / NText >
< NSwitch
v - model : value = { param . value . skip }
checkedValue = { 1 }
uncheckedValue = { 0 }
class = "mx-[.5rem] "
v-slots = { { checked : ( ) = > $t ( '跳过' ) , unchecked : ( ) = > $t ( '不跳过' ) } }
/ >
< NText > { $t ( '重新部署' ) } < / NText >
< / NFormItem >
)
} ,
} )
return config
} )
@@ -195,7 +259,11 @@ export default defineComponent({
*/
const nextStep = async ( ) = > {
if ( ! param . value . provider ) return message . error ( $t ( 't_0_1746858920894' ) )
if ( param . value . provider === 'localhost' ) {
delete param . value . provider_id
} else {
param . value . provider_id = props . node . config . provider_id
}
// 加载证书来源选项
certOptions . value = findApplyUploadNodesUp ( props . node . id ) . map ( ( item ) = > {
return { label : item.name , value : item.id }
@@ -240,11 +308,12 @@ export default defineComponent({
await example . value ? . validate ( )
const tempData = param . value
const inputs = tempData . inputs
updateNode ( props . node . id , { inputs : [ inputs ] , config : { } } , false )
delete tempData . inputs
// 将输入值直接传递给updateNodeConfig
updateNodeConfig ( props . node . id , {
. . . tempData ,
} )
// 单独更新inputs
updateNode ( props . node . id , { inputs : [ inputs ] } as any , false )
isRefreshNode . value = props . node . id
closeModal ( )
} catch ( error ) {
@@ -256,6 +325,8 @@ export default defineComponent({
onMounted ( ( ) = > {
// 隐藏底部按钮
modalOptions . value . footer = false
// 设置弹窗宽度和高度
modalOptions . value . area = [ 850 , 600 ]
// 如果已经选择了部署类型,则跳转到下一步
if ( param . value . provider ) {
if ( props . node . inputs ) param . value . inputs = props . node . inputs [ 0 ]
@@ -270,25 +341,61 @@ export default defineComponent({
< NStep title = { $t ( 't_29_1745735768933' ) } description = { $t ( 't_2_1745738969878' ) } > < / NStep >
< / NSteps >
{ current . value === 1 && (
< div class = { styles . card Container } >
{ deployTypeOptions . map ( ( item ) = > (
< div
key = { item . value }
c lass = { ` ${ styles . optionCard } ${ param . value . provider === item . value ? styles . optionCardSelected : '' } ` }
onClick = { ( ) = > {
param . value . provider = item . value
} }
< div class = { styles . config Container } >
< div class = { styles . leftPanel } >
< NTabs
type = "bar"
p lacement = "left"
value = { currentTab . value }
onUpdateValue = { ( val ) = > ( currentTab . value = val ) }
>
< NCard contentClass = { styles . cardContent } hoverable bordered = { false } >
< SvgIcon
icon = { ` resources- ${ item . value . replace ( /-[a-z]+$/ , ' ') }` }
size = "2rem"
class = { ` ${ styles . icon } ${ param . value . provider === item . value ? styles . iconSelected : '' } ` }
/ >
< NText type = { param . value . provider === item . value ? 'primary' : 'default' } > { item . label } < / NText >
< / NCard >
< NTabPane name = "all" tab = { $t ( 't_7_1747271292060' ) } / >
< NTabPane name = "host" tab = { $t ( 't_1_1745833931535' ) } / >
< NTabPane name = "btpanel" tab = { $t ( 't_8_1747271290414 ') } / >
< NTabPane name = "1panel" tab = { $t ( 't_9_1747271284765' ) } / >
< NTabPane name = "tencentcloud" tab = { $t ( 't_3_1747019616129' ) } / >
< NTabPane name = "aliyun" tab = { $t ( 't_2_1747019616224' ) } / >
< / NTabs >
< / div >
< div class = { styles . rightPanel } >
< div class = { styles . searchBar } >
< NInput
value = { searchKeyword . value }
onUpdateValue = { ( val ) = > ( searchKeyword . value = val ) }
placeholder = { $t ( '搜索部署类型' ) }
clearable
>
{ {
suffix : ( ) = > (
< div class = "flex items-center" >
< SearchOutlined class = "text-[var(--text-color-3)] w-[1.6rem] cursor-pointer font-bold" / >
< / div >
) ,
} }
< / NInput >
< / div >
) ) }
< NDivider class = "!my-[1rem]" / >
< div class = { styles . cardContainer } >
{ filteredDeployTypes . value . map ( ( item ) = > (
< div
key = { item . value }
class = { ` ${ styles . optionCard } ${ param . value . provider === item . value ? styles . optionCardSelected : '' } ` }
onClick = { ( ) = > {
param . value . provider = item . value
} }
>
< div class = { styles . cardContent } >
< SvgIcon
icon = { ` resources- ${ item . icon . replace ( /-[a-z]+$/ , '' ) } ` }
size = "2rem"
class = { ` ${ styles . icon } ${ param . value . provider === item . value ? styles . iconSelected : '' } ` }
/ >
< NText type = { param . value . provider === item . value ? 'primary' : 'default' } > { item . label } < / NText >
< / div >
< / div >
) ) }
< / div >
< / div >
< / div >
) }
{ current . value === 2 && (