♻️ refactor: refactor the logic of fetchTokenKeys and SetupCheck

This commit is contained in:
Apple\Apple
2025-06-04 01:00:48 +08:00
parent 3f45153e75
commit 943f21f3cb
11 changed files with 116 additions and 94 deletions

View File

@@ -25,7 +25,7 @@ import Playground from './pages/Playground/index.js';
import OAuth2Callback from './components/auth/OAuth2Callback.js';
import PersonalSetting from './components/settings/PersonalSetting.js';
import Setup from './pages/Setup/index.js';
import SetupCheck from './components/SetupCheck';
import { useSetupCheck } from './hooks/useSetupCheck.js';
const Home = lazy(() => import('./pages/Home'));
const Detail = lazy(() => import('./pages/Detail'));
@@ -35,7 +35,7 @@ function App() {
const location = useLocation();
return (
<SetupCheck>
<useSetupCheck>
<Routes>
<Route
path='/'
@@ -290,7 +290,7 @@ function App() {
/>
<Route path='*' element={<NotFound />} />
</Routes>
</SetupCheck>
</useSetupCheck>
);
}

View File

@@ -1,18 +0,0 @@
import React, { useContext, useEffect } from 'react';
import { Navigate, useLocation } from 'react-router-dom';
import { StatusContext } from '../context/Status';
const SetupCheck = ({ children }) => {
const [statusState] = useContext(StatusContext);
const location = useLocation();
useEffect(() => {
if (statusState?.status?.setup === false && location.pathname !== '/setup') {
window.location.href = '/setup';
}
}, [statusState?.status?.setup, location.pathname]);
return children;
};
export default SetupCheck;

View File

@@ -1,68 +0,0 @@
// src/hooks/useTokenKeys.js
import { useEffect, useState } from 'react';
import { API, showError } from '../helpers';
async function fetchTokenKeys() {
try {
const response = await API.get('/api/token/?p=0&size=100');
const { success, data } = response.data;
if (success) {
const activeTokens = data.filter((token) => token.status === 1);
return activeTokens.map((token) => token.key);
} else {
throw new Error('Failed to fetch token keys');
}
} catch (error) {
console.error('Error fetching token keys:', error);
return [];
}
}
function getServerAddress() {
let status = localStorage.getItem('status');
let serverAddress = '';
if (status) {
try {
status = JSON.parse(status);
serverAddress = status.server_address || '';
} catch (error) {
console.error('Failed to parse status from localStorage:', error);
}
}
if (!serverAddress) {
serverAddress = window.location.origin;
}
return serverAddress;
}
export function useTokenKeys(id) {
const [keys, setKeys] = useState([]);
// const [chatLink, setChatLink] = useState('');
const [serverAddress, setServerAddress] = useState('');
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const loadAllData = async () => {
const fetchedKeys = await fetchTokenKeys();
if (fetchedKeys.length === 0) {
showError('当前没有可用的启用令牌,请确认是否有令牌处于启用状态!');
setTimeout(() => {
window.location.href = '/token';
}, 1500); // 延迟 1.5 秒后跳转
}
setKeys(fetchedKeys);
setIsLoading(false);
// setChatLink(link);
const address = getServerAddress();
setServerAddress(address);
};
loadAllData();
}, []);
return { keys, serverAddress, isLoading };
}

View File

@@ -5,3 +5,4 @@ export * from './api';
export * from './render';
export * from './log';
export * from './data';
export * from './token';

45
web/src/helpers/token.js Normal file
View File

@@ -0,0 +1,45 @@
import { API } from './api';
/**
* 获取可用的token keys
* @returns {Promise<string[]>} 返回active状态的token key数组
*/
export async function fetchTokenKeys() {
try {
const response = await API.get('/api/token/?p=0&size=100');
const { success, data } = response.data;
if (success) {
const activeTokens = data.filter((token) => token.status === 1);
return activeTokens.map((token) => token.key);
} else {
throw new Error('Failed to fetch token keys');
}
} catch (error) {
console.error('Error fetching token keys:', error);
return [];
}
}
/**
* 获取服务器地址
* @returns {string} 服务器地址
*/
export function getServerAddress() {
let status = localStorage.getItem('status');
let serverAddress = '';
if (status) {
try {
status = JSON.parse(status);
serverAddress = status.server_address || '';
} catch (error) {
console.error('Failed to parse status from localStorage:', error);
}
}
if (!serverAddress) {
serverAddress = window.location.origin;
}
return serverAddress;
}

