Browse Source

登录页完善

CaIon 2 years ago
parent
commit
83050646f9

+ 1 - 1
web/public/index.html

@@ -9,7 +9,7 @@
             name="description"
             content="OpenAI 接口聚合管理,支持多种渠道包括 Azure,可用于二次分发管理 key,仅单可执行文件,已打包好 Docker 镜像,一键部署,开箱即用"
     />
-    <title>MiaoKo API</title>
+    <title>New API</title>
   </head>
   <body>
     <noscript>You need to enable JavaScript to run this app.</noscript>

+ 5 - 80
web/src/components/HeaderBar.js

@@ -57,9 +57,6 @@ const HeaderBar = () => {
         navigate('/login');
     }
 
-    const toggleSidebar = () => {
-        setShowSidebar(!showSidebar);
-    };
 
     const renderButtons = (isMobile) => {
         return headerButtons.map((button) => {
@@ -84,82 +81,6 @@ const HeaderBar = () => {
             );
         });
     };
-
-    // if (isMobile()) {
-    //     return (
-    //         <>
-    //             <Menu
-    //                 borderless
-    //                 size='large'
-    //                 style={
-    //                     showSidebar
-    //                         ? {
-    //                             borderBottom: 'none',
-    //                             marginBottom: '0',
-    //                             borderTop: 'none',
-    //                             height: '51px'
-    //                         }
-    //                         : {borderTop: 'none', height: '52px'}
-    //                 }
-    //             >
-    //                 <Container>
-    //                     <Menu.Item as={Link} to='/'>
-    //                         <img
-    //                             src={logo}
-    //                             alt='logo'
-    //                             style={{marginRight: '0.75em'}}
-    //                         />
-    //                         <div style={{fontSize: '20px'}}>
-    //                             <b>{systemName}</b>
-    //                         </div>
-    //                     </Menu.Item>
-    //                     <Menu.Menu position='right'>
-    //                         <Menu.Item onClick={toggleSidebar}>
-    //                             <Icon name={showSidebar ? 'close' : 'sidebar'}/>
-    //                         </Menu.Item>
-    //                     </Menu.Menu>
-    //                 </Container>
-    //             </Menu>
-    //
-    //             {showSidebar ? (
-    //                 <Segment style={{marginTop: 0, borderTop: '0'}}>
-    //                     <Menu secondary vertical style={{ width: '100%', margin: 0 }}>
-    //                       {renderButtons(true)}
-    //                       <Menu.Item>
-    //                         {userState.user ? (
-    //                           <Button onClick={logout}>注销</Button>
-    //                         ) : (
-    //                           <>
-    //                             <Button
-    //                               onClick={() => {
-    //                                 setShowSidebar(false);
-    //                                 navigate('/login');
-    //                               }}
-    //                             >
-    //                               登录
-    //                             </Button>
-    //                             <Button
-    //                               onClick={() => {
-    //                                 setShowSidebar(false);
-    //                                 navigate('/register');
-    //                               }}
-    //                             >
-    //                               注册
-    //                             </Button>
-    //                           </>
-    //                         )}
-    //                       </Menu.Item>
-    //                     </Menu>
-    //
-    //                 </Segment>
-    //             ) : (
-    //                 <></>
-    //             )}
-    //
-    //
-    //         </>
-    //     );
-    // }
     const switchMode = (model) => {
         const body = document.body;
         if (!model) {
@@ -178,6 +99,8 @@ const HeaderBar = () => {
                         renderWrapper={({itemElement, isSubNav, isInSubNav, props}) => {
                             const routerMap = {
                                 about: "/about",
+                                login: "/login",
+                                register: "/register",
                             };
                             return (
                                 <Link
@@ -190,7 +113,9 @@ const HeaderBar = () => {
                         }}
                         selectedKeys={[]}
                         // items={headerButtons}
-                        onSelect={key => console.log(key)}
+                        onSelect={key => {
+
+                        }}
                         footer={
                             <>
                                 <Nav.Item itemKey={'about'} icon={<IconHelpCircle />} />

+ 221 - 203
web/src/components/LoginForm.js

@@ -1,219 +1,237 @@
-import React, { useContext, useEffect, useState } from 'react';
-import { Button, Divider, Form, Grid, Header, Image, Message, Modal, Segment } from 'semantic-ui-react';
-import { Link, useNavigate, useSearchParams } from 'react-router-dom';
-import { UserContext } from '../context/User';
-import {API, getLogo, showError, showInfo, showSuccess, showWarning} from '../helpers';
-import { onGitHubOAuthClicked } from './utils';
+import React, {useContext, useEffect, useState} from 'react';
+import {
+    Modal,
+} from 'semantic-ui-react';
+import {Link, useNavigate, useSearchParams} from 'react-router-dom';
+import {UserContext} from '../context/User';
+import {API, getLogo, isMobile, showError, showInfo, showSuccess, showWarning} from '../helpers';
+import {onGitHubOAuthClicked} from './utils';
 import Turnstile from "react-turnstile";
+import {Layout, Card, Image, Form, Button, Divider} from "@douyinfe/semi-ui";
+import Title from "@douyinfe/semi-ui/lib/es/typography/title";
+import Text from "@douyinfe/semi-ui/lib/es/typography/text";
 
-const LoginForm = () => {
-  const [inputs, setInputs] = useState({
-    username: '',
-    password: '',
-    wechat_verification_code: ''
-  });
-  const [searchParams, setSearchParams] = useSearchParams();
-  const [submitted, setSubmitted] = useState(false);
-  const { username, password } = inputs;
-  const [userState, userDispatch] = useContext(UserContext);
-  const [turnstileEnabled, setTurnstileEnabled] = useState(false);
-  const [turnstileSiteKey, setTurnstileSiteKey] = useState('');
-  const [turnstileToken, setTurnstileToken] = useState('');
-  let navigate = useNavigate();
-  const [status, setStatus] = useState({});
-  const logo = getLogo();
+import {IconGithubLogo} from '@douyinfe/semi-icons';
 
-  useEffect(() => {
-    if (searchParams.get('expired')) {
-      showError('未登录或登录已过期,请重新登录!');
-    }
-    let status = localStorage.getItem('status');
-    if (status) {
-      status = JSON.parse(status);
-      setStatus(status);
-      if (status.turnstile_check) {
-        setTurnstileEnabled(true);
-        setTurnstileSiteKey(status.turnstile_site_key);
-      }
-    }
-  }, []);
+const LoginForm = () => {
+    const [inputs, setInputs] = useState({
+        username: '',
+        password: '',
+        wechat_verification_code: ''
+    });
+    const [searchParams, setSearchParams] = useSearchParams();
+    const [submitted, setSubmitted] = useState(false);
+    const {username, password} = inputs;
+    const [userState, userDispatch] = useContext(UserContext);
+    const [turnstileEnabled, setTurnstileEnabled] = useState(false);
+    const [turnstileSiteKey, setTurnstileSiteKey] = useState('');
+    const [turnstileToken, setTurnstileToken] = useState('');
+    let navigate = useNavigate();
+    const [status, setStatus] = useState({});
+    const logo = getLogo();
 
-  const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false);
+    useEffect(() => {
+        if (searchParams.get('expired')) {
+            showError('未登录或登录已过期,请重新登录!');
+        }
+        let status = localStorage.getItem('status');
+        if (status) {
+            status = JSON.parse(status);
+            setStatus(status);
+            if (status.turnstile_check) {
+                setTurnstileEnabled(true);
+                setTurnstileSiteKey(status.turnstile_site_key);
+            }
+        }
+    }, []);
 
-  const onWeChatLoginClicked = () => {
-    setShowWeChatLoginModal(true);
-  };
+    const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false);
 
-  const onSubmitWeChatVerificationCode = async () => {
-    if (turnstileEnabled && turnstileToken === '') {
-      showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
-      return;
-    }
-    const res = await API.get(
-      `/api/oauth/wechat?code=${inputs.wechat_verification_code}`
-    );
-    const { success, message, data } = res.data;
-    if (success) {
-      userDispatch({ type: 'login', payload: data });
-      localStorage.setItem('user', JSON.stringify(data));
-      navigate('/');
-      showSuccess('登录成功!');
-      setShowWeChatLoginModal(false);
-    } else {
-      showError(message);
-    }
-  };
+    const onWeChatLoginClicked = () => {
+        setShowWeChatLoginModal(true);
+    };
 
-  function handleChange(e) {
-    const { name, value } = e.target;
-    setInputs((inputs) => ({ ...inputs, [name]: value }));
-  }
+    const onSubmitWeChatVerificationCode = async () => {
+        if (turnstileEnabled && turnstileToken === '') {
+            showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
+            return;
+        }
+        const res = await API.get(
+            `/api/oauth/wechat?code=${inputs.wechat_verification_code}`
+        );
+        const {success, message, data} = res.data;
+        if (success) {
+            userDispatch({type: 'login', payload: data});
+            localStorage.setItem('user', JSON.stringify(data));
+            navigate('/');
+            showSuccess('登录成功!');
+            setShowWeChatLoginModal(false);
+        } else {
+            showError(message);
+        }
+    };
 
-  async function handleSubmit(e) {
-    if (turnstileEnabled && turnstileToken === '') {
-      showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
-      return;
+    function handleChange(name, value) {
+        setInputs((inputs) => ({...inputs, [name]: value}));
     }
-    setSubmitted(true);
-    if (username && password) {
-      const res = await API.post(`/api/user/login?turnstile=${turnstileToken}`, {
-        username,
-        password
-      });
-      const { success, message, data } = res.data;
-      if (success) {
-        userDispatch({ type: 'login', payload: data });
-        localStorage.setItem('user', JSON.stringify(data));
-        if (username === 'root' && password === '123456') {
-          navigate('/user/edit');
-          showSuccess('登录成功!');
-          showWarning('请立刻修改默认密码!');
+
+    async function handleSubmit(e) {
+        if (turnstileEnabled && turnstileToken === '') {
+            showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
+            return;
+        }
+        setSubmitted(true);
+        if (username && password) {
+            const res = await API.post(`/api/user/login?turnstile=${turnstileToken}`, {
+                username,
+                password
+            });
+            const {success, message, data} = res.data;
+            if (success) {
+                userDispatch({type: 'login', payload: data});
+                localStorage.setItem('user', JSON.stringify(data));
+                if (username === 'root' && password === '123456') {
+                    navigate('/user/edit');
+                    showSuccess('登录成功!');
+                    showWarning('请立刻修改默认密码!');
+                } else {
+                    navigate('/token');
+                    showSuccess('登录成功!');
+                }
+            } else {
+                showError(message);
+            }
         } else {
-          navigate('/token');
-          showSuccess('登录成功!');
+            showError('请输入用户名和密码!');
         }
-      } else {
-        showError(message);
-      }
     }
-  }
 
-  return (
-    <Grid textAlign='center' style={{ marginTop: '48px' }}>
-      <Grid.Column style={{ maxWidth: 450 }}>
-        <Header as='h2' color='' textAlign='center'>
-          <Image src={logo} /> 用户登录
-        </Header>
-        <Form size='large'>
-          <Segment>
-            <Form.Input
-              fluid
-              icon='user'
-              iconPosition='left'
-              placeholder='用户名'
-              name='username'
-              value={username}
-              onChange={handleChange}
-            />
-            <Form.Input
-              fluid
-              icon='lock'
-              iconPosition='left'
-              placeholder='密码'
-              name='password'
-              type='password'
-              value={password}
-              onChange={handleChange}
-            />
-            {turnstileEnabled ? (
-                <Turnstile
-                    sitekey={turnstileSiteKey}
-                    onVerify={(token) => {
-                      setTurnstileToken(token);
-                    }}
-                />
-            ) : (
-                <></>
-            )}
-            <Button color='green' fluid size='large' onClick={handleSubmit}>
-              登录
-            </Button>
-          </Segment>
-        </Form>
-        <Message>
-          忘记密码?
-          <Link to='/reset' className='btn btn-link'>
-            点击重置
-          </Link>
-          ; 没有账户?
-          <Link to='/register' className='btn btn-link'>
-            点击注册
-          </Link>
-        </Message>
-        {status.github_oauth || status.wechat_login ? (
-          <>
-            <Divider horizontal>Or</Divider>
-            {status.github_oauth ? (
-              <Button
-                circular
-                color='black'
-                icon='github'
-                onClick={() => onGitHubOAuthClicked(status.github_client_id)}
-              />
-            ) : (
-              <></>
-            )}
-            {status.wechat_login ? (
-              <Button
-                circular
-                color='green'
-                icon='wechat'
-                onClick={onWeChatLoginClicked}
-              />
-            ) : (
-              <></>
-            )}
-          </>
-        ) : (
-          <></>
-        )}
-        <Modal
-          onClose={() => setShowWeChatLoginModal(false)}
-          onOpen={() => setShowWeChatLoginModal(true)}
-          open={showWeChatLoginModal}
-          size={'mini'}
-        >
-          <Modal.Content>
-            <Modal.Description>
-              <Image src={status.wechat_qrcode} fluid />
-              <div style={{ textAlign: 'center' }}>
-                <p>
-                  微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效)
-                </p>
-              </div>
-              <Form size='large'>
-                <Form.Input
-                  fluid
-                  placeholder='验证码'
-                  name='wechat_verification_code'
-                  value={inputs.wechat_verification_code}
-                  onChange={handleChange}
-                />
-                <Button
-                  color=''
-                  fluid
-                  size='large'
-                  onClick={onSubmitWeChatVerificationCode}
-                >
-                  登录
-                </Button>
-              </Form>
-            </Modal.Description>
-          </Modal.Content>
-        </Modal>
-      </Grid.Column>
-    </Grid>
-  );
+    return (
+        <div>
+            <Layout>
+                <Layout.Header>
+                </Layout.Header>
+                <Layout.Content>
+                    <div style={{justifyContent: 'center', display: "flex", marginTop: 120}}>
+                        <div style={{width: 500}}>
+                            <Card>
+                                <Title heading={2} style={{textAlign: 'center'}}>
+                                    用户登录
+                                </Title>
+                                <Form>
+                                    <Form.Input
+                                        field={'username'}
+                                        label={'用户名'}
+                                        placeholder='用户名'
+                                        name='username'
+                                        onChange={(value) => handleChange('username', value)}
+                                    />
+                                    <Form.Input
+                                        field={'password'}
+                                        label={'密码'}
+                                        placeholder='密码'
+                                        name='password'
+                                        type='password'
+                                        onChange={(value) => handleChange('password', value)}
+                                    />
+
+                                    <Button theme='solid' style={{width: '100%'}} type={'primary'} size='large'
+                                            htmlType={'submit'} onClick={handleSubmit}>
+                                        登录
+                                    </Button>
+                                </Form>
+                                <div style={{display: 'flex', justifyContent: 'space-between', marginTop: 20}}>
+                                    <Text>
+                                        没有账号请先 <Link to='/register'>注册账号</Link>
+                                    </Text>
+                                    <Text>
+                                        忘记密码 <Link to='/reset'>点击重置</Link>
+                                    </Text>
+                                </div>
+                                {status.github_oauth || status.wechat_login ? (
+                                    <>
+                                        <Divider margin='12px' align='center'>
+                                            第三方登录
+                                        </Divider>
+                                        <div style={{display: 'flex', justifyContent: 'center', marginTop: 20}}>
+                                            {status.github_oauth ? (
+                                                <Button
+                                                    type='primary'
+                                                    icon={<IconGithubLogo/>}
+                                                    onClick={() => onGitHubOAuthClicked(status.github_client_id)}
+                                                />
+                                            ) : (
+                                                <></>
+                                            )}
+                                            {status.wechat_login ? (
+                                                <Button
+                                                    circular
+                                                    color='green'
+                                                    icon='wechat'
+                                                    onClick={onWeChatLoginClicked}
+                                                />
+                                            ) : (
+                                                <></>
+                                            )}
+                                        </div>
+                                    </>
+                                ) : (
+                                    <></>
+                                )}
+                                <Modal
+                                    onClose={() => setShowWeChatLoginModal(false)}
+                                    onOpen={() => setShowWeChatLoginModal(true)}
+                                    open={showWeChatLoginModal}
+                                    size={'mini'}
+                                >
+                                    <Modal.Content>
+                                        <Modal.Description>
+                                            <Image src={status.wechat_qrcode} fluid/>
+                                            <div style={{textAlign: 'center'}}>
+                                                <p>
+                                                    微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效)
+                                                </p>
+                                            </div>
+                                            <Form size='large'>
+                                                <Form.Input
+                                                    field={'wechat_verification_code'}
+                                                    placeholder='验证码'
+                                                    name='wechat_verification_code'
+                                                    value={inputs.wechat_verification_code}
+                                                    onChange={handleChange}
+                                                />
+                                                <Button
+                                                    color=''
+                                                    fluid
+                                                    size='large'
+                                                    onClick={onSubmitWeChatVerificationCode}
+                                                >
+                                                    登录
+                                                </Button>
+                                            </Form>
+                                        </Modal.Description>
+                                    </Modal.Content>
+                                </Modal>
+                            </Card>
+                            {turnstileEnabled ? (
+                                <div style={{display: 'flex', justifyContent: 'center', marginTop: 20}}>
+                                    <Turnstile
+                                        sitekey={turnstileSiteKey}
+                                        onVerify={(token) => {
+                                            setTurnstileToken(token);
+                                        }}
+                                    />
+                                </div>
+                            ) : (
+                                <></>
+                            )}
+                        </div>
+                    </div>
+
+                </Layout.Content>
+            </Layout>
+        </div>
+    );
 };
 
 export default LoginForm;

+ 1 - 1
web/src/components/SiderBar.js

@@ -179,7 +179,7 @@ const HeaderBar = () => {
                         }}
                         header={{
                             logo: <img src={logo} alt='logo' style={{marginRight: '0.75em'}}/>,
-                            text: 'MiaoKoAPI'
+                            text: systemName,
                         }}
                         // footer={{
                         //   text: '© 2021 NekoAPI',

+ 1 - 0
web/src/components/TokensTable.js

@@ -457,6 +457,7 @@ const TokensTable = () => {
                 total: tokenCount,
                 showSizeChanger: true,
                 pageSizeOptions: [10, 20, 50, 100],
+                formatPageText: (page) => `第 ${page.currentStart} - ${page.currentEnd} 条,共 ${tokens.length} 条`,
                 onPageSizeChange: (size) => {
                     setPageSize(size);
                     setActivePage(1);

+ 1 - 1
web/src/helpers/utils.js

@@ -23,7 +23,7 @@ export function isRoot() {
 
 export function getSystemName() {
   let system_name = localStorage.getItem('system_name');
-  if (!system_name) return 'Neko API';
+  if (!system_name) return 'New API';
   return system_name;
 }