fix(im_llm): 代理绕过Docker内部hostname

This commit is contained in:
QihuAI Design committed 2026-07-31 08:51:15 +08:00
1 parent 96aabc31f6
commit 9a43ee244d
24 files changed
+898 -129

No files matched your search

+2 -2
View File
@@ -90,7 +90,7 @@ const App: React.FC = () => {
localStorage.removeItem('aiflow_token');
localStorage.removeItem('aiflow_user');
};
const isAdmin = user?.role === 'admin';
const isAdmin = user?.role === 'admin' || user?.role === 'super_admin';
if (loading) {
return <div className="loading-screen">加载中...</div>;
@@ -130,7 +130,7 @@ const App: React.FC = () => {
</Route>
{/* Admin Routes */}
<Route path="/admin" element={<AdminLayout />}>
<Route path="/admin" element={isAdmin ? <AdminLayout /> : <Navigate to="/login" replace />}>
<Route index element={<AdminDashboard />} />
<Route path="users" element={<AdminUsers />} />
<Route path="models" element={<AdminModels />} />
@@ -194,13 +194,7 @@ const AdminLayout: React.FC = () => {
const location = useLocation();
// 后台必须登录且为管理员
useEffect(() => {
const token = localStorage.getItem('aiflow_token');
if (!token || !user || user.role !== 'admin') {
logout();
navigate('/login', { replace: true });
}
}, [user, logout, navigate]);
// Auth guard moved to App.tsx route level (no race condition)
const navCrumb = (() => {
@@ -109,12 +109,6 @@ const FrontLayout: React.FC = () => {
<span className="nav-icon"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 2v4m0 12v4m10-10h-4M6 12H2"/><path d="m4.93 4.93 2.83 2.83m8.48 8.48 2.83 2.83M4.93 19.07l2.83-2.83m8.48-8.48 2.83-2.83"/></svg></span>
{!collapsed && <span className="nav-label">Agent 编排</span>}
</NavLink>
<NavLink to="/" className={({ isActive }) => `nav-item nav-home-link`} end>
<span className="nav-item-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
</span>
{!collapsed && <span className="nav-item-label">返回首页</span>}
</NavLink>
{navGroups.map(group => (
<div className="nav-section" key={group.title}>
{!collapsed && <div className="nav-group-title">{group.title}</div>}
@@ -161,7 +155,7 @@ const FrontLayout: React.FC = () => {
</div>
)}
</div>
{user.role === 'admin' && (
{user.role === 'admin' || user.role === 'super_admin' && (
<NavLink
to="/admin"
className={({ isActive }) => `nav-item ${isActive ? 'active' : ''}`}
+11 -2
View File
@@ -26,6 +26,10 @@ const capabilityLabels: Record<string, string> = {
embedding: '嵌入向量', rerank: '重排序', video: '视频生成',
};
// 锁定项:文本对话(text) 与 推理思考(thinking) 强制使用平台默认对话模型,
// 防止被误配到失效模型导致 chat 不可用(见全栈体检修复记录)。
const LOCKED_CAP_DEFAULTS: Record<string, string> = { text: 'aaae3233-4fd9-4b3e-ab51-cd8a87c82e0b', thinking: 'aaae3233-4fd9-4b3e-ab51-cd8a87c82e0b' };
// Test result type
interface TestResult {
modelId: string;
@@ -527,6 +531,8 @@ const Models: React.FC = () => {
);
const cur = capabilityDefaults[cap.id] || '';
const saving = savingCaps.has(cap.id);
const lockedModelId = LOCKED_CAP_DEFAULTS[cap.id];
const isLocked = Boolean(lockedModelId);
const dotColor = cap.color || capabilityColors[cap.id] || '#6B7280';
return (
<div key={cap.id} style={{ border: '1px solid #EEF0F4', borderRadius: '8px', padding: '12px 14px', background: '#FBFCFE' }}>
@@ -537,8 +543,8 @@ const Models: React.FC = () => {
</div>
<div style={{ fontSize: '12px', color: '#8a8a8a', marginBottom: '10px', minHeight: '32px' }}>{cap.desc}</div>
<select
value={cur}
disabled={saving}
value={isLocked ? (lockedModelId as string) : cur}
disabled={saving || isLocked}
onChange={e => handleSetCapabilityDefault(cap.id, e.target.value || null)}
style={{ width: '100%', padding: '7px 10px', border: '1px solid #D1D5DB', borderRadius: '6px', fontSize: '13px', boxSizing: 'border-box', background: '#fff', color: '#333' }}
>
@@ -549,6 +555,9 @@ const Models: React.FC = () => {
</option>
))}
</select>
{isLocked && (
<div style={{ fontSize: '11px', color: '#16A34A', marginTop: '6px' }}>🔒 已锁定为平台默认模型,不可更改</div>
)}
</div>
);
})}
+2 -2
View File
@@ -85,14 +85,14 @@ const LoginPage: React.FC = () => {
createdAt: userData.created_at || new Date().toISOString(),
membership: userData.membership_level > 0 ? {
planId: userData.membership_level >= 3 ? 'mp3' : (userData.membership_level >= 2 ? 'mp2' : 'mp1'),
planName: userData.role === 'admin' ? '管理员' : (userData.membership_level >= 3 ? '企业版' : (userData.membership_level >= 2 ? '专业版' : '免费版')),
planName: userData.role === 'admin' || userData.role === 'super_admin' ? '管理员' : (userData.membership_level >= 3 ? '企业版' : (userData.membership_level >= 2 ? '专业版' : '免费版')),
level: userData.membership_level,
expireAt: userData.membership_expire_at || '',
autoRenew: userData.auto_renew || false,
} : undefined,
};
login(userObj);
navigate(userData.role === 'admin' ? '/admin' : '/chat');
navigate(userData.role === 'admin' || userData.role === 'super_admin' ? '/admin' : '/chat');
} catch (e: any) {
// 处理后端返回的精确错误信息,区分用户不存在和密码错误
const status = e.status || e.response?.status || 0;