前端: 移动端适配 + 模型定价手动添加入口
- 表格加 min-w 窄屏横向滚动; 弹窗/资料网格窄屏换列; 顶栏/头部防溢出 - 渠道页移动卡片化、其余页面头部换行、Toast 自适应宽 - 模型定价页顶部加快捷输入(模型名直接进创建弹窗), 接口导入不全可手动补 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -117,24 +117,24 @@ async function logout() {
|
|||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<div class="flex min-h-[100dvh] flex-1 flex-col md:ml-56">
|
<div class="flex min-h-[100dvh] flex-1 flex-col md:ml-56">
|
||||||
<header class="flex h-14 items-center justify-between border-b border-edge px-4 md:px-6">
|
<header class="flex h-14 items-center justify-between gap-2 border-b border-edge px-4 md:px-6">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex min-w-0 items-center gap-2">
|
||||||
<button
|
<button
|
||||||
class="rounded-md p-1.5 text-muted hover:bg-surface2 hover:text-ink md:hidden"
|
class="shrink-0 rounded-md p-1.5 text-muted hover:bg-surface2 hover:text-ink md:hidden"
|
||||||
aria-label="打开菜单"
|
aria-label="打开菜单"
|
||||||
@click="sidebarOpen = true"
|
@click="sidebarOpen = true"
|
||||||
>
|
>
|
||||||
<PhList :size="20" />
|
<PhList :size="20" />
|
||||||
</button>
|
</button>
|
||||||
<span class="font-mono text-xs text-muted">{{ auth.user?.username }}</span>
|
<span class="truncate font-mono text-xs text-muted">{{ auth.user?.username }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex shrink-0 items-center gap-1.5 md:gap-3">
|
||||||
<span class="mono-num rounded-md border border-edge bg-surface px-2.5 py-1 text-xs text-accent">
|
<span class="mono-num rounded-md border border-edge bg-surface px-2 py-1 text-xs text-accent sm:px-2.5">
|
||||||
余额 {{ balance }}
|
<span class="hidden sm:inline">余额 </span>{{ balance }}
|
||||||
</span>
|
</span>
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
<button
|
<button
|
||||||
class="rounded-md px-2 py-1 text-xs text-muted transition hover:bg-surface2 hover:text-ink"
|
class="rounded-md px-1.5 py-1 text-xs text-muted transition hover:bg-surface2 hover:text-ink md:px-2"
|
||||||
@click="logout"
|
@click="logout"
|
||||||
>
|
>
|
||||||
退出
|
退出
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const toast = useToastStore()
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed right-4 bottom-4 z-[80] flex w-80 flex-col gap-2" aria-live="polite">
|
<div class="fixed right-4 bottom-4 z-[80] flex w-80 max-w-[calc(100vw-2rem)] flex-col gap-2" aria-live="polite">
|
||||||
<TransitionGroup
|
<TransitionGroup
|
||||||
enter-active-class="transition-all duration-200"
|
enter-active-class="transition-all duration-200"
|
||||||
enter-from-class="translate-y-1 opacity-0"
|
enter-from-class="translate-y-1 opacity-0"
|
||||||
|
|||||||
@@ -13,22 +13,22 @@ const auth = useAuthStore()
|
|||||||
<img src="/favicon.svg" alt="" class="size-5" />
|
<img src="/favicon.svg" alt="" class="size-5" />
|
||||||
<span class="text-sm font-semibold tracking-tight">openteam</span>
|
<span class="text-sm font-semibold tracking-tight">openteam</span>
|
||||||
</div>
|
</div>
|
||||||
<nav class="flex items-center gap-2">
|
<nav class="flex items-center gap-1.5 sm:gap-2">
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
<router-link
|
<router-link
|
||||||
v-if="!auth.isAuthed"
|
v-if="!auth.isAuthed"
|
||||||
to="/login"
|
to="/login"
|
||||||
class="rounded-md px-3 py-1.5 text-sm text-muted transition hover:text-ink"
|
class="rounded-md px-2.5 py-1.5 text-sm text-muted transition hover:text-ink sm:px-3"
|
||||||
>
|
>
|
||||||
登录
|
登录
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link v-else to="/console/dashboard" class="rounded-md px-3 py-1.5 text-sm text-muted transition hover:text-ink">
|
<router-link v-else to="/console/dashboard" class="rounded-md px-2.5 py-1.5 text-sm text-muted transition hover:text-ink sm:px-3">
|
||||||
控制台
|
控制台
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="!auth.isAuthed"
|
v-if="!auth.isAuthed"
|
||||||
to="/register"
|
to="/register"
|
||||||
class="rounded-md bg-accent px-3.5 py-1.5 text-sm font-medium text-accent-ink transition hover:bg-accent-strong"
|
class="rounded-md bg-accent px-3 py-1.5 text-sm font-medium text-accent-ink transition hover:bg-accent-strong sm:px-3.5"
|
||||||
>
|
>
|
||||||
免费注册
|
免费注册
|
||||||
</router-link>
|
</router-link>
|
||||||
@@ -42,7 +42,7 @@ const auth = useAuthStore()
|
|||||||
<div class="mx-auto grid max-w-6xl items-center gap-10 px-4 pt-20 pb-16 lg:grid-cols-2 lg:pt-24">
|
<div class="mx-auto grid max-w-6xl items-center gap-10 px-4 pt-20 pb-16 lg:grid-cols-2 lg:pt-24">
|
||||||
<div class="max-w-xl">
|
<div class="max-w-xl">
|
||||||
<p class="mb-3 font-mono text-xs tracking-wide text-accent">LLM API 中转网关</p>
|
<p class="mb-3 font-mono text-xs tracking-wide text-accent">LLM API 中转网关</p>
|
||||||
<h1 class="text-4xl leading-none font-semibold tracking-tight md:text-5xl">
|
<h1 class="text-3xl leading-tight font-semibold tracking-tight sm:text-4xl md:text-5xl">
|
||||||
一个 Key,调用所有主流模型
|
一个 Key,调用所有主流模型
|
||||||
</h1>
|
</h1>
|
||||||
<p class="mt-5 max-w-md text-base leading-relaxed text-muted">
|
<p class="mt-5 max-w-md text-base leading-relaxed text-muted">
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ const summary = ref<ModelSummary>({ total: 0, unpriced: 0, missing: [], denied_c
|
|||||||
const editOpen = ref(false)
|
const editOpen = ref(false)
|
||||||
const editing = ref<Model | null>(null)
|
const editing = ref<Model | null>(null)
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
|
const quickName = ref('')
|
||||||
|
|
||||||
|
function quickAdd() {
|
||||||
|
openCreate()
|
||||||
|
if (quickName.value) form.name = quickName.value.trim()
|
||||||
|
}
|
||||||
|
|
||||||
const bindOpen = ref(false)
|
const bindOpen = ref(false)
|
||||||
const bindModel = ref<Model | null>(null)
|
const bindModel = ref<Model | null>(null)
|
||||||
@@ -129,12 +135,20 @@ onMounted(load)
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mx-auto max-w-6xl">
|
<div class="mx-auto max-w-6xl">
|
||||||
<div class="mb-6 flex items-center justify-between">
|
<div class="mb-6 flex flex-wrap items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-lg font-semibold">模型与定价</h1>
|
<h1 class="text-lg font-semibold">模型与定价</h1>
|
||||||
<p class="text-sm text-muted">价格按每百万 token (USD),历史用量按当时价格入账</p>
|
<p class="text-sm text-muted">接口导入不全时可直接输入模型名添加,如 glm-4.7-flash</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex w-full gap-2 sm:w-auto">
|
||||||
|
<input
|
||||||
|
v-model="quickName"
|
||||||
|
placeholder="模型名,如 glm-4.7-flash"
|
||||||
|
class="h-10 min-w-0 flex-1 rounded-md border border-edge2 bg-surface px-3 font-mono text-xs outline-none focus:border-accent sm:w-52 sm:flex-none"
|
||||||
|
@keyup.enter="quickAdd"
|
||||||
|
/>
|
||||||
|
<Button class="shrink-0" @click="quickAdd">添加模型</Button>
|
||||||
</div>
|
</div>
|
||||||
<Button @click="openCreate">添加模型</Button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 一致性提示:渠道提供的未禁止模型应全部纳入定价 -->
|
<!-- 一致性提示:渠道提供的未禁止模型应全部纳入定价 -->
|
||||||
@@ -151,14 +165,14 @@ onMounted(load)
|
|||||||
|
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<div v-for="m in models" :key="m.id" class="card">
|
<div v-for="m in models" :key="m.id" class="card">
|
||||||
<div class="flex items-center justify-between px-4 py-3">
|
<div class="flex flex-wrap items-center justify-between gap-x-4 gap-y-2 px-4 py-3">
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<span class="font-mono text-sm text-ink">{{ m.name }}</span>
|
<span class="font-mono text-sm text-ink">{{ m.name }}</span>
|
||||||
<Badge :variant="m.enabled ? 'ok' : 'neutral'">{{ m.enabled ? '启用' : '停用' }}</Badge>
|
<Badge :variant="m.enabled ? 'ok' : 'neutral'">{{ m.enabled ? '启用' : '停用' }}</Badge>
|
||||||
<Badge v-if="m.denied" variant="err">已禁止</Badge>
|
<Badge v-if="m.denied" variant="err">已禁止</Badge>
|
||||||
<Badge v-if="m.needs_pricing" variant="warn">未定价</Badge>
|
<Badge v-if="m.needs_pricing" variant="warn">未定价</Badge>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex flex-wrap items-center gap-3">
|
||||||
<span class="mono-num text-xs text-muted">入 {{ m.input_price }}</span>
|
<span class="mono-num text-xs text-muted">入 {{ m.input_price }}</span>
|
||||||
<span class="mono-num text-xs text-muted">出 {{ m.output_price }}</span>
|
<span class="mono-num text-xs text-muted">出 {{ m.output_price }}</span>
|
||||||
<span class="mono-num text-xs text-muted">缓存读 {{ m.cache_read_price }}</span>
|
<span class="mono-num text-xs text-muted">缓存读 {{ m.cache_read_price }}</span>
|
||||||
@@ -197,7 +211,7 @@ onMounted(load)
|
|||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<Input v-model="form.name" label="模型名" placeholder="claude-sonnet-5" :disabled="!!editing" />
|
<Input v-model="form.name" label="模型名" placeholder="claude-sonnet-5" :disabled="!!editing" />
|
||||||
<Input v-model="form.display_name" label="展示名" />
|
<Input v-model="form.display_name" label="展示名" />
|
||||||
<div class="grid grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<Input v-model="form.input_price" label="输入价格 /1M" type="number" />
|
<Input v-model="form.input_price" label="输入价格 /1M" type="number" />
|
||||||
<Input v-model="form.output_price" label="输出价格 /1M" type="number" />
|
<Input v-model="form.output_price" label="输出价格 /1M" type="number" />
|
||||||
<Input v-model="form.cache_read_price" label="缓存读价格 /1M" type="number" />
|
<Input v-model="form.cache_read_price" label="缓存读价格 /1M" type="number" />
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ onMounted(load)
|
|||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="w-full text-sm">
|
<table class="w-full text-sm min-w-[760px]">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="border-b border-edge text-left text-xs text-muted">
|
<tr class="border-b border-edge text-left text-xs text-muted">
|
||||||
<th scope="col" class="px-4 py-2.5 font-medium">用户</th>
|
<th scope="col" class="px-4 py-2.5 font-medium">用户</th>
|
||||||
|
|||||||
@@ -123,25 +123,25 @@ onMounted(load)
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mx-auto max-w-6xl">
|
<div class="mx-auto max-w-6xl">
|
||||||
<div class="mb-6 flex items-center justify-between">
|
<div class="mb-6 flex flex-wrap items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-lg font-semibold">用户</h1>
|
<h1 class="text-lg font-semibold">用户</h1>
|
||||||
<p class="text-sm text-muted">管理角色、状态与余额</p>
|
<p class="text-sm text-muted">管理角色、状态与余额</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex w-full gap-2 sm:w-auto">
|
||||||
<input
|
<input
|
||||||
v-model="q"
|
v-model="q"
|
||||||
placeholder="搜索用户名 / 邮箱"
|
placeholder="搜索用户名 / 邮箱"
|
||||||
class="h-10 w-56 rounded-md border border-edge2 bg-surface px-3 text-sm outline-none focus:border-accent"
|
class="h-10 min-w-0 flex-1 rounded-md border border-edge2 bg-surface px-3 text-sm outline-none focus:border-accent sm:w-56 sm:flex-none"
|
||||||
@keyup.enter="search"
|
@keyup.enter="search"
|
||||||
/>
|
/>
|
||||||
<Button variant="ghost" @click="search">搜索</Button>
|
<Button variant="ghost" class="shrink-0" @click="search">搜索</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="w-full text-sm">
|
<table class="w-full text-sm min-w-[720px]">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="border-b border-edge text-left text-xs text-muted">
|
<tr class="border-b border-edge text-left text-xs text-muted">
|
||||||
<th scope="col" class="px-4 py-2.5 font-medium">ID</th>
|
<th scope="col" class="px-4 py-2.5 font-medium">ID</th>
|
||||||
@@ -225,7 +225,7 @@ onMounted(load)
|
|||||||
placeholder="逗号分隔"
|
placeholder="逗号分隔"
|
||||||
hint="黑名单优先"
|
hint="黑名单优先"
|
||||||
/>
|
/>
|
||||||
<div class="grid grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<label class="block">
|
<label class="block">
|
||||||
<span class="mb-1.5 block text-xs font-medium text-muted">角色</span>
|
<span class="mb-1.5 block text-xs font-medium text-muted">角色</span>
|
||||||
<select v-model="editForm.role" class="h-10 w-full rounded-md border border-edge2 bg-surface px-3 text-sm text-ink outline-none focus:border-accent">
|
<select v-model="editForm.role" class="h-10 w-full rounded-md border border-edge2 bg-surface px-3 text-sm text-ink outline-none focus:border-accent">
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ onMounted(load)
|
|||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="w-full text-sm">
|
<table class="w-full text-sm min-w-[520px]">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="border-b border-edge text-left text-xs text-muted">
|
<tr class="border-b border-edge text-left text-xs text-muted">
|
||||||
<th scope="col" class="px-4 py-2.5 font-medium">名称</th>
|
<th scope="col" class="px-4 py-2.5 font-medium">名称</th>
|
||||||
@@ -202,7 +202,7 @@ onMounted(load)
|
|||||||
{{ advOpen ? '收起' : '展开' }}高级选项(配额 / 白名单)
|
{{ advOpen ? '收起' : '展开' }}高级选项(配额 / 白名单)
|
||||||
</button>
|
</button>
|
||||||
<div v-if="advOpen" class="mt-3 space-y-4">
|
<div v-if="advOpen" class="mt-3 space-y-4">
|
||||||
<div class="grid grid-cols-2 gap-3">
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||||
<Input v-model="createAdv.quota_tokens_per_day" label="每日 Token 上限" placeholder="如 100000" />
|
<Input v-model="createAdv.quota_tokens_per_day" label="每日 Token 上限" placeholder="如 100000" />
|
||||||
<Input v-model="createAdv.quota_requests_per_day" label="每日请求上限" placeholder="如 1000" />
|
<Input v-model="createAdv.quota_requests_per_day" label="每日请求上限" placeholder="如 1000" />
|
||||||
</div>
|
</div>
|
||||||
@@ -220,7 +220,7 @@ onMounted(load)
|
|||||||
<Modal :open="editOpen" :title="`编辑密钥 · ${editing?.name}`" @close="editOpen = false">
|
<Modal :open="editOpen" :title="`编辑密钥 · ${editing?.name}`" @close="editOpen = false">
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<Input v-model="editForm.name" label="名称" />
|
<Input v-model="editForm.name" label="名称" />
|
||||||
<div class="grid grid-cols-2 gap-3">
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||||
<Input v-model="editForm.quota_tokens_per_day" label="每日 Token 上限" placeholder="留空则不修改" />
|
<Input v-model="editForm.quota_tokens_per_day" label="每日 Token 上限" placeholder="留空则不修改" />
|
||||||
<Input v-model="editForm.quota_requests_per_day" label="每日请求上限" placeholder="留空则不修改" />
|
<Input v-model="editForm.quota_requests_per_day" label="每日请求上限" placeholder="留空则不修改" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,6 +15,22 @@ const toast = useToastStore()
|
|||||||
|
|
||||||
const passkeys = ref<{ id: number; name: string; created_at: string }[]>([])
|
const passkeys = ref<{ id: number; name: string; created_at: string }[]>([])
|
||||||
const binding = ref(false)
|
const binding = ref(false)
|
||||||
|
const passkeyName = ref('')
|
||||||
|
|
||||||
|
// 按 UA 推断设备名,方便多设备区分
|
||||||
|
function detectPlatform(): string {
|
||||||
|
const ua = navigator.userAgent || ''
|
||||||
|
if (/iPhone|iPad|iPod/.test(ua)) return 'iPhone'
|
||||||
|
if (/Android/.test(ua)) return 'Android'
|
||||||
|
if (/Windows/.test(ua)) return 'Windows'
|
||||||
|
if (/Macintosh|Mac OS/.test(ua)) return 'Mac'
|
||||||
|
if (/Linux/.test(ua)) return 'Linux'
|
||||||
|
return 'Passkey'
|
||||||
|
}
|
||||||
|
|
||||||
|
function usePasskeyName(): string {
|
||||||
|
return passkeyName.value.trim() || detectPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
async function loadPasskeys() {
|
async function loadPasskeys() {
|
||||||
try {
|
try {
|
||||||
@@ -36,10 +52,11 @@ async function bindPasskey() {
|
|||||||
const credential = await registerPasskey(data.data.creation)
|
const credential = await registerPasskey(data.data.creation)
|
||||||
await http.post('/webauthn/register/complete', {
|
await http.post('/webauthn/register/complete', {
|
||||||
challenge: data.data.challenge,
|
challenge: data.data.challenge,
|
||||||
name: 'passkey',
|
name: usePasskeyName(),
|
||||||
credential,
|
credential,
|
||||||
})
|
})
|
||||||
toast.ok('Passkey 已绑定')
|
toast.ok('Passkey 已绑定')
|
||||||
|
passkeyName.value = ''
|
||||||
await loadPasskeys()
|
await loadPasskeys()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast.err(errMsg(e))
|
toast.err(errMsg(e))
|
||||||
@@ -97,7 +114,7 @@ async function changePassword() {
|
|||||||
|
|
||||||
<div class="card p-5">
|
<div class="card p-5">
|
||||||
<h2 class="mb-4 text-sm font-semibold">个人资料</h2>
|
<h2 class="mb-4 text-sm font-semibold">个人资料</h2>
|
||||||
<dl class="grid grid-cols-2 gap-x-6 gap-y-4 text-sm">
|
<dl class="grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-4 text-sm">
|
||||||
<div>
|
<div>
|
||||||
<dt class="text-xs text-muted">用户名</dt>
|
<dt class="text-xs text-muted">用户名</dt>
|
||||||
<dd class="mt-1 text-ink">{{ auth.user?.username }}</dd>
|
<dd class="mt-1 text-ink">{{ auth.user?.username }}</dd>
|
||||||
@@ -132,13 +149,21 @@ async function changePassword() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card p-5">
|
<div class="card p-5">
|
||||||
<div class="mb-3 flex items-center justify-between">
|
<div class="mb-3 flex flex-wrap items-center justify-between gap-2">
|
||||||
<h2 class="text-sm font-semibold">Passkey 登录</h2>
|
<h2 class="text-sm font-semibold">Passkey 登录</h2>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
v-model="passkeyName"
|
||||||
|
placeholder="设备名,如 iPhone"
|
||||||
|
class="h-8 w-32 rounded-md border border-edge2 bg-surface px-2 text-xs outline-none focus:border-accent"
|
||||||
|
@keyup.enter="bindPasskey"
|
||||||
|
/>
|
||||||
<Button size="sm" :loading="binding" @click="bindPasskey">
|
<Button size="sm" :loading="binding" @click="bindPasskey">
|
||||||
<PhFingerprint :size="14" />
|
<PhFingerprint :size="14" />
|
||||||
绑定 Passkey
|
绑定
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<p class="mb-3 text-xs text-muted">用生物识别或系统 PIN 免密登录。需要 HTTPS 或 localhost 环境。</p>
|
<p class="mb-3 text-xs text-muted">用生物识别或系统 PIN 免密登录。需要 HTTPS 或 localhost 环境。</p>
|
||||||
<ul v-if="passkeys.length" class="divide-y divide-edge">
|
<ul v-if="passkeys.length" class="divide-y divide-edge">
|
||||||
<li v-for="pk in passkeys" :key="pk.id" class="flex items-center justify-between py-2">
|
<li v-for="pk in passkeys" :key="pk.id" class="flex items-center justify-between py-2">
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ onMounted(load)
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="w-full text-sm">
|
<table class="w-full text-sm min-w-[640px]">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="border-b border-edge text-left text-xs text-muted">
|
<tr class="border-b border-edge text-left text-xs text-muted">
|
||||||
<th scope="col" class="px-4 py-2.5 font-medium">模型</th>
|
<th scope="col" class="px-4 py-2.5 font-medium">模型</th>
|
||||||
|
|||||||
Reference in New Issue
Block a user