View File

@@ -0,0 +1,32 @@
import { useContext, useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { StatusContext } from '../context/Status';
/**
* 自定义Hook检查系统setup状态并进行重定向
* @param {Object} options - 配置选项
* @param {boolean} options.autoRedirect - 是否自动重定向默认true
* @param {string} options.setupPath - setup页面路径默认'/setup'
* @returns {Object} 返回setup状态信息
*/
export function useSetupCheck(options = {}) {
const { autoRedirect = true, setupPath = '/setup' } = options;
const [statusState] = useContext(StatusContext);
const location = useLocation();
const isSetupComplete = statusState?.status?.setup !== false;
const needsSetup = !isSetupComplete && location.pathname !== setupPath;
useEffect(() => {
if (autoRedirect && needsSetup) {
window.location.href = setupPath;
}
}, [autoRedirect, needsSetup, setupPath]);
return {
isSetupComplete,
needsSetup,
statusState,
currentPath: location.pathname
};
}

View File

@@ -0,0 +1,30 @@
import { useEffect, useState } from 'react';
import { fetchTokenKeys, getServerAddress } from '../helpers/token';
import { showError } from '../helpers';
export function useTokenKeys(id) {
const [keys, setKeys] = useState([]);
const [serverAddress, setServerAddress] = useState('');
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const loadAllData = async () => {
const fetchedKeys = await fetchTokenKeys();
if (fetchedKeys.length === 0) {
showError('当前没有可用的启用令牌,请确认是否有令牌处于启用状态!');
setTimeout(() => {
window.location.href = '/token';
}, 1500); // 延迟 1.5 秒后跳转
}
setKeys(fetchedKeys);
setIsLoading(false);
const address = getServerAddress();
setServerAddress(address);
};
loadAllData();
}, []);
return { keys, serverAddress, isLoading };
}

View File

@@ -16,7 +16,7 @@ import './index.css';
const root = ReactDOM.createRoot(document.getElementById('root'));
const { Sider, Content, Header, Footer } = Layout;
root.render(
// <React.StrictMode>
<React.StrictMode>
<StatusProvider>
<UserProvider>
<BrowserRouter>
@@ -28,5 +28,5 @@ root.render(
</BrowserRouter>
</UserProvider>
</StatusProvider>
// </React.StrictMode>,
</React.StrictMode>,
);

View File

@@ -1,5 +1,5 @@
import React, { useEffect } from 'react';
import { useTokenKeys } from '../../components/fetchTokenKeys';
import { useTokenKeys } from '../../hooks/useTokenKeys';
import { Banner, Layout } from '@douyinfe/semi-ui';
import { useParams } from 'react-router-dom';

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { useTokenKeys } from '../../components/fetchTokenKeys';
import { useTokenKeys } from '../../hooks/useTokenKeys';
const chat2page = () => {
const { keys, chatLink, serverAddress, isLoading } = useTokenKeys();

View File

@@ -5,7 +5,7 @@ import { StatusContext } from '../../context/Status';
import { marked } from 'marked';
import { useTranslation } from 'react-i18next';
import { IconGithubLogo } from '@douyinfe/semi-icons';
import exampleImage from '..//example.png';
import exampleImage from '/example.png';
import { Link } from 'react-router-dom';
import NoticeModal from '../../components/layout/NoticeModal';
import { Moonshot, OpenAI, XAI, Zhipu, Volcengine, Cohere, Claude, Gemini, Suno, Minimax, Wenxin, Spark, Qingyan, DeepSeek, Qwen, Midjourney, Grok, AzureAI, Hunyuan, Xinference } from '@lobehub/icons';