feat: able to customize system name & logo now

This commit is contained in:
JustSong 2023-05-14 19:29:02 +08:00
parent 2cdc718fde
commit 926951ee03
10 changed files with 87 additions and 29 deletions

View File

@ -11,6 +11,7 @@ var Version = "v0.0.0" // this hard coding will be replaced automatic
var SystemName = "One API"
var ServerAddress = "http://localhost:3000"
var Footer = ""
var Logo = ""
var TopUpLink = ""
var UsingSQLite = false

View File

@ -20,6 +20,7 @@ func GetStatus(c *gin.Context) {
"github_oauth": common.GitHubOAuthEnabled,
"github_client_id": common.GitHubClientId,
"system_name": common.SystemName,
"logo": common.Logo,
"footer_html": common.Footer,
"wechat_qrcode": common.WeChatAccountQRCodeImageURL,
"wechat_login": common.WeChatAuthEnabled,

View File

@ -41,6 +41,8 @@ func InitOptionMap() {
common.OptionMap["About"] = ""
common.OptionMap["HomePageContent"] = ""
common.OptionMap["Footer"] = common.Footer
common.OptionMap["SystemName"] = common.SystemName
common.OptionMap["Logo"] = common.Logo
common.OptionMap["ServerAddress"] = ""
common.OptionMap["GitHubClientId"] = ""
common.OptionMap["GitHubClientSecret"] = ""
@ -134,6 +136,10 @@ func updateOptionMap(key string, value string) (err error) {
common.GitHubClientSecret = value
case "Footer":
common.Footer = value
case "SystemName":
common.SystemName = value
case "Logo":
common.Logo = value
case "WeChatServerAddress":
common.WeChatServerAddress = value
case "WeChatServerToken":

View File

@ -42,6 +42,8 @@ function App() {
if (success) {
localStorage.setItem('status', JSON.stringify(data));
statusDispatch({ type: 'set', payload: data });
localStorage.setItem('system_name', data.system_name);
localStorage.setItem('logo', data.logo);
localStorage.setItem('footer_html', data.footer_html);
if (
data.version !== process.env.REACT_APP_VERSION &&

View File

@ -1,40 +1,37 @@
import React, { useEffect, useState } from 'react';
import React from 'react';
import { Container, Segment } from 'semantic-ui-react';
import { getFooterHTML, getSystemName } from '../helpers';
const Footer = () => {
const [Footer, setFooter] = useState('');
useEffect(() => {
let savedFooter = localStorage.getItem('footer_html');
if (!savedFooter) savedFooter = '';
setFooter(savedFooter);
});
const systemName = getSystemName();
const footer = getFooterHTML();
return (
<Segment vertical>
<Container textAlign="center">
{Footer === '' ? (
<div className="custom-footer">
<Container textAlign='center'>
{footer ? (
<div
className='custom-footer'
dangerouslySetInnerHTML={{ __html: footer }}
></div>
) : (
<div className='custom-footer'>
<a
href="https://github.com/songquanpeng/one-api"
target="_blank"
href='https://github.com/songquanpeng/one-api'
target='_blank'
>
One API {process.env.REACT_APP_VERSION}{' '}
{systemName} {process.env.REACT_APP_VERSION}{' '}
</a>
{' '}
<a href="https://github.com/songquanpeng" target="_blank">
<a href='https://github.com/songquanpeng' target='_blank'>
JustSong
</a>{' '}
构建源代码遵循{' '}
<a href="https://opensource.org/licenses/mit-license.php">
<a href='https://opensource.org/licenses/mit-license.php'>
MIT 协议
</a>
</div>
) : (
<div
className="custom-footer"
dangerouslySetInnerHTML={{ __html: Footer }}
></div>
)}
</Container>
</Segment>

View File

@ -3,7 +3,7 @@ import { Link, useNavigate } from 'react-router-dom';
import { UserContext } from '../context/User';
import { Button, Container, Dropdown, Icon, Menu, Segment } from 'semantic-ui-react';
import { API, isAdmin, isMobile, showSuccess } from '../helpers';
import { API, getLogo, getSystemName, isAdmin, isMobile, showSuccess } from '../helpers';
import '../index.css';
// Header Buttons
@ -53,6 +53,8 @@ const Header = () => {
let navigate = useNavigate();
const [showSidebar, setShowSidebar] = useState(false);
const systemName = getSystemName();
const logo = getLogo();
async function logout() {
setShowSidebar(false);
@ -111,12 +113,12 @@ const Header = () => {
<Container>
<Menu.Item as={Link} to='/'>
<img
src='/logo.png'
src={logo}
alt='logo'
style={{ marginRight: '0.75em' }}
/>
<div style={{ fontSize: '20px' }}>
<b>One API</b>
<b>{systemName}</b>
</div>
</Menu.Item>
<Menu.Menu position='right'>
@ -168,9 +170,9 @@ const Header = () => {
<Menu borderless style={{ borderTop: 'none' }}>
<Container>
<Menu.Item as={Link} to='/' className={'hide-on-mobile'}>
<img src='/logo.png' alt='logo' style={{ marginRight: '0.75em' }} />
<img src={logo} alt='logo' style={{ marginRight: '0.75em' }} />
<div style={{ fontSize: '20px' }}>
<b>One API</b>
<b>{systemName}</b>
</div>
</Menu.Item>
{renderButtons(false)}

View File

@ -12,7 +12,7 @@ import {
} from 'semantic-ui-react';
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
import { UserContext } from '../context/User';
import { API, showError, showSuccess } from '../helpers';
import { API, getLogo, showError, showSuccess } from '../helpers';
const LoginForm = () => {
const [inputs, setInputs] = useState({
@ -27,6 +27,7 @@ const LoginForm = () => {
let navigate = useNavigate();
const [status, setStatus] = useState({});
const logo = getLogo();
useEffect(() => {
if (searchParams.get("expired")) {
@ -95,7 +96,7 @@ const LoginForm = () => {
<Grid textAlign="center" style={{ marginTop: '48px' }}>
<Grid.Column style={{ maxWidth: 450 }}>
<Header as="h2" color="" textAlign="center">
<Image src="/logo.png" /> 用户登录
<Image src={logo} /> 用户登录
</Header>
<Form size="large">
<Segment>

View File

@ -8,6 +8,8 @@ const OtherSetting = () => {
Footer: '',
Notice: '',
About: '',
SystemName: '',
Logo: '',
HomePageContent: '',
});
let originInputs = {};
@ -66,6 +68,14 @@ const OtherSetting = () => {
await updateOption('Footer', inputs.Footer);
};
const submitSystemName = async () => {
await updateOption('SystemName', inputs.SystemName);
};
const submitLogo = async () => {
await updateOption('Logo', inputs.Logo);
};
const submitAbout = async () => {
await updateOption('About', inputs.About);
};
@ -114,6 +124,27 @@ const OtherSetting = () => {
<Form.Button onClick={submitNotice}>保存公告</Form.Button>
<Divider />
<Header as='h3'>个性化设置</Header>
<Form.Group widths='equal'>
<Form.Input
label='系统名称'
placeholder='在此输入系统名称'
value={inputs.SystemName}
name='SystemName'
onChange={handleInputChange}
/>
</Form.Group>
<Form.Button onClick={submitSystemName}>设置系统名称</Form.Button>
<Form.Group widths='equal'>
<Form.Input
label='Logo 图片地址'
placeholder='在此输入 Logo 图片地址'
value={inputs.Logo}
name='Logo'
type='url'
onChange={handleInputChange}
/>
</Form.Group>
<Form.Button onClick={submitLogo}>设置 Logo</Form.Button>
<Form.Group widths='equal'>
<Form.TextArea
label='首页内容'

View File

@ -9,7 +9,7 @@ import {
Segment,
} from 'semantic-ui-react';
import { Link, useNavigate } from 'react-router-dom';
import { API, showError, showInfo, showSuccess } from '../helpers';
import { API, getLogo, showError, showInfo, showSuccess } from '../helpers';
import Turnstile from 'react-turnstile';
const RegisterForm = () => {
@ -26,6 +26,7 @@ const RegisterForm = () => {
const [turnstileSiteKey, setTurnstileSiteKey] = useState('');
const [turnstileToken, setTurnstileToken] = useState('');
const [loading, setLoading] = useState(false);
const logo = getLogo();
useEffect(() => {
let status = localStorage.getItem('status');
@ -100,7 +101,7 @@ const RegisterForm = () => {
<Grid textAlign='center' style={{ marginTop: '48px' }}>
<Grid.Column style={{ maxWidth: 450 }}>
<Header as='h2' color='' textAlign='center'>
<Image src='/logo.png' /> 新用户注册
<Image src={logo} /> 新用户注册
</Header>
<Form size='large'>
<Segment>

View File

@ -15,6 +15,22 @@ export function isRoot() {
return user.role >= 100;
}
export function getSystemName() {
let system_name = localStorage.getItem('system_name');
if (!system_name) return 'One API';
return system_name;
}
export function getLogo() {
let logo = localStorage.getItem('logo');
if (!logo) return '/logo.png';
return logo
}
export function getFooterHTML() {
return localStorage.getItem('footer_html');
}
export async function copy(text) {
let okay = true;
try {