148 lines
4.6 KiB
Vue
148 lines
4.6 KiB
Vue
<script setup lang="ts">
|
||
import { NInput, NSelect, type SelectOption } from 'naive-ui'
|
||
import { computed, ref, watch } from 'vue'
|
||
|
||
import { attachVnic } from '@/api/instances'
|
||
import { listSubnets } from '@/api/networks'
|
||
import FormField from '@/components/FormField.vue'
|
||
import FormModal from '@/components/FormModal.vue'
|
||
import ToggleCard from '@/components/ToggleCard.vue'
|
||
import { useAsync } from '@/composables/useAsync'
|
||
import { shortAd } from '@/composables/useFormat'
|
||
import { useToast } from '@/composables/useToast'
|
||
|
||
const props = defineProps<{
|
||
show: boolean
|
||
cfgId: number
|
||
instanceId: string
|
||
region?: string
|
||
/** 已附加网卡数,仅用于配额提示文案 */
|
||
attachedCount: number
|
||
}>()
|
||
|
||
const emit = defineEmits<{ 'update:show': [boolean]; attached: [] }>()
|
||
|
||
const message = useToast()
|
||
const submitting = ref(false)
|
||
const subnetId = ref<string | null>(null)
|
||
const displayName = ref('')
|
||
const privateIp = ref('')
|
||
const assignPublicIp = ref(false)
|
||
const assignIpv6 = ref(false)
|
||
|
||
/** vcnId 传空列全部子网:次要网卡允许跨 VCN */
|
||
const subnets = useAsync(() => listSubnets(props.cfgId, '', props.region), false)
|
||
|
||
watch(
|
||
() => props.show,
|
||
(v) => {
|
||
if (v) {
|
||
subnetId.value = null
|
||
displayName.value = ''
|
||
privateIp.value = ''
|
||
assignPublicIp.value = false
|
||
assignIpv6.value = false
|
||
void subnets.run()
|
||
}
|
||
},
|
||
)
|
||
|
||
const options = computed<SelectOption[]>(() =>
|
||
(subnets.data.value ?? [])
|
||
.filter((s) => s.lifecycleState === 'AVAILABLE')
|
||
.map((s) => ({
|
||
label: `${s.displayName}(${s.cidrBlock})${s.availabilityDomain ? ` · ${shortAd(s.availabilityDomain)}` : ''}`,
|
||
value: s.id,
|
||
})),
|
||
)
|
||
|
||
const selected = computed(() => (subnets.data.value ?? []).find((s) => s.id === subnetId.value))
|
||
/** 私有子网禁分公网 IP;未启用 IPv6 的子网禁自动分配 */
|
||
const publicIpBlocked = computed(() => !!selected.value?.prohibitPublicIp)
|
||
const ipv6Blocked = computed(() => !!selected.value && !selected.value.ipv6CidrBlock)
|
||
|
||
watch(selected, (s) => {
|
||
if (s?.prohibitPublicIp) assignPublicIp.value = false
|
||
if (s && !s.ipv6CidrBlock) assignIpv6.value = false
|
||
})
|
||
|
||
async function submit() {
|
||
if (!subnetId.value) return
|
||
submitting.value = true
|
||
try {
|
||
await attachVnic(props.cfgId, props.instanceId, {
|
||
region: props.region,
|
||
subnetId: subnetId.value,
|
||
displayName: displayName.value.trim(),
|
||
privateIp: privateIp.value.trim(),
|
||
assignPublicIp: assignPublicIp.value,
|
||
assignIpv6: assignIpv6.value,
|
||
})
|
||
message.success('附加请求已提交,OS 内需自行配置新网卡 IP')
|
||
emit('update:show', false)
|
||
emit('attached')
|
||
} catch (e) {
|
||
message.error(e instanceof Error ? e.message : '附加失败')
|
||
} finally {
|
||
submitting.value = false
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<FormModal
|
||
:show="show"
|
||
title="附加 VNIC"
|
||
:submitting="submitting"
|
||
:submit-disabled="!subnetId"
|
||
submit-text="附加"
|
||
@update:show="emit('update:show', $event)"
|
||
@submit="submit"
|
||
>
|
||
<FormField
|
||
label="子网"
|
||
required
|
||
hint="与实例同 AD 的子网;跨 VCN 子网亦可选"
|
||
:error="
|
||
!subnets.loading.value && !options.length ? '该区域没有可用子网,请先创建' : undefined
|
||
"
|
||
>
|
||
<NSelect
|
||
v-model:value="subnetId"
|
||
:options="options"
|
||
:loading="subnets.loading.value"
|
||
filterable
|
||
placeholder="选择子网"
|
||
/>
|
||
</FormField>
|
||
<FormField label="显示名称">
|
||
<NInput v-model:value="displayName" placeholder="留空自动生成" />
|
||
</FormField>
|
||
<FormField label="私网 IP">
|
||
<NInput v-model:value="privateIp" placeholder="留空自动分配(推荐)" />
|
||
</FormField>
|
||
<div class="flex flex-col gap-2.5">
|
||
<ToggleCard
|
||
v-model="assignPublicIp"
|
||
title="分配公网 IP"
|
||
:desc="publicIpBlocked ? '所选子网为私有子网,不可分配公网 IP' : '仅公有子网可用;临时地址,分离即释放'"
|
||
:disabled="publicIpBlocked"
|
||
/>
|
||
<ToggleCard
|
||
v-model="assignIpv6"
|
||
title="自动分配 IPv6"
|
||
:desc="
|
||
ipv6Blocked
|
||
? '所选子网未启用 IPv6(可在 VCN 详情一键启用)'
|
||
: '附加时同时分一个 IPv6;后续可在网卡列表继续添加'
|
||
"
|
||
:disabled="ipv6Blocked"
|
||
/>
|
||
</div>
|
||
<div class="mt-2 rounded-md bg-wash px-3 py-2 text-xs leading-relaxed text-ink-3">
|
||
当前已附加 {{ attachedCount }} 张网卡。可附加数量由 shape 决定(如 A1.Flex 每 OCPU 1
|
||
张),超出配额时 OCI 会拒绝请求。
|
||
</div>
|
||
</FormModal>
|
||
</template>
|