feat: 优化界面显示

This commit is contained in:
CalciumIon
2024-09-17 19:55:18 +08:00
parent 6263616cd9
commit feb1d76942
6 changed files with 350 additions and 297 deletions

View File

@@ -24,6 +24,7 @@ import { Layout } from '@douyinfe/semi-ui';
import Midjourney from './pages/Midjourney'; import Midjourney from './pages/Midjourney';
import Pricing from './pages/Pricing/index.js'; import Pricing from './pages/Pricing/index.js';
import Task from "./pages/Task/index.js"; import Task from "./pages/Task/index.js";
import FooterBar from './components/Footer.js';
// import Detail from './pages/Detail'; // import Detail from './pages/Detail';
const Home = lazy(() => import('./pages/Home')); const Home = lazy(() => import('./pages/Home'));
@@ -58,207 +59,205 @@ function App() {
}, []); }, []);
return ( return (
<Layout> <>
<Layout.Content> <Routes>
<Routes> <Route
<Route path='/'
path='/' element={
element={ <Suspense fallback={<Loading></Loading>}>
<Home />
</Suspense>
}
/>
<Route
path='/channel'
element={
<PrivateRoute>
<Channel />
</PrivateRoute>
}
/>
<Route
path='/channel/edit/:id'
element={
<Suspense fallback={<Loading></Loading>}>
<EditChannel />
</Suspense>
}
/>
<Route
path='/channel/add'
element={
<Suspense fallback={<Loading></Loading>}>
<EditChannel />
</Suspense>
}
/>
<Route
path='/token'
element={
<PrivateRoute>
<Token />
</PrivateRoute>
}
/>
<Route
path='/redemption'
element={
<PrivateRoute>
<Redemption />
</PrivateRoute>
}
/>
<Route
path='/user'
element={
<PrivateRoute>
<User />
</PrivateRoute>
}
/>
<Route
path='/user/edit/:id'
element={
<Suspense fallback={<Loading></Loading>}>
<EditUser />
</Suspense>
}
/>
<Route
path='/user/edit'
element={
<Suspense fallback={<Loading></Loading>}>
<EditUser />
</Suspense>
}
/>
<Route
path='/user/reset'
element={
<Suspense fallback={<Loading></Loading>}>
<PasswordResetConfirm />
</Suspense>
}
/>
<Route
path='/login'
element={
<Suspense fallback={<Loading></Loading>}>
<LoginForm />
</Suspense>
}
/>
<Route
path='/register'
element={
<Suspense fallback={<Loading></Loading>}>
<RegisterForm />
</Suspense>
}
/>
<Route
path='/reset'
element={
<Suspense fallback={<Loading></Loading>}>
<PasswordResetForm />
</Suspense>
}
/>
<Route
path='/oauth/github'
element={
<Suspense fallback={<Loading></Loading>}>
<GitHubOAuth />
</Suspense>
}
/>
<Route
path='/setting'
element={
<PrivateRoute>
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<Home /> <Setting />
</Suspense> </Suspense>
} </PrivateRoute>
/> }
<Route />
path='/channel' <Route
element={ path='/topup'
<PrivateRoute> element={
<Channel /> <PrivateRoute>
</PrivateRoute>
}
/>
<Route
path='/channel/edit/:id'
element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<EditChannel /> <TopUp />
</Suspense> </Suspense>
} </PrivateRoute>
/> }
<Route />
path='/channel/add' <Route
element={ path='/log'
element={
<PrivateRoute>
<Log />
</PrivateRoute>
}
/>
<Route
path='/detail'
element={
<PrivateRoute>
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<EditChannel /> <Detail />
</Suspense> </Suspense>
} </PrivateRoute>
/> }
<Route />
path='/token' <Route
element={ path='/midjourney'
<PrivateRoute> element={
<Token /> <PrivateRoute>
</PrivateRoute>
}
/>
<Route
path='/redemption'
element={
<PrivateRoute>
<Redemption />
</PrivateRoute>
}
/>
<Route
path='/user'
element={
<PrivateRoute>
<User />
</PrivateRoute>
}
/>
<Route
path='/user/edit/:id'
element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<EditUser /> <Midjourney />
</Suspense> </Suspense>
} </PrivateRoute>
/> }
<Route />
path='/user/edit' <Route
element={ path='/task'
element={
<PrivateRoute>
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<EditUser /> <Task />
</Suspense> </Suspense>
} </PrivateRoute>
/> }
<Route />
path='/user/reset' <Route
element={ path='/pricing'
<Suspense fallback={<Loading></Loading>}> element={
<PasswordResetConfirm /> <Suspense fallback={<Loading></Loading>}>
</Suspense> <Pricing />
} </Suspense>
/> }
<Route />
path='/login' <Route
element={ path='/about'
<Suspense fallback={<Loading></Loading>}> element={
<LoginForm /> <Suspense fallback={<Loading></Loading>}>
</Suspense> <About />
} </Suspense>
/> }
<Route />
path='/register' <Route
element={ path='/chat'
<Suspense fallback={<Loading></Loading>}> element={
<RegisterForm /> <Suspense fallback={<Loading></Loading>}>
</Suspense> <Chat />
} </Suspense>
/> }
<Route />
path='/reset' <Route path='*' element={<NotFound />} />
element={ </Routes>
<Suspense fallback={<Loading></Loading>}> </>
<PasswordResetForm />
</Suspense>
}
/>
<Route
path='/oauth/github'
element={
<Suspense fallback={<Loading></Loading>}>
<GitHubOAuth />
</Suspense>
}
/>
<Route
path='/setting'
element={
<PrivateRoute>
<Suspense fallback={<Loading></Loading>}>
<Setting />
</Suspense>
</PrivateRoute>
}
/>
<Route
path='/topup'
element={
<PrivateRoute>
<Suspense fallback={<Loading></Loading>}>
<TopUp />
</Suspense>
</PrivateRoute>
}
/>
<Route
path='/log'
element={
<PrivateRoute>
<Log />
</PrivateRoute>
}
/>
<Route
path='/detail'
element={
<PrivateRoute>
<Suspense fallback={<Loading></Loading>}>
<Detail />
</Suspense>
</PrivateRoute>
}
/>
<Route
path='/midjourney'
element={
<PrivateRoute>
<Suspense fallback={<Loading></Loading>}>
<Midjourney />
</Suspense>
</PrivateRoute>
}
/>
<Route
path='/task'
element={
<PrivateRoute>
<Suspense fallback={<Loading></Loading>}>
<Task />
</Suspense>
</PrivateRoute>
}
/>
<Route
path='/pricing'
element={
<Suspense fallback={<Loading></Loading>}>
<Pricing />
</Suspense>
}
/>
<Route
path='/about'
element={
<Suspense fallback={<Loading></Loading>}>
<About />
</Suspense>
}
/>
<Route
path='/chat'
element={
<Suspense fallback={<Loading></Loading>}>
<Chat />
</Suspense>
}
/>
<Route path='*' element={<NotFound />} />
</Routes>
</Layout.Content>
</Layout>
); );
} }

