From 0155715278a7c77f3ecce5d8d9d571c9933cd0e1 Mon Sep 17 00:00:00 2001 From: shiran Date: Tue, 30 Jun 2026 10:26:01 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=99=9A=E6=8B=9F=E6=9C=BA=E7=BD=91?= =?UTF-8?q?=E7=BB=9C=E7=AE=A1=E7=90=86=E6=94=B9=E4=B8=BA=E8=A7=A3=E7=BB=91?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E4=B8=8D=E5=86=8D=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E5=BA=95=E5=B1=82=E7=BD=91=E7=BB=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 user-vm/UserVmDetail 和 virtualization/VmDetail 中的网络删除操作改为通过 updateVm 接口解绑,与绑定网络逻辑对称,避免误删底层物理网络。 Co-authored-by: Cursor --- src/views/user-vm/UserVmDetail.vue | 30 ++++++++++++++++----------- src/views/user/UserDetail.vue | 11 +++++++++- src/views/virtualization/VmDetail.vue | 26 +++++++++++++++++------ 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/views/user-vm/UserVmDetail.vue b/src/views/user-vm/UserVmDetail.vue index 3c351e9..086f220 100644 --- a/src/views/user-vm/UserVmDetail.vue +++ b/src/views/user-vm/UserVmDetail.vue @@ -344,7 +344,7 @@ @@ -1807,21 +1807,27 @@ const resolveNetworkServiceHost = async (row) => { } const handleDeleteVmNetwork = (row) => { ElMessageBox.confirm( - `将删除底层网络「${row.name}」(ID:${row.id}),该操作会影响所有绑定该网络的虚拟机,是否继续?`, - '删除网络', - { confirmButtonText: '确定删除', cancelButtonText: '取消', type: 'warning' } + `确定从该虚拟机解绑网络「${row.name}」(ID:${row.id}) 吗?`, + '解绑网络', + { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' } ).then(async () => { deletingNetworkId.value = row.id try { - const { serviceId, hostId } = await resolveNetworkServiceHost(row) - if (!serviceId) { ElMessage.error('无法获取该网络所属服务ID,删除失败'); return } - const params = { service_id: serviceId, network_id: row.id } - if (hostId) params.host_id = hostId - const res = await deletePointNetwork(params) - if (res?.data?.code === 200) { ElMessage.success('删除成功'); loadDetail() } - else ElMessage.error(extractApiError(res?.data, '删除失败')) + const payload = { user_goods_id: userGoodsId.value } + const remainingNetworks = vmNetworks.value.filter(n => n.id !== row.id) + const bridgeIds = remainingNetworks.filter(n => n.type === 'bridge').map(n => n.id) + const natNet = remainingNetworks.find(n => n.type === 'nat') + payload.network_ids = bridgeIds + if (natNet) payload.internet_network_id = natNet.id + if (vm.value?.rx_bandwidth) payload.rx_bandwidth = vm.value.rx_bandwidth + if (vm.value?.tx_bandwidth) payload.tx_bandwidth = vm.value.tx_bandwidth + if (vm.value?.ssh_port) payload.ssh_port = vm.value.ssh_port + if (inPortGroup.value?.id) payload.port_group_id = inPortGroup.value.id + const res = await updateUserVm(payload) + if (res?.data?.code === 200) { ElMessage.success('解绑网络成功'); loadDetail() } + else ElMessage.error(extractApiError(res?.data, '解绑网络失败')) } catch (e) { - ElMessage.error(extractApiError(e?.response?.data, '删除失败')) + ElMessage.error(extractApiError(e?.response?.data, '解绑网络失败')) } finally { deletingNetworkId.value = 0 } diff --git a/src/views/user/UserDetail.vue b/src/views/user/UserDetail.vue index f20c9df..efdd312 100644 --- a/src/views/user/UserDetail.vue +++ b/src/views/user/UserDetail.vue @@ -257,7 +257,11 @@ - + + + @@ -280,6 +284,11 @@ + + +
详情 编辑 设为主IP - 删除 + 解绑 @@ -2962,13 +2962,27 @@ const submitNetForm = () => { } const handleNetDetail = (row) => { netDetailData.value = row; netDetailVisible.value = true } const handleNetDelete = (row) => { - ElMessageBox.confirm(`确定要删除网络「${row.name}」(ID: ${row.id}) 吗?`, '删除网络', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }) + ElMessageBox.confirm(`确定从该虚拟机解绑网络「${row.name}」(ID: ${row.id}) 吗?`, '解绑网络', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }) .then(async () => { + actionLoading.value = true try { - const res = await deleteNetwork({ service_id: serviceId.value, network_id: row.id, host_id: row.host_id }) - if (res?.data?.code === 200) { ElMessage.success('删除成功'); loadDetail() } - else ElMessage.error(extractApiError(res?.data, '删除失败')) - } catch (e) { ElMessage.error(extractApiError(e?.response?.data, '删除失败')) } + const fd = new FormData() + fd.append('service_id', serviceId.value) + fd.append('vm_id', vmId.value) + const remainingNetworks = vmNetworks.value.filter(n => n.id !== row.id) + const bridgeIds = remainingNetworks.filter(n => n.type === 'bridge').map(n => n.id) + const natNet = remainingNetworks.find(n => n.type === 'nat') + bridgeIds.forEach(id => fd.append('network_ids', id)) + if (natNet) fd.append('internet_network_id', natNet.id) + if (detail.value?.rx_bandwidth) fd.append('rx_bandwidth', detail.value.rx_bandwidth) + if (detail.value?.tx_bandwidth) fd.append('tx_bandwidth', detail.value.tx_bandwidth) + if (detail.value?.ssh_port) fd.append('ssh_port', detail.value.ssh_port) + if (vmPortGroup.value?.id) fd.append('port_group_id', vmPortGroup.value.id) + const res = await updateVm(fd) + if (res?.data?.code === 200) { ElMessage.success('解绑网络成功'); loadDetail() } + else ElMessage.error(extractApiError(res?.data, '解绑网络失败')) + } catch (e) { ElMessage.error(extractApiError(e?.response?.data, '解绑网络失败')) } + finally { actionLoading.value = false } }).catch(() => {}) }