mirror of
				https://github.com/songquanpeng/one-api.git
				synced 2025-10-31 22:03:41 +08:00 
			
		
		
		
	Compare commits
	
		
			5 Commits
		
	
	
		
			v0.6.11-al
			...
			v0.6.11-al
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | a316ed7abc | ||
|  | 0895d8660e | ||
|  | be1ed114f4 | ||
|  | eb6da573a3 | ||
|  | 0a6273fc08 | 
							
								
								
									
										19
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -4,21 +4,20 @@ WORKDIR /web | ||||
| COPY ./VERSION . | ||||
| COPY ./web . | ||||
|  | ||||
| WORKDIR /web/default | ||||
| RUN npm install | ||||
| RUN DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat VERSION) npm run build | ||||
| RUN npm install --prefix /web/default & \ | ||||
|     npm install --prefix /web/berry & \ | ||||
|     npm install --prefix /web/air & \ | ||||
|     wait | ||||
|  | ||||
| WORKDIR /web/berry | ||||
| RUN npm install | ||||
| RUN DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat VERSION) npm run build | ||||
|  | ||||
| WORKDIR /web/air | ||||
| RUN npm install | ||||
| RUN DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat VERSION) npm run build | ||||
| RUN DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat /web/default/VERSION) npm run build --prefix /web/default & \ | ||||
|     DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat /web/berry/VERSION) npm run build --prefix /web/berry & \ | ||||
|     DISABLE_ESLINT_PLUGIN='true' REACT_APP_VERSION=$(cat /web/air/VERSION) npm run build --prefix /web/air & \ | ||||
|     wait | ||||
|  | ||||
| FROM golang:alpine AS builder2 | ||||
|  | ||||
| RUN apk add --no-cache g++ | ||||
| RUN apk add --no-cache gcc musl-dev libc-dev sqlite-dev | ||||
|  | ||||
| ENV GO111MODULE=on \ | ||||
|     CGO_ENABLED=1 \ | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import React, { useEffect, useState } from 'react'; | ||||
| import { Card } from 'semantic-ui-react'; | ||||
| import { Card, Header, Segment } from 'semantic-ui-react'; | ||||
| import { API, showError } from '../../helpers'; | ||||
| import { marked } from 'marked'; | ||||
|  | ||||
| @@ -7,39 +7,58 @@ const About = () => { | ||||
|   const [about, setAbout] = useState(''); | ||||
|   const [aboutLoaded, setAboutLoaded] = useState(false); | ||||
|  | ||||
|   // ... 其他函数保持不变 ... | ||||
|   const displayAbout = async () => { | ||||
|     setAbout(localStorage.getItem('about') || ''); | ||||
|     const res = await API.get('/api/about'); | ||||
|     const { success, message, data } = res.data; | ||||
|     if (success) { | ||||
|       let aboutContent = data; | ||||
|       if (!data.startsWith('https://')) { | ||||
|         aboutContent = marked.parse(data); | ||||
|       } | ||||
|       setAbout(aboutContent); | ||||
|       localStorage.setItem('about', aboutContent); | ||||
|     } else { | ||||
|       showError(message); | ||||
|       setAbout('加载关于内容失败...'); | ||||
|     } | ||||
|     setAboutLoaded(true); | ||||
|   }; | ||||
|  | ||||
|   useEffect(() => { | ||||
|     displayAbout().then(); | ||||
|   }, []); | ||||
|   return ( | ||||
|     <div className='dashboard-container'> | ||||
|       <Card fluid className='chart-card'> | ||||
|         <Card.Content> | ||||
|           <Card.Header className='header'>关于系统</Card.Header> | ||||
|           {aboutLoaded && about === '' ? ( | ||||
|             <> | ||||
|     <> | ||||
|       {aboutLoaded && about === '' ? ( | ||||
|         <div className='dashboard-container'> | ||||
|           <Card fluid className='chart-card'> | ||||
|             <Card.Content> | ||||
|               <Card.Header className='header'>关于系统</Card.Header> | ||||
|               <p>可在设置页面设置关于内容,支持 HTML & Markdown</p> | ||||
|               项目仓库地址: | ||||
|               <a href='https://github.com/songquanpeng/one-api'> | ||||
|                 https://github.com/songquanpeng/one-api | ||||
|               </a> | ||||
|             </> | ||||
|             </Card.Content> | ||||
|           </Card> | ||||
|         </div> | ||||
|       ) : ( | ||||
|         <> | ||||
|           {about.startsWith('https://') ? ( | ||||
|             <iframe | ||||
|               src={about} | ||||
|               style={{ width: '100%', height: '100vh', border: 'none' }} | ||||
|             /> | ||||
|           ) : ( | ||||
|             <> | ||||
|               {about.startsWith('https://') ? ( | ||||
|                 <iframe | ||||
|                   src={about} | ||||
|                   style={{ width: '100%', height: '100vh', border: 'none' }} | ||||
|                 /> | ||||
|               ) : ( | ||||
|                 <div | ||||
|                   style={{ fontSize: 'larger' }} | ||||
|                   dangerouslySetInnerHTML={{ __html: about }} | ||||
|                 ></div> | ||||
|               )} | ||||
|             </> | ||||
|             <div | ||||
|               style={{ fontSize: 'larger' }} | ||||
|               dangerouslySetInnerHTML={{ __html: about }} | ||||
|             ></div> | ||||
|           )} | ||||
|         </Card.Content> | ||||
|       </Card> | ||||
|     </div> | ||||
|         </> | ||||
|       )} | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -68,16 +68,27 @@ const Dashboard = () => { | ||||
|     try { | ||||
|       const response = await axios.get('/api/user/dashboard'); | ||||
|       if (response.data.success) { | ||||
|         const dashboardData = response.data.data; | ||||
|         const dashboardData = response.data.data || []; | ||||
|         setData(dashboardData); | ||||
|         calculateSummary(dashboardData); | ||||
|       } | ||||
|     } catch (error) { | ||||
|       console.error('Failed to fetch dashboard data:', error); | ||||
|       setData([]); | ||||
|       calculateSummary([]); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   const calculateSummary = (dashboardData) => { | ||||
|     if (!Array.isArray(dashboardData) || dashboardData.length === 0) { | ||||
|       setSummaryData({ | ||||
|         todayRequests: 0, | ||||
|         todayQuota: 0, | ||||
|         todayTokens: 0 | ||||
|       }); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     const today = new Date().toISOString().split('T')[0]; | ||||
|     const todayData = dashboardData.filter((item) => item.Day === today); | ||||
|  | ||||
| @@ -87,7 +98,7 @@ const Dashboard = () => { | ||||
|         0 | ||||
|       ), | ||||
|       todayQuota: | ||||
|         todayData.reduce((sum, item) => sum + item.Quota, 0) / 1000000, // 转换为美元 | ||||
|         todayData.reduce((sum, item) => sum + item.Quota, 0) / 1000000, | ||||
|       todayTokens: todayData.reduce( | ||||
|         (sum, item) => sum + item.PromptTokens + item.CompletionTokens, | ||||
|         0 | ||||
|   | ||||
| @@ -56,218 +56,222 @@ const Home = () => { | ||||
|   }, []); | ||||
|  | ||||
|   return ( | ||||
|     <div className='dashboard-container'> | ||||
|       <Card fluid className='chart-card'> | ||||
|         <Card.Content> | ||||
|           <Card.Header className='header'>欢迎使用 One API</Card.Header> | ||||
|           <Card.Description style={{ lineHeight: '1.6' }}> | ||||
|             <p> | ||||
|               One API 是一个 LLM API | ||||
|               接口管理和分发系统,可以帮助您更好地管理和使用各大厂商的 LLM API。 | ||||
|             </p> | ||||
|             {!userState.user && ( | ||||
|               <p> | ||||
|                 如需使用,请先<Link to='/login'>登录</Link>或 | ||||
|                 <Link to='/register'>注册</Link>。 | ||||
|               </p> | ||||
|             )} | ||||
|           </Card.Description> | ||||
|         </Card.Content> | ||||
|       </Card> | ||||
|  | ||||
|     <> | ||||
|       {homePageContentLoaded && homePageContent === '' ? ( | ||||
|         <Card fluid className='chart-card'> | ||||
|           <Card.Content> | ||||
|             <Card.Header> | ||||
|               <Header as='h3'>系统状况</Header> | ||||
|             </Card.Header> | ||||
|             <Grid columns={2} stackable> | ||||
|               <Grid.Column> | ||||
|                 <Card | ||||
|                   fluid | ||||
|                   className='chart-card' | ||||
|                   style={{ boxShadow: '0 1px 3px rgba(0,0,0,0.12)' }} | ||||
|                 > | ||||
|                   <Card.Content> | ||||
|                     <Card.Header> | ||||
|                       <Header as='h3' style={{ color: '#444' }}> | ||||
|                         系统信息 | ||||
|                       </Header> | ||||
|                     </Card.Header> | ||||
|                     <Card.Description | ||||
|                       style={{ lineHeight: '2', marginTop: '1em' }} | ||||
|                     > | ||||
|                       <p | ||||
|                         style={{ | ||||
|                           display: 'flex', | ||||
|                           alignItems: 'center', | ||||
|                           gap: '0.5em', | ||||
|                         }} | ||||
|         <div className='dashboard-container'> | ||||
|           <Card fluid className='chart-card'> | ||||
|             <Card.Content> | ||||
|               <Card.Header className='header'>欢迎使用 One API</Card.Header> | ||||
|               <Card.Description style={{ lineHeight: '1.6' }}> | ||||
|                 <p> | ||||
|                   One API 是一个 LLM API | ||||
|                   接口管理和分发系统,可以帮助您更好地管理和使用各大厂商的 LLM | ||||
|                   API。 | ||||
|                 </p> | ||||
|                 {!userState.user && ( | ||||
|                   <p> | ||||
|                     如需使用,请先<Link to='/login'>登录</Link>或 | ||||
|                     <Link to='/register'>注册</Link>。 | ||||
|                   </p> | ||||
|                 )} | ||||
|               </Card.Description> | ||||
|             </Card.Content> | ||||
|           </Card> | ||||
|           <Card fluid className='chart-card'> | ||||
|             <Card.Content> | ||||
|               <Card.Header> | ||||
|                 <Header as='h3'>系统状况</Header> | ||||
|               </Card.Header> | ||||
|               <Grid columns={2} stackable> | ||||
|                 <Grid.Column> | ||||
|                   <Card | ||||
|                     fluid | ||||
|                     className='chart-card' | ||||
|                     style={{ boxShadow: '0 1px 3px rgba(0,0,0,0.12)' }} | ||||
|                   > | ||||
|                     <Card.Content> | ||||
|                       <Card.Header> | ||||
|                         <Header as='h3' style={{ color: '#444' }}> | ||||
|                           系统信息 | ||||
|                         </Header> | ||||
|                       </Card.Header> | ||||
|                       <Card.Description | ||||
|                         style={{ lineHeight: '2', marginTop: '1em' }} | ||||
|                       > | ||||
|                         <i className='info circle icon'></i> | ||||
|                         <span style={{ fontWeight: 'bold' }}>名称:</span> | ||||
|                         <span>{statusState?.status?.system_name}</span> | ||||
|                       </p> | ||||
|                       <p | ||||
|                         style={{ | ||||
|                           display: 'flex', | ||||
|                           alignItems: 'center', | ||||
|                           gap: '0.5em', | ||||
|                         }} | ||||
|                       > | ||||
|                         <i className='code branch icon'></i> | ||||
|                         <span style={{ fontWeight: 'bold' }}>版本:</span> | ||||
|                         <span>{statusState?.status?.version || 'unknown'}</span> | ||||
|                       </p> | ||||
|                       <p | ||||
|                         style={{ | ||||
|                           display: 'flex', | ||||
|                           alignItems: 'center', | ||||
|                           gap: '0.5em', | ||||
|                         }} | ||||
|                       > | ||||
|                         <i className='github icon'></i> | ||||
|                         <span style={{ fontWeight: 'bold' }}>源码:</span> | ||||
|                         <a | ||||
|                           href='https://github.com/songquanpeng/one-api' | ||||
|                           target='_blank' | ||||
|                           style={{ color: '#2185d0' }} | ||||
|                         <p | ||||
|                           style={{ | ||||
|                             display: 'flex', | ||||
|                             alignItems: 'center', | ||||
|                             gap: '0.5em', | ||||
|                           }} | ||||
|                         > | ||||
|                           GitHub 仓库 | ||||
|                         </a> | ||||
|                       </p> | ||||
|                       <p | ||||
|                         style={{ | ||||
|                           display: 'flex', | ||||
|                           alignItems: 'center', | ||||
|                           gap: '0.5em', | ||||
|                         }} | ||||
|                       > | ||||
|                         <i className='clock outline icon'></i> | ||||
|                         <span style={{ fontWeight: 'bold' }}>启动时间:</span> | ||||
|                         <span>{getStartTimeString()}</span> | ||||
|                       </p> | ||||
|                     </Card.Description> | ||||
|                   </Card.Content> | ||||
|                 </Card> | ||||
|               </Grid.Column> | ||||
|                           <i className='info circle icon'></i> | ||||
|                           <span style={{ fontWeight: 'bold' }}>名称:</span> | ||||
|                           <span>{statusState?.status?.system_name}</span> | ||||
|                         </p> | ||||
|                         <p | ||||
|                           style={{ | ||||
|                             display: 'flex', | ||||
|                             alignItems: 'center', | ||||
|                             gap: '0.5em', | ||||
|                           }} | ||||
|                         > | ||||
|                           <i className='code branch icon'></i> | ||||
|                           <span style={{ fontWeight: 'bold' }}>版本:</span> | ||||
|                           <span> | ||||
|                             {statusState?.status?.version || 'unknown'} | ||||
|                           </span> | ||||
|                         </p> | ||||
|                         <p | ||||
|                           style={{ | ||||
|                             display: 'flex', | ||||
|                             alignItems: 'center', | ||||
|                             gap: '0.5em', | ||||
|                           }} | ||||
|                         > | ||||
|                           <i className='github icon'></i> | ||||
|                           <span style={{ fontWeight: 'bold' }}>源码:</span> | ||||
|                           <a | ||||
|                             href='https://github.com/songquanpeng/one-api' | ||||
|                             target='_blank' | ||||
|                             style={{ color: '#2185d0' }} | ||||
|                           > | ||||
|                             GitHub 仓库 | ||||
|                           </a> | ||||
|                         </p> | ||||
|                         <p | ||||
|                           style={{ | ||||
|                             display: 'flex', | ||||
|                             alignItems: 'center', | ||||
|                             gap: '0.5em', | ||||
|                           }} | ||||
|                         > | ||||
|                           <i className='clock outline icon'></i> | ||||
|                           <span style={{ fontWeight: 'bold' }}>启动时间:</span> | ||||
|                           <span>{getStartTimeString()}</span> | ||||
|                         </p> | ||||
|                       </Card.Description> | ||||
|                     </Card.Content> | ||||
|                   </Card> | ||||
|                 </Grid.Column> | ||||
|  | ||||
|               <Grid.Column> | ||||
|                 <Card | ||||
|                   fluid | ||||
|                   className='chart-card' | ||||
|                   style={{ boxShadow: '0 1px 3px rgba(0,0,0,0.12)' }} | ||||
|                 > | ||||
|                   <Card.Content> | ||||
|                     <Card.Header> | ||||
|                       <Header as='h3' style={{ color: '#444' }}> | ||||
|                         系统配置 | ||||
|                       </Header> | ||||
|                     </Card.Header> | ||||
|                     <Card.Description | ||||
|                       style={{ lineHeight: '2', marginTop: '1em' }} | ||||
|                     > | ||||
|                       <p | ||||
|                         style={{ | ||||
|                           display: 'flex', | ||||
|                           alignItems: 'center', | ||||
|                           gap: '0.5em', | ||||
|                         }} | ||||
|                 <Grid.Column> | ||||
|                   <Card | ||||
|                     fluid | ||||
|                     className='chart-card' | ||||
|                     style={{ boxShadow: '0 1px 3px rgba(0,0,0,0.12)' }} | ||||
|                   > | ||||
|                     <Card.Content> | ||||
|                       <Card.Header> | ||||
|                         <Header as='h3' style={{ color: '#444' }}> | ||||
|                           系统配置 | ||||
|                         </Header> | ||||
|                       </Card.Header> | ||||
|                       <Card.Description | ||||
|                         style={{ lineHeight: '2', marginTop: '1em' }} | ||||
|                       > | ||||
|                         <i className='envelope icon'></i> | ||||
|                         <span style={{ fontWeight: 'bold' }}>邮箱验证:</span> | ||||
|                         <span | ||||
|                         <p | ||||
|                           style={{ | ||||
|                             color: statusState?.status?.email_verification | ||||
|                               ? '#21ba45' | ||||
|                               : '#db2828', | ||||
|                             fontWeight: '500', | ||||
|                             display: 'flex', | ||||
|                             alignItems: 'center', | ||||
|                             gap: '0.5em', | ||||
|                           }} | ||||
|                         > | ||||
|                           {statusState?.status?.email_verification | ||||
|                             ? '已启用' | ||||
|                             : '未启用'} | ||||
|                         </span> | ||||
|                       </p> | ||||
|                       <p | ||||
|                         style={{ | ||||
|                           display: 'flex', | ||||
|                           alignItems: 'center', | ||||
|                           gap: '0.5em', | ||||
|                         }} | ||||
|                       > | ||||
|                         <i className='github icon'></i> | ||||
|                         <span style={{ fontWeight: 'bold' }}> | ||||
|                           GitHub 身份验证: | ||||
|                         </span> | ||||
|                         <span | ||||
|                           <i className='envelope icon'></i> | ||||
|                           <span style={{ fontWeight: 'bold' }}>邮箱验证:</span> | ||||
|                           <span | ||||
|                             style={{ | ||||
|                               color: statusState?.status?.email_verification | ||||
|                                 ? '#21ba45' | ||||
|                                 : '#db2828', | ||||
|                               fontWeight: '500', | ||||
|                             }} | ||||
|                           > | ||||
|                             {statusState?.status?.email_verification | ||||
|                               ? '已启用' | ||||
|                               : '未启用'} | ||||
|                           </span> | ||||
|                         </p> | ||||
|                         <p | ||||
|                           style={{ | ||||
|                             color: statusState?.status?.github_oauth | ||||
|                               ? '#21ba45' | ||||
|                               : '#db2828', | ||||
|                             fontWeight: '500', | ||||
|                             display: 'flex', | ||||
|                             alignItems: 'center', | ||||
|                             gap: '0.5em', | ||||
|                           }} | ||||
|                         > | ||||
|                           {statusState?.status?.github_oauth | ||||
|                             ? '已启用' | ||||
|                             : '未启用'} | ||||
|                         </span> | ||||
|                       </p> | ||||
|                       <p | ||||
|                         style={{ | ||||
|                           display: 'flex', | ||||
|                           alignItems: 'center', | ||||
|                           gap: '0.5em', | ||||
|                         }} | ||||
|                       > | ||||
|                         <i className='wechat icon'></i> | ||||
|                         <span style={{ fontWeight: 'bold' }}> | ||||
|                           微信身份验证: | ||||
|                         </span> | ||||
|                         <span | ||||
|                           <i className='github icon'></i> | ||||
|                           <span style={{ fontWeight: 'bold' }}> | ||||
|                             GitHub 身份验证: | ||||
|                           </span> | ||||
|                           <span | ||||
|                             style={{ | ||||
|                               color: statusState?.status?.github_oauth | ||||
|                                 ? '#21ba45' | ||||
|                                 : '#db2828', | ||||
|                               fontWeight: '500', | ||||
|                             }} | ||||
|                           > | ||||
|                             {statusState?.status?.github_oauth | ||||
|                               ? '已启用' | ||||
|                               : '未启用'} | ||||
|                           </span> | ||||
|                         </p> | ||||
|                         <p | ||||
|                           style={{ | ||||
|                             color: statusState?.status?.wechat_login | ||||
|                               ? '#21ba45' | ||||
|                               : '#db2828', | ||||
|                             fontWeight: '500', | ||||
|                             display: 'flex', | ||||
|                             alignItems: 'center', | ||||
|                             gap: '0.5em', | ||||
|                           }} | ||||
|                         > | ||||
|                           {statusState?.status?.wechat_login | ||||
|                             ? '已启用' | ||||
|                             : '未启用'} | ||||
|                         </span> | ||||
|                       </p> | ||||
|                       <p | ||||
|                         style={{ | ||||
|                           display: 'flex', | ||||
|                           alignItems: 'center', | ||||
|                           gap: '0.5em', | ||||
|                         }} | ||||
|                       > | ||||
|                         <i className='shield alternate icon'></i> | ||||
|                         <span style={{ fontWeight: 'bold' }}> | ||||
|                           Turnstile 校验: | ||||
|                         </span> | ||||
|                         <span | ||||
|                           <i className='wechat icon'></i> | ||||
|                           <span style={{ fontWeight: 'bold' }}> | ||||
|                             微信身份验证: | ||||
|                           </span> | ||||
|                           <span | ||||
|                             style={{ | ||||
|                               color: statusState?.status?.wechat_login | ||||
|                                 ? '#21ba45' | ||||
|                                 : '#db2828', | ||||
|                               fontWeight: '500', | ||||
|                             }} | ||||
|                           > | ||||
|                             {statusState?.status?.wechat_login | ||||
|                               ? '已启用' | ||||
|                               : '未启用'} | ||||
|                           </span> | ||||
|                         </p> | ||||
|                         <p | ||||
|                           style={{ | ||||
|                             color: statusState?.status?.turnstile_check | ||||
|                               ? '#21ba45' | ||||
|                               : '#db2828', | ||||
|                             fontWeight: '500', | ||||
|                             display: 'flex', | ||||
|                             alignItems: 'center', | ||||
|                             gap: '0.5em', | ||||
|                           }} | ||||
|                         > | ||||
|                           {statusState?.status?.turnstile_check | ||||
|                             ? '已启用' | ||||
|                             : '未启用'} | ||||
|                         </span> | ||||
|                       </p> | ||||
|                     </Card.Description> | ||||
|                   </Card.Content> | ||||
|                 </Card> | ||||
|               </Grid.Column> | ||||
|             </Grid> | ||||
|           </Card.Content> | ||||
|         </Card> | ||||
|                           <i className='shield alternate icon'></i> | ||||
|                           <span style={{ fontWeight: 'bold' }}> | ||||
|                             Turnstile 校验: | ||||
|                           </span> | ||||
|                           <span | ||||
|                             style={{ | ||||
|                               color: statusState?.status?.turnstile_check | ||||
|                                 ? '#21ba45' | ||||
|                                 : '#db2828', | ||||
|                               fontWeight: '500', | ||||
|                             }} | ||||
|                           > | ||||
|                             {statusState?.status?.turnstile_check | ||||
|                               ? '已启用' | ||||
|                               : '未启用'} | ||||
|                           </span> | ||||
|                         </p> | ||||
|                       </Card.Description> | ||||
|                     </Card.Content> | ||||
|                   </Card> | ||||
|                 </Grid.Column> | ||||
|               </Grid> | ||||
|             </Card.Content> | ||||
|           </Card>{' '} | ||||
|         </div> | ||||
|       ) : ( | ||||
|         <> | ||||
|           {homePageContent.startsWith('https://') ? ( | ||||
| @@ -283,7 +287,7 @@ const Home = () => { | ||||
|           )} | ||||
|         </> | ||||
|       )} | ||||
|     </div> | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user