Files
openteam/web/src/views/LandingView.vue
T
Sakurasan c78a473e59 feat: API Key 前缀改为 sk-ot
- apikey 包 prefix 常量 sk- → sk-ot(生成/校验/展示前缀统一驱动)
- 鉴权错误提示同步更新为 sk-ot 格式
- 测试断言改用常量,避免硬编码长度
- 前端 curl 示例与 README/PLANNING 文档同步
2026-08-25 00:34:50 +08:00

181 lines
8.9 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 { useAuthStore } from '@/stores/auth'
import ThemeToggle from '@/components/ui/ThemeToggle.vue'
const auth = useAuthStore()
// 调用演示用浏览器当前 host(兼容端点),避免写死域名
const host = window.location.host
const baseURL = `${window.location.origin}/v1`
</script>
<template>
<div class="min-h-[100dvh] bg-bg text-ink">
<!-- 导航 -->
<header class="sticky top-0 z-40 border-b border-edge bg-bg backdrop-blur">
<div class="mx-auto flex h-14 max-w-6xl items-center justify-between px-4">
<div class="flex items-center gap-2">
<img src="/favicon.svg" alt="" class="size-5" />
<span class="text-sm font-semibold tracking-tight">openteam</span>
</div>
<nav class="flex items-center gap-1.5 sm:gap-2">
<ThemeToggle />
<router-link
v-if="!auth.isAuthed"
to="/login"
class="rounded-md px-2.5 py-1.5 text-sm text-muted transition hover:text-ink sm:px-3"
>
登录
</router-link>
<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
v-if="!auth.isAuthed"
to="/register"
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>
</nav>
</div>
</header>
<!-- Hero:左文案 + 右真实调用演示 -->
<section class="relative overflow-hidden">
<div class="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-emerald-500/40 to-transparent" />
<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">
<p class="mb-3 font-mono text-xs tracking-wide text-accent">LLM API 中转网关</p>
<h1 class="text-3xl leading-tight font-semibold tracking-tight sm:text-4xl md:text-5xl">
一个 Key,调用所有主流模型
</h1>
<p class="mt-5 max-w-md text-base leading-relaxed text-muted">
统一 OpenAI 与 Anthropic 协议入口,三套 API 自动互转,用量、计费与 API Key 管理开箱即用。
</p>
<div class="mt-8 flex items-center gap-3">
<router-link
to="/register"
class="inline-flex h-10 items-center rounded-md bg-accent px-5 text-sm font-medium text-accent-ink transition hover:bg-accent-strong active:scale-[0.98]"
>
免费注册
</router-link>
<router-link
to="/login"
class="inline-flex h-10 items-center rounded-md border border-edge2 px-5 text-sm text-ink transition hover:border-edge2"
>
登录
</router-link>
</div>
<p class="mt-5 font-mono text-xs text-muted">不用换 SDK,改一行 base_url 即可接入</p>
</div>
<!-- 调用演示(真实格式,非伪截图) -->
<div class="card overflow-hidden font-mono text-xs">
<div class="flex items-center gap-1.5 border-b border-edge px-4 py-2.5">
<span class="size-2.5 rounded-full bg-surface2" />
<span class="size-2.5 rounded-full bg-surface2" />
<span class="ml-2 text-muted">curl {{ host }}</span>
</div>
<div class="space-y-3 p-4 leading-relaxed">
<div>
<p class="text-muted"><span class="text-accent">$</span> curl {{ baseURL }}/chat/completions</p>
<p class="text-muted"> -H <span class="text-accent">"Authorization: Bearer sk-ot..."</span> \</p>
<p class="text-muted"> -d <span class="text-ink">'{"model": "claude-sonnet-5", "messages": [{"role": "user", "content": "你好"}]}'</span></p>
</div>
<div class="border-t border-edge pt-3 text-muted">
<p class="text-muted"># OpenAI 格式请求,网关自动转 Anthropic 协议</p>
<p class="text-ink">data: {"id":"resp_1","model":"claude-sonnet-5","choices":[{</p>
<p class="text-ink">&nbsp;&nbsp;"delta":{"content":"你好,这是流式回复"}</p>
<p class="text-ink">}]}</p>
<p class="text-ink">data: [DONE]</p>
</div>
</div>
</div>
</div>
</section>
<!-- 协议入口 -->
<section class="border-t border-edge">
<div class="mx-auto max-w-6xl px-4 py-16">
<h2 class="text-2xl font-semibold tracking-tight">三套协议,一个入口</h2>
<p class="mt-2 max-w-xl text-sm text-muted">
对客户端暴露统一的 OpenAI 兼容入口;客户端协议与上游渠道不匹配时自动转换,无需关心背后接的是哪家。
</p>
<div class="card mt-8 divide-y divide-edge">
<div v-for="p in [
{ path: 'POST /v1/chat/completions', desc: 'OpenAI Chat,兼容面最广,SDK 与工具链最全', tag: 'OpenAI' },
{ path: 'POST /v1/responses', desc: 'OpenAI Responses,新一代 SDK 与 Agents 首选', tag: 'OpenAI' },
{ path: 'POST /v1/messages', desc: 'Anthropic Messages,Claude 生态原生格式', tag: 'Anthropic' },
{ path: 'GET /v1/models', desc: 'OpenAI 风格模型列表', tag: 'List' },
]" :key="p.path" class="grid gap-1 px-5 py-3.5 sm:grid-cols-3 sm:items-center">
<code class="font-mono text-sm text-accent">{{ p.path }}</code>
<p class="text-sm text-muted sm:col-span-1">{{ p.desc }}</p>
<span class="hidden justify-self-end font-mono text-[11px] text-muted sm:block">{{ p.tag }}</span>
</div>
</div>
</div>
</section>
<!-- 网关能力 -->
<section class="border-t border-edge">
<div class="mx-auto max-w-6xl px-4 py-16">
<h2 class="text-2xl font-semibold tracking-tight">网关替你处理的事</h2>
<div class="mt-8 grid gap-4 lg:grid-cols-3">
<div class="card p-5 lg:col-span-2">
<p class="font-mono text-xs text-accent">responses → claude-sonnet-5</p>
<h3 class="mt-2 text-lg font-semibold">协议自动转换</h3>
<p class="mt-2 text-sm leading-relaxed text-muted">
客户端按 Responses 调用 Claude 模型,网关转成 Anthropic 协议打给上游,再以 Responses 事件流式返回。直通优先,能力无损时零转换。
</p>
</div>
<div class="card p-5">
<p class="font-mono text-xs text-muted">usage · daily</p>
<h3 class="mt-2 text-lg font-semibold">用量与计费</h3>
<p class="mt-2 text-sm leading-relaxed text-muted">
请求级 token 统计,按模型价格自动扣费,日粒度报表与余额流水可追溯。
</p>
</div>
<div class="card p-5">
<p class="font-mono text-xs text-muted">sk-ot…</p>
<h3 class="mt-2 text-lg font-semibold">API Key 管理</h3>
<p class="mt-2 text-sm leading-relaxed text-muted">
密钥仅存哈希,支持配额、过期与模型白名单,创建时一次性展示。
</p>
</div>
<div class="card p-5 lg:col-span-2">
<p class="font-mono text-xs text-muted">channels · lb · health</p>
<h3 class="mt-2 text-lg font-semibold">多渠道接入</h3>
<p class="mt-2 text-sm leading-relaxed text-muted">
一个模型绑定多个上游渠道,按权重与健康状态选择,故障自动转移。管理员在后台一键接入新渠道、导入模型并定价。
</p>
</div>
</div>
</div>
</section>
<!-- CTA -->
<section class="border-t border-edge">
<div class="mx-auto max-w-6xl px-4 py-20 text-center">
<h2 class="text-2xl font-semibold tracking-tight">自托管,密钥在自己手里</h2>
<p class="mx-auto mt-3 max-w-md text-sm text-muted">Docker Compose 一键部署,PostgreSQL 存账,渠道密钥加密存储。</p>
<router-link
to="/register"
class="mt-8 inline-flex h-10 items-center rounded-md bg-accent px-6 text-sm font-medium text-accent-ink transition hover:bg-accent-strong active:scale-[0.98]"
>
开始使用
</router-link>
</div>
</section>
<footer class="border-t border-edge">
<div class="mx-auto flex max-w-6xl items-center justify-between px-4 py-6 text-xs text-muted">
<div class="flex items-center gap-2">
<img src="/favicon.svg" alt="" class="size-4" />
<span>openteam · LLM API 中转站</span>
</div>
<span class="font-mono">© 2026</span>
</div>
</footer>
</div>
</template>