Files
oci-portal-dash/src/components/proxy/ProxyTenantsModal.vue
T
wangdefa aea00c2382
CI / test (push) Successful in 25s
Release / release (push) Successful in 25s
关于页运行状态、代理关联租户与步进框修复
2026-07-13 12:21:28 +08:00

131 lines
4.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { NButton, NModal } from 'naive-ui'
import { computed, ref, watch } from 'vue'
import { listConfigs } from '@/api/configs'
import { setProxyTenants } from '@/api/proxies'
import FormField from '@/components/FormField.vue'
import TenantPicker from '@/components/TenantPicker.vue'
import { useAsync } from '@/composables/useAsync'
import type { ProxyInfo } from '@/types/api'
import { useToast } from '@/composables/useToast'
/** 代理侧关联租户管理:打开时回显当前关联名单,多选增删,保存即设置全集
* (选中即关联,含从其他代理改挂;取消选中即解除)。 */
const props = defineProps<{ show: boolean; proxy: ProxyInfo | null }>()
const emit = defineEmits<{ 'update:show': [boolean]; saved: [] }>()
const message = useToast()
const configs = useAsync(listConfigs, false)
const selected = ref<number[]>([])
const saving = ref(false)
watch(
() => props.show,
async (v) => {
if (!v || !props.proxy) return
selected.value = []
await configs.run()
const pid = props.proxy.id
selected.value = (configs.data.value ?? []).filter((c) => c.proxyId === pid).map((c) => c.id)
},
)
const all = computed(() => configs.data.value ?? [])
/** 当前选中名单(打开时即已关联名单),chips 展示并支持点 × 移除 */
const picked = computed(() => all.value.filter((c) => selected.value.includes(c.id)))
/** 选中但已挂其他代理的租户:保存即改挂,给出警示 */
const rebinding = computed(() =>
picked.value.filter((c) => c.proxyId !== null && c.proxyId !== props.proxy?.id),
)
function removeOne(id: number) {
selected.value = selected.value.filter((v) => v !== id)
}
async function save() {
if (!props.proxy) return
saving.value = true
try {
const res = await setProxyTenants(props.proxy.id, selected.value)
message.success(`已更新关联,当前 ${res.usedBy} 个租户经此代理出站`)
emit('update:show', false)
emit('saved')
} catch (e) {
message.error(e instanceof Error ? e.message : '保存失败')
} finally {
saving.value = false
}
}
</script>
<template>
<NModal
:show="show"
preset="card"
:title="`关联租户 · ${proxy?.name ?? ''}`"
:style="{ width: '480px', maxWidth: 'calc(100vw - 24px)' }"
@update:show="emit('update:show', $event)"
>
<FormField label="关联租户" hint="选中即关联,取消选中即解除;关联后租户全部 SDK 请求经此代理出站">
<TenantPicker
v-model:values="selected"
multiple
:configs="all"
:loading="configs.loading.value"
placeholder="选择要关联的租户"
/>
</FormField>
<div v-if="picked.length" class="mb-3 flex flex-wrap gap-1.5">
<span
v-for="c in picked"
:key="c.id"
class="inline-flex items-center gap-1 rounded-full border border-line bg-wash px-2.5 py-0.5 text-[11.5px] font-medium text-ink-2"
>
{{ c.alias }}
<button
type="button"
class="cursor-pointer text-ink-3 hover:text-err"
:aria-label="`移除 ${c.alias}`"
@click="removeOne(c.id)"
>
</button>
</span>
</div>
<div v-else class="mb-3 text-xs text-ink-3">暂无租户关联此代理</div>
<div
v-if="rebinding.length"
class="mb-3 flex items-start gap-2 rounded-lg border border-warn/30 bg-warn/10 px-3 py-2.5 text-xs leading-relaxed"
>
<svg
class="mt-0.5 h-[14px] w-[14px] flex-none text-warn"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z" />
<path d="M12 9v4M12 17h.01" />
</svg>
<span>
<template v-for="(c, i) in rebinding" :key="c.id">
<template v-if="i > 0"></template>
<b>{{ c.alias }}</b>
<span v-if="c.proxyName" class="text-ink-3">现挂 {{ c.proxyName }}</span>
</template>
已关联其他代理,保存后将改挂到本代理
</span>
</div>
<div class="mt-1 flex items-center gap-2">
<NButton size="small" type="primary" :loading="saving" @click="save">保存</NButton>
<NButton size="small" quaternary @click="emit('update:show', false)">取消</NButton>
</div>
</NModal>
</template>