View File

@@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react';
import { getFooterHTML, getSystemName } from '../helpers'; import { getFooterHTML, getSystemName } from '../helpers';
import { Layout, Tooltip } from '@douyinfe/semi-ui'; import { Layout, Tooltip } from '@douyinfe/semi-ui';
const Footer = () => { const FooterBar = () => {
const systemName = getSystemName(); const systemName = getSystemName();
const [footer, setFooter] = useState(getFooterHTML()); const [footer, setFooter] = useState(getFooterHTML());
let remainCheckTimes = 5; let remainCheckTimes = 5;
@@ -56,19 +56,17 @@ const Footer = () => {
}, []); }, []);
return ( return (
<Layout> <div style={{ textAlign: 'center' }}>
<Layout.Content style={{ textAlign: 'center' }}> {footer ? (
{footer ? ( <div
<div className='custom-footer'
className='custom-footer' dangerouslySetInnerHTML={{ __html: footer }}
dangerouslySetInnerHTML={{ __html: footer }} ></div>
></div> ) : (
) : ( defaultFooter
defaultFooter )}
)} </div>
</Layout.Content>
</Layout>
); );
}; };
export default Footer; export default FooterBar;

View File

@@ -3,14 +3,23 @@ import { Link, useNavigate } from 'react-router-dom';
import { UserContext } from '../context/User'; import { UserContext } from '../context/User';
import { useSetTheme, useTheme } from '../context/Theme'; import { useSetTheme, useTheme } from '../context/Theme';
import { API, getLogo, getSystemName, showSuccess } from '../helpers'; import { API, getLogo, getSystemName, isMobile, showSuccess } from '../helpers';
import '../index.css'; import '../index.css';
import fireworks from 'react-fireworks'; import fireworks from 'react-fireworks';
import { IconHelpCircle, IconKey, IconUser } from '@douyinfe/semi-icons'; import {
IconHelpCircle,
IconHome,
IconHomeStroked,
IconKey,
IconNoteMoneyStroked,
IconPriceTag,
IconUser
} from '@douyinfe/semi-icons';
import { Avatar, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui'; import { Avatar, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
import { stringToColor } from '../helpers/render'; import { stringToColor } from '../helpers/render';
import Text from '@douyinfe/semi-ui/lib/es/typography/text';
// HeaderBar Buttons // HeaderBar Buttons
let headerButtons = [ let headerButtons = [
@@ -22,6 +31,21 @@ let headerButtons = [
}, },
]; ];
let buttons = [
{
text: '首页',
itemKey: 'home',
to: '/',
icon: <IconHomeStroked />,
},
// {
// text: '模型价格',
// itemKey: 'pricing',
// to: '/pricing',
// icon: <IconNoteMoneyStroked />,
// },
];
if (localStorage.getItem('chat_link')) { if (localStorage.getItem('chat_link')) {
headerButtons.splice(1, 0, { headerButtons.splice(1, 0, {
name: '聊天', name: '聊天',
@@ -90,6 +114,7 @@ const HeaderBar = () => {
about: '/about', about: '/about',
login: '/login', login: '/login',
register: '/register', register: '/register',
home: '/',
}; };
return ( return (
<Link <Link
@@ -103,6 +128,18 @@ const HeaderBar = () => {
selectedKeys={[]} selectedKeys={[]}
// items={headerButtons} // items={headerButtons}
onSelect={(key) => {}} onSelect={(key) => {}}
header={isMobile()?{
logo: (
<img src={logo} alt='logo' style={{ marginRight: '0.75em' }} />
),
}:{
logo: (
<img src={logo} alt='logo' />
),
text: systemName,
}}
items={buttons}
footer={ footer={
<> <>
{isNewYear && ( {isNewYear && (
@@ -121,15 +158,19 @@ const HeaderBar = () => {
</Dropdown> </Dropdown>
)} )}
<Nav.Item itemKey={'about'} icon={<IconHelpCircle />} /> <Nav.Item itemKey={'about'} icon={<IconHelpCircle />} />
<Switch <>
checkedText='🌞' {!isMobile() && (
size={'large'} <Switch
checked={theme === 'dark'} checkedText='🌞'
uncheckedText='🌙' size={'large'}
onChange={(checked) => { checked={theme === 'dark'}
setTheme(checked); uncheckedText='🌙'
}} onChange={(checked) => {
/> setTheme(checked);
}}
/>
)}
</>
{userState.user ? ( {userState.user ? (
<> <>
<Dropdown <Dropdown
@@ -155,7 +196,7 @@ const HeaderBar = () => {
<Nav.Item <Nav.Item
itemKey={'login'} itemKey={'login'}
text={'登录'} text={'登录'}
icon={<IconKey />} // icon={<IconKey />}
/> />
<Nav.Item <Nav.Item
itemKey={'register'} itemKey={'register'}

View File

@@ -17,7 +17,7 @@ import {
IconCalendarClock, IconChecklistStroked, IconCalendarClock, IconChecklistStroked,
IconComment, IconComment,
IconCreditCard, IconCreditCard,
IconGift, IconGift, IconHelpCircle,
IconHistogram, IconHistogram,
IconHome, IconHome,
IconImage, IconImage,
@@ -25,10 +25,12 @@ import {
IconLayers, IconLayers,
IconPriceTag, IconPriceTag,
IconSetting, IconSetting,
IconUser, IconUser
} from '@douyinfe/semi-icons'; } from '@douyinfe/semi-icons';
import { Layout, Nav } from '@douyinfe/semi-ui'; import { Avatar, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
import { setStatusData } from '../helpers/data.js'; import { setStatusData } from '../helpers/data.js';
import { stringToColor } from '../helpers/render.js';
import { useSetTheme, useTheme } from '../context/Theme/index.js';
// HeaderBar Buttons // HeaderBar Buttons
@@ -43,6 +45,8 @@ const SiderBar = () => {
const systemName = getSystemName(); const systemName = getSystemName();
const logo = getLogo(); const logo = getLogo();
const [isCollapsed, setIsCollapsed] = useState(defaultIsCollapsed); const [isCollapsed, setIsCollapsed] = useState(defaultIsCollapsed);
const theme = useTheme();
const setTheme = useSetTheme();
const routerMap = { const routerMap = {
home: '/', home: '/',
@@ -63,11 +67,17 @@ const SiderBar = () => {
const headerButtons = useMemo( const headerButtons = useMemo(
() => [ () => [
// {
// text: '首页',
// itemKey: 'home',
// to: '/',
// icon: <IconHome />,
// },
{ {
text: '首页', text: '模型价格',
itemKey: 'home', itemKey: 'pricing',
to: '/', to: '/pricing',
icon: <IconHome />, icon: <IconPriceTag />,
}, },
{ {
text: '渠道', text: '渠道',
@@ -104,12 +114,6 @@ const SiderBar = () => {
to: '/topup', to: '/topup',
icon: <IconCreditCard />, icon: <IconCreditCard />,
}, },
{
text: '模型价格',
itemKey: 'pricing',
to: '/pricing',
icon: <IconPriceTag />,
},
{ {
text: '用户管理', text: '用户管理',
itemKey: 'user', itemKey: 'user',
@@ -205,48 +209,58 @@ const SiderBar = () => {
return ( return (
<> <>
<Layout> <Nav
<div style={{ height: '100%' }}> style={{ maxWidth: 220, height: '100%' }}
<Nav defaultIsCollapsed={
// bodyStyle={{ maxWidth: 200 }} isMobile() ||
style={{ maxWidth: 200 }} localStorage.getItem('default_collapse_sidebar') === 'true'
defaultIsCollapsed={ }
isMobile() || isCollapsed={isCollapsed}
localStorage.getItem('default_collapse_sidebar') === 'true' onCollapseChange={(collapsed) => {
} setIsCollapsed(collapsed);
isCollapsed={isCollapsed} }}
onCollapseChange={(collapsed) => { selectedKeys={selectedKeys}
setIsCollapsed(collapsed); renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
}} return (
selectedKeys={selectedKeys} <Link
renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => { style={{ textDecoration: 'none' }}
return ( to={routerMap[props.itemKey]}
<Link >
style={{ textDecoration: 'none' }} {itemElement}
to={routerMap[props.itemKey]} </Link>
> );
{itemElement} }}
</Link> items={headerButtons}
); onSelect={(key) => {
}} setSelectedKeys([key.itemKey]);
items={headerButtons} }}
onSelect={(key) => { // header={{
setSelectedKeys([key.itemKey]); // logo: (
}} // <img src={logo} alt='logo' style={{ marginRight: '0.75em' }} />
header={{ // ),
logo: ( // text: systemName,
<img src={logo} alt='logo' style={{ marginRight: '0.75em' }} /> // }}
), // footer={{
text: systemName, // text: '© 2021 NekoAPI',
}} // }}
// footer={{ footer={
// text: '© 2021 NekoAPI', <>
// }} {isMobile() && (
> <Switch
<Nav.Footer collapseButton={true}></Nav.Footer> checkedText='🌞'
</Nav> size={'small'}
</div> checked={theme === 'dark'}
</Layout> uncheckedText='🌙'
onChange={(checked) => {
setTheme(checked);
}}
/>
)}
</>
}
>
<Nav.Footer collapseButton={true}></Nav.Footer>
</Nav>
</> </>
); );
}; };

View File

@@ -9,11 +9,12 @@ body {
scrollbar-width: none; scrollbar-width: none;
color: var(--semi-color-text-0) !important; color: var(--semi-color-text-0) !important;
background-color: var(--semi-color-bg-0) !important; background-color: var(--semi-color-bg-0) !important;
height: 100%; height: 100vh;
} }
#root { #root {
height: 100%; height: 100vh;
flex-direction: column;
} }
@media only screen and (max-width: 767px) { @media only screen and (max-width: 767px) {
@@ -50,9 +51,9 @@ body {
} }
} }
.semi-layout { /*.semi-layout {*/
height: 100%; /* height: 100%;*/
} /*}*/
.tableShow { .tableShow {
display: revert; display: revert;

View File

@@ -3,7 +3,6 @@ import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import App from './App'; import App from './App';
import HeaderBar from './components/HeaderBar'; import HeaderBar from './components/HeaderBar';
import Footer from './components/Footer';
import 'semantic-ui-offline/semantic.min.css'; import 'semantic-ui-offline/semantic.min.css';
import './index.css'; import './index.css';
import { UserProvider } from './context/User'; import { UserProvider } from './context/User';
@@ -13,35 +12,36 @@ import { StatusProvider } from './context/Status';
import { Layout } from '@douyinfe/semi-ui'; import { Layout } from '@douyinfe/semi-ui';
import SiderBar from './components/SiderBar'; import SiderBar from './components/SiderBar';
import { ThemeProvider } from './context/Theme'; import { ThemeProvider } from './context/Theme';
import FooterBar from './components/Footer';
// initialization // initialization
const root = ReactDOM.createRoot(document.getElementById('root')); const root = ReactDOM.createRoot(document.getElementById('root'));
const { Sider, Content, Header } = Layout; const { Sider, Content, Header, Footer } = Layout;
root.render( root.render(
<React.StrictMode> <React.StrictMode>
<StatusProvider> <StatusProvider>
<UserProvider> <UserProvider>
<BrowserRouter> <BrowserRouter>
<ThemeProvider> <ThemeProvider>
<Layout> <Layout style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
<Sider> <Header>
<SiderBar /> <HeaderBar />
</Sider> </Header>
<Layout> <Layout style={{ flex: 1, overflow: 'hidden' }}>
<Header> <Sider>
<HeaderBar /> <SiderBar />
</Header> </Sider>
<Content <Layout>
style={{ <Content
padding: '24px', style={{ overflowY: 'auto', padding: '24px' }}
}} >
> <App />
<App /> </Content>
</Content> <Layout.Footer>
<Layout.Footer> <FooterBar></FooterBar>
<Footer></Footer> </Layout.Footer>
</Layout.Footer> </Layout>
</Layout> </Layout>
<ToastContainer /> <ToastContainer />
</Layout> </Layout>