三页面重设计与移动端适配;接入 PWA 与构建分包
CI / test (push) Successful in 47s

This commit is contained in:
2026-07-21 19:26:22 +08:00
parent ac457282ce
commit 6129173fe6
64 changed files with 6243 additions and 549 deletions
+50 -16
View File
@@ -21,6 +21,7 @@ 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 { useIsMobile } from '@/composables/useIsMobile'
import { useRegionAlias } from '@/composables/useRegionAlias'
import { useAsync } from '@/composables/useAsync'
import { useScopeStore } from '@/stores/scope'
@@ -36,6 +37,10 @@ const cfgId = computed(() => Number(route.params.id))
const tab = ref('quota')
const verifying = ref(false)
/** 移动端 hero 元信息默认收起省首屏;域选择器移出 Tab suffix 独立成行 */
const isMobile = useIsMobile()
const heroExpanded = ref(false)
const config = useAsync(() => getConfig(cfgId.value))
/** 失联/暂停租户各 tab 拉不到云端数据,内容区整体换占位 */
@@ -135,22 +140,45 @@ async function remove() {
/>
<AccountTypeBadge :type="config.data.value.accountType" />
<div class="flex-1" />
<NButton size="small" :loading="verifying" @click="verify">立即测活</NButton>
<ConfirmPop
:title="`删除「${config.data.value.alias}」?`"
content="将清理面板内关联数据。"
note="云端日志回传链路请先在「其他」页销毁"
confirm-text="删除"
placement="bottom-end"
:on-confirm="remove"
>
<template #trigger>
<NButton size="small" type="error" ghost>删除租户</NButton>
</template>
</ConfirmPop>
<!-- 操作按钮组:移动端整组独立成行,不随标题换行散落 -->
<div class="flex items-center gap-2 max-md:w-full">
<NButton size="small" :loading="verifying" @click="verify">立即测活</NButton>
<ConfirmPop
:title="`删除「${config.data.value.alias}」?`"
content="将清理面板内关联数据。"
note="云端日志回传链路请先在「其他」页销毁"
confirm-text="删除"
placement="bottom-end"
:on-confirm="remove"
>
<template #trigger>
<NButton size="small" type="error" ghost>删除租户</NButton>
</template>
</ConfirmPop>
</div>
</div>
<div class="mt-3 grid grid-cols-4 gap-4 pb-4 max-lg:grid-cols-2 max-md:grid-cols-1">
<button
v-if="isMobile"
class="mt-2 flex cursor-pointer items-center gap-1 text-xs text-ink-3"
@click="heroExpanded = !heroExpanded"
>
{{ heroExpanded ? '收起详情' : '展开详情' }}
<svg
class="h-3 w-3 transition-transform"
:class="heroExpanded ? 'rotate-180' : ''"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="m6 9 6 6 6-6" />
</svg>
</button>
<div
v-if="!isMobile || heroExpanded"
class="mt-3 grid grid-cols-4 gap-4 pb-4 max-lg:grid-cols-2 max-md:grid-cols-1"
>
<div class="min-w-0">
<div class="text-xs text-ink-3">租户名</div>
<div class="mono mt-0.5 truncate text-[13px]">{{ config.data.value.tenancyName }}</div>
@@ -168,6 +196,7 @@ async function remove() {
<div class="mt-0.5 text-[13px]">{{ fmtTime(config.data.value.createdAt).slice(0, 10) }}</div>
</div>
</div>
<div v-if="isMobile" class="pt-2"></div>
<NTabs v-model:value="tab" type="line" class="tenant-tabs">
<NTabPane name="quota" tab="配额" />
@@ -178,13 +207,18 @@ async function remove() {
<NTabPane name="subs" tab="订阅" />
<NTabPane name="audit" tab="审计日志" />
<NTabPane name="misc" tab="其他" />
<template #suffix>
<template v-if="!isMobile" #suffix>
<!-- 多域租户:用户/IDP/其他 tab 按选中域读写 -->
<div v-if="showDomainPicker" class="w-64 max-md:w-44">
<div v-if="showDomainPicker" class="w-64">
<NSelect v-model:value="domainId" size="small" :options="domainOptions" placeholder="身份域" />
</div>
</template>
</NTabs>
<!-- 移动端:域选择器独立成行,不与 Tab 条抢横向空间 -->
<div v-if="isMobile && showDomainPicker" class="flex items-center gap-2 pt-2.5 pb-3">
<span class="flex-none text-xs text-ink-3">身份域</span>
<NSelect v-model:value="domainId" size="small" :options="domainOptions" placeholder="身份域" />
</div>
</div>
<template v-if="config.data.value">