Files
YG_FT/frontend/src/views/tenants/TenantDetailView.vue
2026-08-17 09:15:36 +08:00

114 lines
4.1 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 { onMounted, reactive, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { getTenant, setTenantQuota, type Tenant } from '@/api/modules/tenant'
const route = useRoute()
const router = useRouter()
const tenant = ref<Tenant | null>(null)
const loading = ref(false)
const quotaForm = reactive({ gpu: 0, storage: 0, maxProjects: 0 })
function parseQuota(quota: Record<string, unknown> | undefined | null | string) {
// 兼容处理quota 可能是 JSON 字符串或嵌套 { quota: {...} } 格式
let q: Record<string, unknown> = {}
if (typeof quota === 'string') {
try { q = JSON.parse(quota) || {} } catch { q = {} }
} else if (quota && typeof quota === 'object') {
q = quota
}
// 如果是嵌套格式 { quota: { gpu: 4, ... } },提取内层
if (q.quota && typeof q.quota === 'object' && !q.gpu) {
q = q.quota as Record<string, unknown>
}
return {
gpu: Number(q.gpu || q.gpu_quota || 0),
storage: Number(q.storage || q.storage_quota || 0),
maxProjects: Number(q.max_projects || 0),
}
}
function formatQuota(quota: Record<string, unknown> | undefined | null) {
const q = parseQuota(quota)
const parts: string[] = []
if (q.gpu > 0) parts.push(`GPU ${q.gpu}`)
if (q.storage > 0) parts.push(`存储 ${q.storage}GB`)
if (q.maxProjects > 0) parts.push(`项目 ${q.maxProjects}`)
return parts.length ? parts.join(' | ') : '—'
}
async function load() {
const id = route.params.id as string
loading.value = true
try {
tenant.value = await getTenant(id)
const q = parseQuota(tenant.value?.quota)
quotaForm.gpu = q.gpu
quotaForm.storage = q.storage
quotaForm.maxProjects = q.maxProjects
} finally {
loading.value = false
}
}
async function saveQuota() {
if (!tenant.value) return
const quota: Record<string, unknown> = {}
if (quotaForm.gpu > 0) quota.gpu = quotaForm.gpu
if (quotaForm.storage > 0) quota.storage = quotaForm.storage
if (quotaForm.maxProjects > 0) quota.max_projects = quotaForm.maxProjects
await setTenantQuota(tenant.value.id, quota)
ElMessage.success('配额已保存')
load()
}
onMounted(load)
</script>
<template>
<div class="page">
<el-page-header title="返回" @back="router.back()">
<template #content>
<span class="page-title">租户详情{{ tenant?.name }}</span>
</template>
</el-page-header>
<el-card class="section" v-loading="loading">
<template #header>基本信息</template>
<el-descriptions :column="2" border>
<el-descriptions-item label="名称">{{ tenant?.name }}</el-descriptions-item>
<el-descriptions-item label="用户ID">{{ tenant?.code }}</el-descriptions-item>
<el-descriptions-item label="状态">{{ tenant?.status }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ tenant?.create_time }}</el-descriptions-item>
<el-descriptions-item label="配额">{{ formatQuota(tenant?.quota) }}</el-descriptions-item>
</el-descriptions>
<el-divider />
<div class="quota-edit">
<span class="label">配额设置0 表示不限制</span>
<el-form label-width="100px">
<el-form-item label="GPU 数量">
<el-input-number v-model="quotaForm.gpu" :min="0" :step="1" />
</el-form-item>
<el-form-item label="存储配额(GB)">
<el-input-number v-model="quotaForm.storage" :min="0" :step="10" />
</el-form-item>
<el-form-item label="最大项目数">
<el-input-number v-model="quotaForm.maxProjects" :min="0" :step="1" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveQuota">保存配额</el-button>
</el-form-item>
</el-form>
</div>
</el-card>
</div>
</template>
<style scoped lang="scss">
.page { padding: 16px; }
.section { margin-top: 16px; }
.page-title { font-size: 16px; font-weight: 600; }
.quota-edit { display: flex; flex-direction: column; gap: 12px; max-width: 480px; }
.label { font-size: 13px; color: #606266; }
</style>