重构充值页面和统一控制台页面风格
- 充值页面:全新设计余额概览、预设金额卡片、支付方式、兑换码区域 - 控制台主页:移除灰色背景,统一页面边距和宽度 - API测速页:移至控制台下,调整字体大小和间距 - 侧边栏:新增API测速菜单入口 - 修复个人设置页TwoFASetting组件缺少IconShield导入 - 多个页面统一顶部间距和背景样式
This commit is contained in:
parent
44356571a6
commit
ac1120fc33
|
|
@ -18,6 +18,38 @@ For commercial licensing, please contact support@quantumnous.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { lazy, Suspense, useContext, useMemo } from 'react';
|
import React, { lazy, Suspense, useContext, useMemo } from 'react';
|
||||||
|
|
||||||
|
class ErrorBoundary extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = { hasError: false, error: null, info: null };
|
||||||
|
}
|
||||||
|
static getDerivedStateFromError(error) {
|
||||||
|
return { hasError: true, error };
|
||||||
|
}
|
||||||
|
componentDidCatch(error, info) {
|
||||||
|
this.setState({ info });
|
||||||
|
console.error('ErrorBoundary caught:', error, info);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
if (this.state.hasError) {
|
||||||
|
return (
|
||||||
|
<div style={{ padding: 40, color: 'red', fontFamily: 'monospace', whiteSpace: 'pre-wrap' }}>
|
||||||
|
<h2>页面崩溃: {this.state.error?.message}</h2>
|
||||||
|
<details>
|
||||||
|
<summary>Stack</summary>
|
||||||
|
<pre>{this.state.error?.stack}</pre>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Component Stack</summary>
|
||||||
|
<pre>{this.state.info?.componentStack}</pre>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
}
|
||||||
import { Route, Routes, useLocation, useParams } from 'react-router-dom';
|
import { Route, Routes, useLocation, useParams } from 'react-router-dom';
|
||||||
import Loading from './components/common/ui/Loading';
|
import Loading from './components/common/ui/Loading';
|
||||||
import User from './pages/User';
|
import User from './pages/User';
|
||||||
|
|
@ -352,9 +384,11 @@ function App() {
|
||||||
path='/console/personal'
|
path='/console/personal'
|
||||||
element={
|
element={
|
||||||
<PrivateRoute>
|
<PrivateRoute>
|
||||||
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
<ErrorBoundary>
|
||||||
<PersonalSetting />
|
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
|
||||||
</Suspense>
|
<PersonalSetting />
|
||||||
|
</Suspense>
|
||||||
|
</ErrorBoundary>
|
||||||
</PrivateRoute>
|
</PrivateRoute>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,7 @@ const Dashboard = () => {
|
||||||
const { unreadCount } = useUserMessageUnreadCount(user);
|
const { unreadCount } = useUserMessageUnreadCount(user);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='min-h-full bg-slate-50 pb-16 text-slate-900 dark:bg-neutral-950 dark:text-white'>
|
<div className='flex flex-col gap-6 pb-8'>
|
||||||
<div className='mx-auto w-full max-w-[1400px] px-4 sm:px-6 lg:px-10'>
|
|
||||||
<TopBar
|
<TopBar
|
||||||
onSearch={() => {}}
|
onSearch={() => {}}
|
||||||
onRefresh={dashboard.refresh}
|
onRefresh={dashboard.refresh}
|
||||||
|
|
@ -60,7 +59,7 @@ const Dashboard = () => {
|
||||||
unreadCount={unreadCount}
|
unreadCount={unreadCount}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='space-y-6 pt-8 pb-8'>
|
<div className='space-y-6 pb-8'>
|
||||||
<Hero user={user} />
|
<Hero user={user} />
|
||||||
|
|
||||||
{/* 第一行:5 个核心指标卡 */}
|
{/* 第一行:5 个核心指标卡 */}
|
||||||
|
|
@ -97,7 +96,6 @@ const Dashboard = () => {
|
||||||
<div className='flex items-center justify-center border-t border-slate-200 py-6 text-xs text-slate-400 dark:border-white/10 dark:text-white/30'>
|
<div className='flex items-center justify-center border-t border-slate-200 py-6 text-xs text-slate-400 dark:border-white/10 dark:text-white/30'>
|
||||||
<span>{getSystemName()} · 2026</span>
|
<span>{getSystemName()} · 2026</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ const routerMap = {
|
||||||
'model-heat': '/console/model-heat',
|
'model-heat': '/console/model-heat',
|
||||||
playground: '/console/playground',
|
playground: '/console/playground',
|
||||||
benchmarks: '/benchmarks',
|
benchmarks: '/benchmarks',
|
||||||
|
'api-tester': '/console/api-tester',
|
||||||
personal: '/console/personal',
|
personal: '/console/personal',
|
||||||
supplier: null,
|
supplier: null,
|
||||||
distributor: '/console/distributor/admin',
|
distributor: '/console/distributor/admin',
|
||||||
|
|
@ -90,6 +91,11 @@ const SiderBar = ({ onNavigate = () => {} }) => {
|
||||||
itemKey: 'benchmarks',
|
itemKey: 'benchmarks',
|
||||||
to: '/benchmarks',
|
to: '/benchmarks',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: t('API 测速'),
|
||||||
|
itemKey: 'api-tester',
|
||||||
|
to: '/api-tester',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: t('数据看板'),
|
text: t('数据看板'),
|
||||||
itemKey: 'detail',
|
itemKey: 'detail',
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import {
|
||||||
IconAlertTriangle,
|
IconAlertTriangle,
|
||||||
IconRefresh,
|
IconRefresh,
|
||||||
IconCopy,
|
IconCopy,
|
||||||
|
IconShield,
|
||||||
} from '@douyinfe/semi-icons';
|
} from '@douyinfe/semi-icons';
|
||||||
import { ScanFace } from 'lucide-react';
|
import { ScanFace } from 'lucide-react';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -864,7 +864,7 @@ const TopUp = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='mx-auto w-full max-w-[1400px] px-4 pb-16 sm:px-6 lg:px-10'>
|
<div className='mx-auto w-full max-w-[1400px] px-4 pb-16 pt-20 sm:px-6 lg:px-10'>
|
||||||
{/* 划转模态框 */}
|
{/* 划转模态框 */}
|
||||||
<TransferModal
|
<TransferModal
|
||||||
t={t}
|
t={t}
|
||||||
|
|
|
||||||
|
|
@ -308,16 +308,16 @@ const ApiTester = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='min-h-full bg-slate-50 pb-16 text-slate-900 dark:bg-neutral-950 dark:text-white'>
|
<div className='min-h-full pb-16 text-slate-900 dark:text-white'>
|
||||||
<div className='mx-auto w-full max-w-[1400px] px-4 sm:px-6 lg:px-10'>
|
<div className='mx-auto w-full max-w-[1400px] px-4 pt-20 sm:px-6 lg:px-10'>
|
||||||
<div className='space-y-6 pt-8 pb-8'>
|
<div className='space-y-8 pb-8'>
|
||||||
{/* 页面标题区 */}
|
{/* 页面标题区 */}
|
||||||
<div className='flex flex-wrap items-end justify-between gap-4'>
|
<div className='flex flex-wrap items-end justify-between gap-4'>
|
||||||
<div>
|
<div>
|
||||||
<h1 className='text-3xl font-bold tracking-tight text-slate-900 md:text-4xl dark:text-white'>
|
<h1 className='text-3xl font-bold tracking-tight text-slate-900 md:text-4xl dark:text-white'>
|
||||||
API 快速测试
|
API 快速测试
|
||||||
</h1>
|
</h1>
|
||||||
<p className='mt-2 text-sm text-slate-500 dark:text-white/50'>
|
<p className='mt-2 text-xs text-slate-500 dark:text-white/50'>
|
||||||
当前协议:{format === 'anthropic' ? 'Anthropic Messages' : 'OpenAI Chat Completions'} · 请求地址 {finalEndpoint}
|
当前协议:{format === 'anthropic' ? 'Anthropic Messages' : 'OpenAI Chat Completions'} · 请求地址 {finalEndpoint}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -330,14 +330,14 @@ const ApiTester = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 第一行:API Key / 测试目标 / 模型 */}
|
{/* 第一行:API Key / 测试目标 / 模型 */}
|
||||||
<div className='grid grid-cols-1 gap-5 lg:grid-cols-3'>
|
<div className='grid grid-cols-1 gap-6 lg:grid-cols-3'>
|
||||||
{/* API Key 输入卡片 */}
|
{/* API Key 输入卡片 */}
|
||||||
<div className='rounded-2xl border border-slate-200 bg-white p-5 transition-shadow hover:shadow-md dark:border-white/5 dark:bg-white/[0.02] dark:hover:shadow-black/20'>
|
<div className='rounded-2xl border border-slate-200 bg-white p-6 transition-shadow hover:shadow-md dark:border-white/10 dark:bg-white/[0.02] dark:hover:shadow-black/20'>
|
||||||
<div className='mb-3 flex items-center gap-2'>
|
<div className='mb-3 flex items-center gap-2'>
|
||||||
<div className='flex h-8 w-8 items-center justify-center rounded-lg bg-blue-50 text-blue-600 dark:bg-blue-500/10 dark:text-blue-400'>
|
<div className='flex h-8 w-8 items-center justify-center rounded-lg bg-blue-50 text-blue-600 dark:bg-blue-500/10 dark:text-blue-400'>
|
||||||
<KeyRound size={15} />
|
<KeyRound size={15} />
|
||||||
</div>
|
</div>
|
||||||
<div className='text-sm font-semibold text-slate-900 dark:text-white'>API Key</div>
|
<div className='text-xs font-semibold text-slate-900 dark:text-white'>API Key</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
<input
|
<input
|
||||||
|
|
@ -354,25 +354,25 @@ const ApiTester = () => {
|
||||||
{showKey ? <EyeOff size={14} /> : <Eye size={14} />}
|
{showKey ? <EyeOff size={14} /> : <Eye size={14} />}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className='mt-2 text-[11px] text-slate-400 dark:text-white/40'>
|
<div className='mt-2 text-xs text-slate-400 dark:text-white/40'>
|
||||||
{user?.token ? '已自动填充当前登录用户的 Token' : '请填写你的 API Key'}
|
{user?.token ? '已自动填充当前登录用户的 Token' : '请填写你的 API Key'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 测试目标选择卡片 */}
|
{/* 测试目标选择卡片 */}
|
||||||
<div className='rounded-2xl border border-slate-200 bg-white p-5 transition-shadow hover:shadow-md dark:border-white/5 dark:bg-white/[0.02] dark:hover:shadow-black/20'>
|
<div className='rounded-2xl border border-slate-200 bg-white p-6 transition-shadow hover:shadow-md dark:border-white/10 dark:bg-white/[0.02] dark:hover:shadow-black/20'>
|
||||||
<div className='mb-3 flex items-center justify-between'>
|
<div className='mb-3 flex items-center justify-between'>
|
||||||
<div className='flex items-center gap-2'>
|
<div className='flex items-center gap-2'>
|
||||||
<div className='flex h-8 w-8 items-center justify-center rounded-lg bg-blue-50 text-blue-600 dark:bg-blue-500/10 dark:text-blue-400'>
|
<div className='flex h-8 w-8 items-center justify-center rounded-lg bg-blue-50 text-blue-600 dark:bg-blue-500/10 dark:text-blue-400'>
|
||||||
<Globe size={15} />
|
<Globe size={15} />
|
||||||
</div>
|
</div>
|
||||||
<div className='text-sm font-semibold text-slate-900 dark:text-white'>
|
<div className='text-xs font-semibold text-slate-900 dark:text-white'>
|
||||||
测试目标
|
测试目标
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowCustomBase((v) => !v)}
|
onClick={() => setShowCustomBase((v) => !v)}
|
||||||
className='inline-flex items-center gap-1 text-[11px] text-slate-400 transition-colors hover:text-slate-700 dark:text-white/40 dark:hover:text-white'
|
className='inline-flex items-center gap-1 text-xs text-slate-400 transition-colors hover:text-slate-700 dark:text-white/40 dark:hover:text-white'
|
||||||
title='切换自定义域名'
|
title='切换自定义域名'
|
||||||
>
|
>
|
||||||
{showCustomBase ? '收起域名' : '换个平台'}
|
{showCustomBase ? '收起域名' : '换个平台'}
|
||||||
|
|
@ -386,10 +386,10 @@ const ApiTester = () => {
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
return (
|
return (
|
||||||
<div className='space-y-2.5'>
|
<div className='space-y-3'>
|
||||||
{Object.entries(grouped).map(([group, items]) => (
|
{Object.entries(grouped).map(([group, items]) => (
|
||||||
<div key={group}>
|
<div key={group}>
|
||||||
<div className='mb-1.5 text-[10px] font-medium uppercase tracking-wider text-slate-400 dark:text-white/40'>
|
<div className='mb-1.5 text-[11px] font-medium uppercase tracking-wider text-slate-400 dark:text-white/40'>
|
||||||
{group}
|
{group}
|
||||||
</div>
|
</div>
|
||||||
<div className='flex flex-wrap gap-1.5'>
|
<div className='flex flex-wrap gap-1.5'>
|
||||||
|
|
@ -397,7 +397,7 @@ const ApiTester = () => {
|
||||||
<button
|
<button
|
||||||
key={s.id}
|
key={s.id}
|
||||||
onClick={() => applyScene(s)}
|
onClick={() => applyScene(s)}
|
||||||
className='inline-flex items-center gap-1.5 rounded-full border border-slate-200 bg-white px-3 py-1.5 text-[11px] font-medium text-slate-600 transition hover:border-blue-400 hover:bg-blue-50 hover:text-blue-600 dark:border-white/10 dark:bg-white/[0.02] dark:text-white/70 dark:hover:border-blue-400 dark:hover:bg-blue-500/10 dark:hover:text-blue-400'
|
className='inline-flex items-center gap-1.5 rounded-full border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-600 transition hover:border-blue-400 hover:bg-blue-50 hover:text-blue-600 dark:border-white/10 dark:bg-white/[0.02] dark:text-white/70 dark:hover:border-blue-400 dark:hover:bg-blue-500/10 dark:hover:text-blue-400'
|
||||||
>
|
>
|
||||||
<s.Icon size={11} /> {s.label}
|
<s.Icon size={11} /> {s.label}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -408,18 +408,18 @@ const ApiTester = () => {
|
||||||
|
|
||||||
<div className='border-t border-slate-100 pt-2.5 dark:border-white/5'>
|
<div className='border-t border-slate-100 pt-2.5 dark:border-white/5'>
|
||||||
<div className='mb-1.5 flex items-center justify-between'>
|
<div className='mb-1.5 flex items-center justify-between'>
|
||||||
<div className='text-[10px] font-medium uppercase tracking-wider text-slate-400 dark:text-white/40'>
|
<div className='text-[11px] font-medium uppercase tracking-wider text-slate-400 dark:text-white/40'>
|
||||||
我的目标
|
我的目标
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={saveCurrentAsCustom}
|
onClick={saveCurrentAsCustom}
|
||||||
className='inline-flex items-center gap-1 rounded-full border border-slate-200 bg-white px-2.5 py-1 text-[10px] font-medium text-slate-600 transition hover:border-blue-400 hover:text-blue-600 dark:border-white/10 dark:bg-white/[0.02] dark:text-white/70 dark:hover:text-blue-400'
|
className='inline-flex items-center gap-1 rounded-full border border-slate-200 bg-white px-2.5 py-1 text-xs font-medium text-slate-600 transition hover:border-blue-400 hover:text-blue-600 dark:border-white/10 dark:bg-white/[0.02] dark:text-white/70 dark:hover:text-blue-400'
|
||||||
>
|
>
|
||||||
<Plus size={10} /> 保存当前
|
<Plus size={10} /> 保存当前
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{customScenes.length === 0 ? (
|
{customScenes.length === 0 ? (
|
||||||
<div className='text-[11px] text-slate-400 dark:text-white/40'>
|
<div className='text-xs text-slate-400 dark:text-white/40'>
|
||||||
调整完地址后,点右上「保存当前」即可收藏到本地
|
调整完地址后,点右上「保存当前」即可收藏到本地
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -431,7 +431,7 @@ const ApiTester = () => {
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
onClick={() => applyScene(s)}
|
onClick={() => applyScene(s)}
|
||||||
className='inline-flex items-center gap-1.5 px-3 py-1.5 text-[11px] font-medium text-slate-600 transition hover:bg-blue-50 hover:text-blue-600 dark:text-white/70 dark:hover:bg-blue-500/10 dark:hover:text-blue-400'
|
className='inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-slate-600 transition hover:bg-blue-50 hover:text-blue-600 dark:text-white/70 dark:hover:bg-blue-500/10 dark:hover:text-blue-400'
|
||||||
>
|
>
|
||||||
<Bookmark size={11} /> {s.label}
|
<Bookmark size={11} /> {s.label}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -452,14 +452,14 @@ const ApiTester = () => {
|
||||||
})()}
|
})()}
|
||||||
|
|
||||||
<div className='mt-3'>
|
<div className='mt-3'>
|
||||||
<label className='mb-1.5 block text-[11px] font-medium text-slate-500 dark:text-white/50'>
|
<label className='mb-1.5 block text-xs font-medium text-slate-500 dark:text-white/50'>
|
||||||
完整请求地址
|
完整请求地址
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
value={isAbsoluteEndpoint ? endpointPath : `${endpointBase}${endpointPath}`}
|
value={isAbsoluteEndpoint ? endpointPath : `${endpointBase}${endpointPath}`}
|
||||||
onChange={(e) => applyFullUrl(e.target.value)}
|
onChange={(e) => applyFullUrl(e.target.value)}
|
||||||
placeholder='https://你的平台域名/v1/chat/completions'
|
placeholder='https://你的平台域名/v1/chat/completions'
|
||||||
className='w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 font-mono text-[11px] text-slate-900 outline-none transition focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-500/20 dark:border-white/10 dark:bg-white/[0.04] dark:text-white dark:focus:border-blue-400 dark:focus:bg-white/[0.06]'
|
className='w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 font-mono text-xs text-slate-900 outline-none transition focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-500/20 dark:border-white/10 dark:bg-white/[0.04] dark:text-white dark:focus:border-blue-400 dark:focus:bg-white/[0.06]'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -480,29 +480,29 @@ const ApiTester = () => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className='mt-3 flex items-center gap-1.5 truncate font-mono text-[11px] text-slate-400 dark:text-white/40'>
|
<div className='mt-3 flex items-center gap-1.5 truncate font-mono text-xs text-slate-400 dark:text-white/40'>
|
||||||
<span className='shrink-0'>实际请求:</span>
|
<span className='shrink-0'>实际请求:</span>
|
||||||
<span className='truncate'>{finalEndpoint}</span>
|
<span className='truncate'>{finalEndpoint}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 模型选择卡片 */}
|
{/* 模型选择卡片 */}
|
||||||
<div className='rounded-2xl border border-slate-200 bg-white p-5 transition-shadow hover:shadow-md dark:border-white/5 dark:bg-white/[0.02] dark:hover:shadow-black/20'>
|
<div className='rounded-2xl border border-slate-200 bg-white p-6 transition-shadow hover:shadow-md dark:border-white/10 dark:bg-white/[0.02] dark:hover:shadow-black/20'>
|
||||||
<div className='mb-3 flex items-center gap-2'>
|
<div className='mb-3 flex items-center gap-2'>
|
||||||
<div className='flex h-8 w-8 items-center justify-center rounded-lg bg-blue-50 text-blue-600 dark:bg-blue-500/10 dark:text-blue-400'>
|
<div className='flex h-8 w-8 items-center justify-center rounded-lg bg-blue-50 text-blue-600 dark:bg-blue-500/10 dark:text-blue-400'>
|
||||||
<Cpu size={15} />
|
<Cpu size={15} />
|
||||||
</div>
|
</div>
|
||||||
<div className='text-sm font-semibold text-slate-900 dark:text-white'>模型</div>
|
<div className='text-xs font-semibold text-slate-900 dark:text-white'>模型</div>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
value={model}
|
value={model}
|
||||||
onChange={(e) => setModel(e.target.value)}
|
onChange={(e) => setModel(e.target.value)}
|
||||||
placeholder='例如 gpt-4o-mini / claude-3-5-sonnet ...'
|
placeholder='例如 gpt-4o-mini / claude-3-5-sonnet ...'
|
||||||
className='w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 font-mono text-xs text-slate-900 outline-none transition focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-500/20 dark:border-white/10 dark:bg-white/[0.04] dark:text-white dark:focus:border-blue-400 dark:focus:bg-white/[0.06]'
|
className='w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2.5 font-mono text-xs text-slate-900 outline-none transition focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-500/20 dark:border-white/10 dark:bg-white/[0.04] dark:text-white dark:focus:border-blue-400 dark:focus:bg-white/[0.06]'
|
||||||
/>
|
/>
|
||||||
{format === 'anthropic' && (
|
{format === 'anthropic' && (
|
||||||
<div className='mt-3'>
|
<div className='mt-3'>
|
||||||
<label className='mb-1.5 block text-[11px] font-medium text-slate-500 dark:text-white/50'>
|
<label className='mb-1.5 block text-xs font-medium text-slate-500 dark:text-white/50'>
|
||||||
max_tokens(Anthropic 必填)
|
max_tokens(Anthropic 必填)
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
|
|
@ -511,7 +511,7 @@ const ApiTester = () => {
|
||||||
max={8192}
|
max={8192}
|
||||||
value={maxTokens}
|
value={maxTokens}
|
||||||
onChange={(e) => setMaxTokens(Number(e.target.value) || 1)}
|
onChange={(e) => setMaxTokens(Number(e.target.value) || 1)}
|
||||||
className='w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 font-mono text-xs text-slate-900 outline-none transition focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-500/20 dark:border-white/10 dark:bg-white/[0.04] dark:text-white dark:focus:border-blue-400 dark:focus:bg-white/[0.06]'
|
className='w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2.5 font-mono text-xs text-slate-900 outline-none transition focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-500/20 dark:border-white/10 dark:bg-white/[0.04] dark:text-white dark:focus:border-blue-400 dark:focus:bg-white/[0.06]'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -519,7 +519,7 @@ const ApiTester = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 第二行:请求参数 + 响应结果 */}
|
{/* 第二行:请求参数 + 响应结果 */}
|
||||||
<div className='grid grid-cols-1 gap-5 lg:grid-cols-2'>
|
<div className='grid grid-cols-1 gap-6 lg:grid-cols-2'>
|
||||||
{/* 请求参数卡片 */}
|
{/* 请求参数卡片 */}
|
||||||
<div className='rounded-2xl border border-slate-200 bg-white p-6 transition-shadow hover:shadow-md dark:border-white/5 dark:bg-white/[0.02] dark:hover:shadow-black/20'>
|
<div className='rounded-2xl border border-slate-200 bg-white p-6 transition-shadow hover:shadow-md dark:border-white/5 dark:bg-white/[0.02] dark:hover:shadow-black/20'>
|
||||||
<div className='mb-4 flex items-center justify-between'>
|
<div className='mb-4 flex items-center justify-between'>
|
||||||
|
|
@ -527,7 +527,7 @@ const ApiTester = () => {
|
||||||
<div className='flex h-8 w-8 items-center justify-center rounded-lg bg-blue-50 text-blue-600 dark:bg-blue-500/10 dark:text-blue-400'>
|
<div className='flex h-8 w-8 items-center justify-center rounded-lg bg-blue-50 text-blue-600 dark:bg-blue-500/10 dark:text-blue-400'>
|
||||||
<MessageSquare size={15} />
|
<MessageSquare size={15} />
|
||||||
</div>
|
</div>
|
||||||
<div className='text-sm font-semibold text-slate-900 dark:text-white'>
|
<div className='text-xs font-semibold text-slate-900 dark:text-white'>
|
||||||
请求参数
|
请求参数
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -547,7 +547,7 @@ const ApiTester = () => {
|
||||||
|
|
||||||
<div className='space-y-4'>
|
<div className='space-y-4'>
|
||||||
<div>
|
<div>
|
||||||
<label className='mb-1.5 block text-[11px] font-medium uppercase tracking-wider text-slate-500 dark:text-white/50'>
|
<label className='mb-1.5 block text-xs font-medium uppercase tracking-wider text-slate-500 dark:text-white/50'>
|
||||||
{format === 'anthropic' ? 'system(顶层字段)' : '系统提示'}
|
{format === 'anthropic' ? 'system(顶层字段)' : '系统提示'}
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
|
|
@ -555,12 +555,12 @@ const ApiTester = () => {
|
||||||
onChange={(e) => setSystemPrompt(e.target.value)}
|
onChange={(e) => setSystemPrompt(e.target.value)}
|
||||||
rows={2}
|
rows={2}
|
||||||
placeholder={format === 'anthropic' ? '(可选)Anthropic 顶层 system 字段' : '(可选)设置模型角色'}
|
placeholder={format === 'anthropic' ? '(可选)Anthropic 顶层 system 字段' : '(可选)设置模型角色'}
|
||||||
className='w-full resize-none rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-xs text-slate-900 outline-none transition focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-500/20 dark:border-white/10 dark:bg-white/[0.04] dark:text-white dark:focus:border-blue-400 dark:focus:bg-white/[0.06]'
|
className='w-full resize-none rounded-lg border border-slate-200 bg-slate-50 px-3 py-2.5 text-xs text-slate-900 outline-none transition focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-500/20 dark:border-white/10 dark:bg-white/[0.04] dark:text-white dark:focus:border-blue-400 dark:focus:bg-white/[0.06]'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className='mb-1.5 block text-[11px] font-medium uppercase tracking-wider text-slate-500 dark:text-white/50'>
|
<label className='mb-1.5 block text-xs font-medium uppercase tracking-wider text-slate-500 dark:text-white/50'>
|
||||||
用户提示 <span className='text-red-500'>*</span>
|
用户提示 <span className='text-red-500'>*</span>
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
|
|
@ -568,7 +568,7 @@ const ApiTester = () => {
|
||||||
onChange={(e) => setPrompt(e.target.value)}
|
onChange={(e) => setPrompt(e.target.value)}
|
||||||
rows={5}
|
rows={5}
|
||||||
placeholder='输入你想让模型回答的内容'
|
placeholder='输入你想让模型回答的内容'
|
||||||
className='w-full resize-none rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-xs text-slate-900 outline-none transition focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-500/20 dark:border-white/10 dark:bg-white/[0.04] dark:text-white dark:focus:border-blue-400 dark:focus:bg-white/[0.06]'
|
className='w-full resize-none rounded-lg border border-slate-200 bg-slate-50 px-3 py-2.5 text-xs text-slate-900 outline-none transition focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-500/20 dark:border-white/10 dark:bg-white/[0.04] dark:text-white dark:focus:border-blue-400 dark:focus:bg-white/[0.06]'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -581,12 +581,12 @@ const ApiTester = () => {
|
||||||
<div className='flex h-8 w-8 items-center justify-center rounded-lg bg-blue-50 text-blue-600 dark:bg-blue-500/10 dark:text-blue-400'>
|
<div className='flex h-8 w-8 items-center justify-center rounded-lg bg-blue-50 text-blue-600 dark:bg-blue-500/10 dark:text-blue-400'>
|
||||||
<Zap size={15} />
|
<Zap size={15} />
|
||||||
</div>
|
</div>
|
||||||
<div className='text-sm font-semibold text-slate-900 dark:text-white'>
|
<div className='text-xs font-semibold text-slate-900 dark:text-white'>
|
||||||
响应结果
|
响应结果
|
||||||
</div>
|
</div>
|
||||||
{status && (
|
{status && (
|
||||||
<span
|
<span
|
||||||
className={`ml-2 inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-[11px] font-medium ${
|
className={`ml-2 inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium ${
|
||||||
status.ok
|
status.ok
|
||||||
? 'bg-emerald-50 text-emerald-700 dark:bg-emerald-500/10 dark:text-emerald-400'
|
? 'bg-emerald-50 text-emerald-700 dark:bg-emerald-500/10 dark:text-emerald-400'
|
||||||
: 'bg-red-50 text-red-600 dark:bg-red-500/10 dark:text-red-400'
|
: 'bg-red-50 text-red-600 dark:bg-red-500/10 dark:text-red-400'
|
||||||
|
|
@ -607,7 +607,7 @@ const ApiTester = () => {
|
||||||
navigator.clipboard?.writeText(response);
|
navigator.clipboard?.writeText(response);
|
||||||
Toast.success('已复制响应');
|
Toast.success('已复制响应');
|
||||||
}}
|
}}
|
||||||
className='inline-flex items-center gap-1.5 rounded-full border border-slate-200 bg-white px-3 py-1.5 text-[11px] font-medium text-slate-600 transition-colors hover:border-slate-300 hover:text-slate-900 dark:border-white/10 dark:bg-white/[0.02] dark:text-white/60 dark:hover:border-white/20 dark:hover:text-white'
|
className='inline-flex items-center gap-1.5 rounded-full border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-600 transition-colors hover:border-slate-300 hover:text-slate-900 dark:border-white/10 dark:bg-white/[0.02] dark:text-white/60 dark:hover:border-white/20 dark:hover:text-white'
|
||||||
>
|
>
|
||||||
<Copy size={11} /> 复制
|
<Copy size={11} /> 复制
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -621,7 +621,7 @@ const ApiTester = () => {
|
||||||
请求中...
|
请求中...
|
||||||
</div>
|
</div>
|
||||||
) : response ? (
|
) : response ? (
|
||||||
<pre className='max-h-[480px] overflow-auto p-4 font-mono text-[11px] leading-relaxed text-slate-800 dark:text-white/80'>
|
<pre className='max-h-[480px] overflow-auto p-4 font-mono text-xs leading-relaxed text-slate-800 dark:text-white/80'>
|
||||||
{response}
|
{response}
|
||||||
</pre>
|
</pre>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,10 @@ import React from 'react';
|
||||||
import Dashboard from '../../components/dashboard';
|
import Dashboard from '../../components/dashboard';
|
||||||
|
|
||||||
const Detail = () => (
|
const Detail = () => (
|
||||||
<div className='mt-[60px] w-full max-w-[1600px] mx-auto px-3 sm:px-4 lg:px-6 pb-6'>
|
<div className='min-h-full pb-16 pt-20 text-slate-900 dark:text-white'>
|
||||||
<Dashboard />
|
<div className='w-full max-w-[1400px] px-4 sm:px-6 lg:px-10 ml-4 lg:ml-10'>
|
||||||
|
<Dashboard />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue