@@ -1,305 +1,335 @@
< script setup lang = "ts" >
import { computed , onMounted , onUnmounted , ref } from 'vue' ;
import { CopyDocument } from '@element-plus/icons-vue' ;
import { computed , ref } from 'vue' ;
import { CopyDocument , Connection , Monitor , ChatLineRound , VideoPlay } from '@element-plus/icons-vue' ;
import { ElMessage } from 'element-plus' ;
// API配置
// API Configuration
const apiList = [
{ url : '/v1/chat/completions' , name : 'OpenAi Completions' } ,
{ url : '/v1/messages' , name : 'Claude Messages' } ,
{ url : '/v1/responses' , name : 'OpenAi Responses' } ,
{ url : '/v1beta/models/{model}/streamGenerateContent' , name : 'Gemini GenerateContent' } ,
{
id : 'openai' ,
name : 'OpenAI Completions' ,
url : '/v1/chat/completions' ,
method : 'POST' ,
description : 'OpenAI 经典的对话补全接口。虽然官方正逐步转向新标准,但它仍是目前生态中最通用的标准,绝大多数第三方 AI 工具和库都默认支持此协议。' ,
icon : ChatLineRound ,
requestBody : {
"messages" : [
{
"role" : "user" ,
"content" : "hi"
}
] ,
"stream" : true ,
"model" : "gpt-5.3-codex"
}
} ,
{
id : 'claude' ,
name : 'Claude Messages' ,
url : '/v1/messages' ,
method : 'POST' ,
description : 'Anthropic 官方统一的消息接口。专为 Claude 系列模型设计,支持复杂的对话交互,完美适配 Claude Code 等新一代开发工具。' ,
icon : Connection ,
requestBody : {
"messages" : [
{
"role" : "user" ,
"content" : "hi"
}
] ,
"max_tokens" : 32000 ,
"stream" : true ,
"model" : "claude-opus-4-6"
}
} ,
{
id : 'openai-resp' ,
name : 'OpenAI Responses' ,
url : '/v1/responses' ,
method : 'POST' ,
description : 'OpenAI 推出的最新一代统一响应接口。旨在提供更灵活、强大的交互能力,是未来对接 Codex 等高级模型和新特性的首选方式。' ,
icon : Monitor ,
requestBody : {
"model" : "gpt-5.3-codex" ,
"stream" : true ,
"input" : [
{ "content" : "hi" , "role" : "user" }
]
}
} ,
{
id : 'gemini' ,
name : 'Gemini GenerateContent' ,
url : '/v1beta/models/{model}/streamGenerateContent' ,
method : 'POST' ,
description : 'Google Gemini 原生生成接口。专为 Gemini 系列多模态模型打造,支持流式生成,是使用 Gemini CLI 及谷歌生态工具的最佳入口。' ,
icon : VideoPlay ,
requestBody : {
"contents" : [
{
"role" : "user" ,
"parts" : [
{
"text" : "hi"
}
]
}
]
}
} ,
] ;
const baseUrl = 'https://yxai.chat' ;
const current Index = ref ( 0 ) ;
let autoPlayTimer : ReturnType < typeof setInterval > | null = null ;
const active Index = ref ( '0' ) ;
// 当前选中的API
const currentApi = computed ( ( ) => apiList [ currentIndex . value ] ) ;
// 完整URL
const currentApi = computed ( ( ) => apiList [ Number ( activeIndex . value ) ] ) ;
const fullUrl = computed ( ( ) => ` ${ baseUrl } ${ currentApi . value . url } ` ) ;
// 切换API
function selectApi ( index : number ) {
currentIndex . value = index ;
resetAutoPlay ( ) ;
function handleSelect ( key : string ) {
activeIndex . value = key ;
}
// 复制URL
async function copyUrl ( ) {
async function copyText ( text : string ) {
try {
await navigator . clipboard . writeText ( fullUrl . value ) ;
await navigator . clipboard . writeText ( text ) ;
ElMessage . success ( '复制成功' ) ;
} catch {
ElMessage . error ( '复制失败' ) ;
}
}
// 自动轮播
function startAutoPlay ( ) {
autoPlayTimer = setInterval ( ( ) => {
currentIndex . value = ( currentIndex . value + 1 ) % apiList . length ;
} , 3000 ) ;
}
function resetAutoPlay ( ) {
if ( autoPlayTimer ) {
clearInterval ( autoPlayTimer ) ;
}
startAutoPlay ( ) ;
}
onMounted ( ( ) => {
startAutoPlay ( ) ;
} ) ;
onUnmounted ( ( ) => {
if ( autoPlayTimer ) {
clearInterval ( autoPlayTimer ) ;
}
} ) ;
< / script >
< template >
< div class = "api-page" >
< div class = "api-container " >
<!-- 标题 -- >
< h1 class = "page-title" > AI 接口地址 < / h1 >
< p class = "page-subtitle" > 支持多种主流AI接口协议 , 一键切换 < / p >
<!-- 主内容区 -- >
< div class = "content-wrapper" >
<!-- 左侧URL展示 -- >
< div class = "url-section" >
< div class = "url-card" >
< div class = "url-label" > 接口地址 < / div >
< div class = "url-display" >
< span class = "base-url" > { { baseUrl } } < / span >
< span class = "api-path" > { { currentApi . url } } < / span >
< / div >
< button class = "copy-btn" @click ="copyUrl" >
< el -icon > < CopyDocument / > < / el-icon >
复制
< / button >
< / div >
< el-container class = "h-full " >
<!-- Desktop Sidebar -- >
< el-aside width = "280px" class = "api-sidebar hidden-sm-and-down" >
< div class = "sidebar-header" >
< h2 class = "text-lg font-bold m-0" > API 接口文档 < / h2 >
< p class = "text-xs text-gray-500 mt-1" > 开发者接入指南 < / p >
< / div >
<!-- 右侧按钮列表 -- >
< div class = "api-buttons" >
< button
< el-menu
:default-active = "activeIndex"
class = "api-menu"
@select ="handleSelect"
>
< el-menu-item
v-for = "(api, index) in apiList"
:key = "index"
class = "api-btn "
: class = "{ active: currentIndex === index }"
@click ="selectApi(index)"
:index = "index.toString() "
>
{ { api . name } }
< / butto n>
< / div >
< / div >
< el-icon > < component :is = "api.icon" / > < / el-icon >
< span > { { api . name } } < / spa n>
< / el-menu-item >
< / el-menu >
< / el-aside >
<!-- 进度指示器 -- >
< div class = "progress-dots" >
< span
v-for = "(_, index) in apiList"
:key = "index"
class = "dot"
: class = "{ active: currentIndex === index } "
@click ="selectApi( index) "
/ >
< / div >
< / div >
< el-main class = "api-main" >
<!-- Mobile Select -- >
< div class = "hidden-md-and-up mb-6" >
< h2 class = "text-lg font-bold mb-4" > API 接口文档 < / h2 >
< el-select v-model = "activeIndex" placeholder="Select API" class="w-full" @change="handleSelect" >
< el -option
v-for = "(api, index) in apiList "
:key = " index"
:label = "api.name"
:value = "index.toString()"
/ >
< / el-select >
< / div >
< div class = "content-container" >
< el-alert
title = "接口兼容性重要提示"
type = "warning"
show -icon
:closable = "false"
class = "api-warning-alert"
>
< template # default >
< div class = "leading-normal text-sm" >
自 2025 年末起 , AI 领域接口标准逐渐分化 , 原有的统一接口 < code class = "bg-yellow-100 dark:bg-yellow-900 px-1 rounded" > / v1 / chat / completions < / code > 已不再兼容所有模型 。 各厂商推出的新接口差异较大 , 接入第三方工具时 , 请务必根据具体模型选择正确的 API 类型 。 您可前往
< router-link to = "/model-library" class = "text-primary font-bold hover:underline" > 模型库 < / router-link >
查看各模型对应的 API 信息 。
< / div >
< / template >
< / el-alert >
< div class = "mb-6" >
< div class = "flex items-center gap-3 mb-2" >
< el-icon :size = "24" class = "text-primary" > < component :is = "currentApi.icon" / > < / el-icon >
< h1 class = "text-xl font-bold m-0" > { { currentApi . name } } < / h1 >
< / div >
< p class = "text-gray-500 dark:text-gray-400 leading-relaxed text-sm" > { { currentApi . description } } < / p >
< / div >
< el-card class = "box-card mb-4" shadow = "hover" >
< template # header >
< div class = "card-header flex justify-between items-center py-1" >
< span class = "font-bold text-sm" > 接口详情 < / span >
< el-tag : type = "currentApi.method === 'POST' ? 'success' : 'warning'" effect = "dark" round size = "small" >
{ { currentApi . method } }
< / el-tag >
< / div >
< / template >
< div class = "api-detail-item" >
< div class = "label mb-2 text-xs font-medium text-gray-500" > 请求地址 ( Endpoint ) < / div >
< div class = "url-box" >
< div class = "url-content" >
< span class = "base-url" title = "Base URL" > { { baseUrl } } < / span >
< span class = "api-path" title = "Path" > { { currentApi . url } } < / span >
< / div >
< div class = "url-actions" >
< el-tooltip content = "复制 Base URL" placement = "top" >
< el-button link @click ="copyText(baseUrl)" size = "small" >
< span class = "text-xs font-mono" > Base < / span >
< / el-button >
< / el-tooltip >
< el-divider direction = "vertical" / >
< el-tooltip content = "复制完整地址" placement = "top" >
< el-button link type = "primary" @click ="copyText(fullUrl)" size = "small" >
< el-icon > < CopyDocument / > < / el-icon >
< / el-button >
< / el-tooltip >
< / div >
< / div >
< / div >
< / el-card >
< el-card class = "box-card" shadow = "hover" >
< template # header >
< div class = "card-header py-1" >
< span class = "font-bold text-sm" > 调用示例 ( cURL ) < / span >
< / div >
< / template >
< div class = "code-block bg-gray-50 dark:bg-[#161b22] p-3 rounded-md border border-gray-200 dark:border-gray-700" >
< pre class = "text-xs overflow-x-auto font-mono m-0" > < code class = "language-bash" > curl { { fullUrl } } \
- H "Content-Type: application/json" \
- H "Authorization: Bearer YOUR_API_KEY" \
- d '{{ JSON.stringify(currentApi.requestBody, null, 2) }}' < / code > < / pre >
< / div >
< / el-card >
< / div >
< / el-main >
< / el-container >
< / div >
< / template >
< style scoped lang = "scss" >
. api - page {
min - height : 100 % ;
display : flex ;
align - items : center ;
justify - content : center ;
padding : 40 px 20 px ;
background : linear - gradient ( 135 deg , # 667 eea 0 % , # 764 ba2 100 % ) ;
}
. api - container {
width : 100 % ;
max - width : 900 px ;
padding : 50 px ;
background : rgba ( 255 , 255 , 255 , 0.15 ) ;
backdrop - filter : blur ( 20 px ) ;
border - radius : 24 px ;
border : 1 px solid rgba ( 255 , 255 , 255 , 0.2 ) ;
box - shadow : 0 8 px 32 px rgba ( 0 , 0 , 0 , 0.1 ) ;
}
. page - title {
text - align : center ;
font - size : 36 px ;
font - weight : 700 ;
color : # fff ;
margin : 0 0 10 px 0 ;
text - shadow : 0 2 px 4 px rgba ( 0 , 0 , 0 , 0.1 ) ;
}
. page - subtitle {
text - align : center ;
font - size : 16 px ;
color : rgba ( 255 , 255 , 255 , 0.8 ) ;
margin : 0 0 40 px 0 ;
}
. content - wrapper {
display : flex ;
gap : 30 px ;
align - items : stretch ;
}
. url - section {
flex : 1 ;
}
. url - card {
position : relative ;
background : rgba ( 255 , 255 , 255 , 0.95 ) ;
border - radius : 16 px ;
padding : 30 px ;
height : 100 % ;
background - color : var ( -- bg - color - tertiary ) ;
display : flex ;
flex - direction : column ;
box - shadow : 0 4 px 20 px rgba ( 0 , 0 , 0 , 0.1 ) ;
overflow : hidden ;
}
. url - label {
font - size : 14 px ;
color : # 666 ;
margin - bottom : 15 px ;
font - weight : 500 ;
}
. url - display {
flex : 1 ;
. api - sidebar {
background - color : var ( -- bg - color - primary ) ;
border - right : 1 px solid var ( -- border - color - light ) ;
display : flex ;
flex - direction : column ;
gap : 8 px ;
font - family : 'Monaco' , 'Menlo' , monospace ;
word - break : break - all ;
. sidebar - header {
padding : 16 px 20 px ;
border - bottom : 1 px solid var ( -- border - color - light ) ;
}
. api - menu {
border - right : none ;
background - color : transparent ;
flex : 1 ;
overflow - y : auto ;
padding : 8 px 0 ;
: deep ( . el - menu - item ) {
border - radius : 8 px ;
margin : 2 px 10 px ;
height : 40 px ;
& . is - active {
background - color : var ( -- el - color - primary - light - 9 ) ;
color : var ( -- el - color - primary ) ;
font - weight : 600 ;
}
& : hover : not ( . is - active ) {
background - color : var ( -- el - fill - color - light ) ;
}
}
}
}
. base - url {
font - size : 18 px ;
c olor : # 409 eff ;
font - weight : 600 ;
. api - main {
padding : 24 px ;
overf low - y : auto ;
}
. api - path {
font - size : 16 px ;
color : # 333 ;
padding : 12 px ;
background : # f5f7fa ;
border - radius : 8 px ;
transition : all 0.3 s ease ;
. content - container {
max - width : 900 px ;
margin : 0 auto ;
}
. copy - btn {
position : absolute ;
top : 15 px ;
right : 15 px ;
. text - primary {
color : var ( -- el - color - primary ) ;
}
. url - box {
display : flex ;
align - items : center ;
gap : 6 px ;
padding : 8 px 16 px ;
background : # 409 eff ;
color : # fff ;
border : none ;
justify - content : space - between ;
background - color : var ( -- el - fill - color - light ) ;
border : 1 px solid var ( -- el - border - color ) ;
border - radius : 8 px ;
cursor : pointer ;
font - size : 14 px ;
transition : all 0.3 s ease ;
& : hover {
background : # 66 b1ff ;
transform : translateY ( - 2 px ) ;
}
}
. api - buttons {
display : flex ;
flex - direction : column ;
padding : 12 px 16 px ;
gap : 12 px ;
min - width : 220 px ;
}
. api - btn {
padding : 16 px 24 px ;
background : rgba ( 255 , 255 , 255 , 0.2 ) ;
border : 2 px solid rgba ( 255 , 255 , 255 , 0.3 ) ;
border - radius : 12 px ;
color : # fff ;
font - size : 15 px ;
font - weight : 500 ;
cursor : pointer ;
transition : all 0.3 s ease ;
text - align : left ;
& : hover {
background : rgba ( 255 , 255 , 255 , 0.3 ) ;
transform : translateX ( 5 px ) ;
. url - content {
font - family : 'Monaco' , 'Menlo' , 'Consolas' , monospace ;
font - size : 14 px ;
word - break : break - all ;
line - height : 1.5 ;
. base - url {
color : var ( -- el - text - color - secondary ) ;
}
. api - path {
color : var ( -- el - color - primary ) ;
font - weight : 600 ;
}
}
& . active {
background : # fff ;
color : # 667 eea ;
border - color : # fff ;
box - shadow : 0 4 px 15 px rgba ( 0 , 0 , 0 , 0.15 ) ;
}
}
. progress - dots {
display : flex ;
justify - content : center ;
gap : 10 px ;
margin - top : 30 px ;
}
. dot {
width : 10 px ;
height : 10 px ;
border - radius : 50 % ;
background : rgba ( 255 , 255 , 255 , 0.4 ) ;
cursor : pointer ;
transition : all 0.3 s ease ;
& : hover {
background : rgba ( 255 , 255 , 255 , 0.7 ) ;
}
& . active {
background : # fff ;
transform : scale ( 1.3 ) ;
. url - actions {
display : flex ;
align - items : center ;
flex - shrink : 0 ;
}
}
/* Utility classes for responsiveness if unocss/tailwind not fully available in this scope */
@ media ( max - width : 768 px ) {
. api - container {
padding : 30 px 20 px ;
. hidden - sm - and - down {
display : none ! important ;
}
. hidden - md - and - up {
display : block ! important ;
}
. api - main {
padding : 20 px ;
}
}
. page - title {
font - size : 28 px ;
@ media ( min - width : 769 px ) {
. hidden - md - and - up {
display : none ! important ;
}
}
. content - wrapp er {
flex - direction : column ;
}
. api - buttons {
min - width : auto ;
}
. api - btn {
text - align : center ;
}
. api - warning - al ert {
margin - bottom : 20 px ;
}
< / style >