发布 0.1.0:通知渠道、告警规则与多项体验修复
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { NButton, NPopconfirm, NSpin, NTabPane, NTabs, NTooltip, useMessage } from 'naive-ui'
|
||||
import { computed, ref } from 'vue'
|
||||
import { NButton, NPopconfirm, NSelect, NSpin, NTabPane, NTabs, NTooltip } from 'naive-ui'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { RouterLink, useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import { deleteConfig, getConfig, verifyConfig } from '@/api/configs'
|
||||
import { listIdentityDomains } from '@/api/tenant'
|
||||
import AccountTypeBadge from '@/components/AccountTypeBadge.vue'
|
||||
import AuditLogTab from '@/components/tenant/AuditLogTab.vue'
|
||||
import CostTab from '@/components/tenant/CostTab.vue'
|
||||
@@ -15,15 +16,17 @@ import QuotaTab from '@/components/tenant/QuotaTab.vue'
|
||||
import StatusBadge from '@/components/StatusBadge.vue'
|
||||
import SubsTab from '@/components/tenant/SubsTab.vue'
|
||||
import UsersTab from '@/components/tenant/UsersTab.vue'
|
||||
import { aliveMeta } from '@/composables/useAliveStatus'
|
||||
import { fmtTime } from '@/composables/useFormat'
|
||||
import { useRegionAlias } from '@/composables/useRegionAlias'
|
||||
import { useAsync } from '@/composables/useAsync'
|
||||
import { useScopeStore } from '@/stores/scope'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
|
||||
const scope = useScopeStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const message = useMessage()
|
||||
const message = useToast()
|
||||
const { alias: regionAlias } = useRegionAlias()
|
||||
|
||||
const cfgId = computed(() => Number(route.params.id))
|
||||
@@ -32,8 +35,33 @@ const verifying = ref(false)
|
||||
|
||||
const config = useAsync(() => getConfig(cfgId.value))
|
||||
|
||||
/** 失联租户各 tab 拉不到云端数据,内容区整体换失联占位 */
|
||||
const isDead = computed(() => config.data.value?.aliveStatus === 'dead')
|
||||
/** 失联/暂停租户各 tab 拉不到云端数据,内容区整体换占位 */
|
||||
const isBlocked = computed(() =>
|
||||
['dead', 'suspended'].includes(config.data.value?.aliveStatus ?? ''),
|
||||
)
|
||||
|
||||
// ---- 身份域:用户 / IDP / 其他 三个 tab 共享的域上下文 ----
|
||||
// 拉取失败(无权限/老租户)静默降级:不显示选择器,各 tab 走缺省 Default 路径
|
||||
const domains = useAsync(async () => {
|
||||
try {
|
||||
return await listIdentityDomains(cfgId.value)
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
})
|
||||
const domainId = ref<string | undefined>(undefined)
|
||||
watch(domains.data, (list) => {
|
||||
if (!list?.length) return
|
||||
const preferred = list.find((d) => d.displayName === 'Default') ?? list[0]
|
||||
domainId.value ??= preferred.id
|
||||
})
|
||||
const domainOptions = computed(
|
||||
() => domains.data.value?.map((d) => ({ label: d.displayName, value: d.id })) ?? [],
|
||||
)
|
||||
/** 域选择器只在多域租户的域相关 tab 显示 */
|
||||
const showDomainPicker = computed(
|
||||
() => (domains.data.value?.length ?? 0) > 1 && ['users', 'idp', 'misc'].includes(tab.value),
|
||||
)
|
||||
|
||||
async function verify() {
|
||||
verifying.value = true
|
||||
@@ -53,7 +81,7 @@ async function verify() {
|
||||
async function remove() {
|
||||
try {
|
||||
await deleteConfig(cfgId.value)
|
||||
message.success('已删除(仅移除本面板配置,不影响云端资源)')
|
||||
message.success('已删除租户及关联本地数据,OCI 云端资源未受影响')
|
||||
void scope.refreshConfigs()
|
||||
void router.push({ name: 'tenants' })
|
||||
} catch (e) {
|
||||
@@ -88,19 +116,22 @@ async function remove() {
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<h1 class="page-title">{{ config.data.value.alias }}</h1>
|
||||
<NTooltip
|
||||
v-if="isDead && config.data.value.lastError"
|
||||
v-if="isBlocked && config.data.value.lastError"
|
||||
trigger="hover"
|
||||
placement="top-start"
|
||||
>
|
||||
<template #trigger>
|
||||
<StatusBadge kind="term" label="失联" />
|
||||
<StatusBadge
|
||||
:kind="aliveMeta(config.data.value.aliveStatus).kind"
|
||||
:label="aliveMeta(config.data.value.aliveStatus).label"
|
||||
/>
|
||||
</template>
|
||||
<div class="max-w-80 text-xs">{{ config.data.value.lastError }}</div>
|
||||
</NTooltip>
|
||||
<StatusBadge
|
||||
v-else
|
||||
:kind="config.data.value.aliveStatus === 'alive' ? 'run' : 'term'"
|
||||
:label="config.data.value.aliveStatus === 'alive' ? '存活' : '失联'"
|
||||
:kind="aliveMeta(config.data.value.aliveStatus).kind"
|
||||
:label="aliveMeta(config.data.value.aliveStatus).label"
|
||||
/>
|
||||
<AccountTypeBadge :type="config.data.value.accountType" />
|
||||
<div class="flex-1" />
|
||||
@@ -109,7 +140,8 @@ async function remove() {
|
||||
<template #trigger>
|
||||
<NButton size="small" type="error" ghost>删除租户</NButton>
|
||||
</template>
|
||||
删除「{{ config.data.value.alias }}」?仅移除本面板配置与快照,不影响云端资源。
|
||||
删除「{{ config.data.value.alias }}」?将清理本面板中的关联任务、快照、回传事件与 Webhook
|
||||
密钥、告警及 AI 渠道数据;OCI 云端资源不会被删除(云端日志回传链路请先在“其他”页销毁)。
|
||||
</NPopconfirm>
|
||||
</div>
|
||||
|
||||
@@ -140,19 +172,30 @@ async function remove() {
|
||||
<NTabPane name="subs" tab="订阅" />
|
||||
<NTabPane name="audit" tab="审计日志" />
|
||||
<NTabPane name="misc" tab="其他" />
|
||||
<template #suffix>
|
||||
<!-- 多域租户:用户/IDP/其他 tab 按选中域读写 -->
|
||||
<div v-if="showDomainPicker" class="w-64 max-md:w-44">
|
||||
<NSelect v-model:value="domainId" size="small" :options="domainOptions" placeholder="身份域" />
|
||||
</div>
|
||||
</template>
|
||||
</NTabs>
|
||||
</div>
|
||||
|
||||
<template v-if="config.data.value">
|
||||
<DeadPlaceholder v-if="isDead" :last-error="config.data.value.lastError" />
|
||||
<DeadPlaceholder
|
||||
v-if="isBlocked"
|
||||
:last-error="config.data.value.lastError"
|
||||
:suspended="config.data.value.aliveStatus === 'suspended'"
|
||||
/>
|
||||
<template v-else>
|
||||
<QuotaTab v-if="tab === 'quota'" :cfg-id="cfgId" />
|
||||
<IdpTab v-else-if="tab === 'idp'" :cfg-id="cfgId" />
|
||||
<UsersTab v-else-if="tab === 'users'" :cfg-id="cfgId" />
|
||||
<!-- 域相关 tab 以 domainId 为 key:切域整组件重挂载,状态与数据全量刷新 -->
|
||||
<IdpTab v-else-if="tab === 'idp'" :key="`idp-${domainId ?? ''}`" :cfg-id="cfgId" :domain-id="domainId" />
|
||||
<UsersTab v-else-if="tab === 'users'" :key="`users-${domainId ?? ''}`" :cfg-id="cfgId" :domain-id="domainId" />
|
||||
<CostTab v-else-if="tab === 'cost'" :cfg-id="cfgId" />
|
||||
<SubsTab v-else-if="tab === 'subs'" :cfg-id="cfgId" :account-type="config.data.value.accountType" />
|
||||
<AuditLogTab v-else-if="tab === 'audit'" :cfg-id="cfgId" />
|
||||
<MiscTab v-else :cfg-id="cfgId" />
|
||||
<MiscTab v-else :key="`misc-${domainId ?? ''}`" :cfg-id="cfgId" :domain-id="domainId" />
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user