Commit add3b05d by CaIon

chore: reformat code

parent 7c547cbc
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
// TODO: when a new api is enabled, check the pricing here // TODO: when a new api is enabled, check the pricing here
// 1 === $0.002 / 1K tokens // 1 === $0.002 / 1K tokens
// 1 === ¥0.014 / 1k tokens // 1 === ¥0.014 / 1k tokens
var ModelRatio = map[string]float64{ var DefaultModelRatio = map[string]float64{
//"midjourney": 50, //"midjourney": 50,
"gpt-4-gizmo-*": 15, "gpt-4-gizmo-*": 15,
"gpt-4": 15, "gpt-4": 15,
...@@ -115,6 +115,7 @@ var DefaultModelPrice = map[string]float64{ ...@@ -115,6 +115,7 @@ var DefaultModelPrice = map[string]float64{
} }
var ModelPrice = map[string]float64{} var ModelPrice = map[string]float64{}
var ModelRatio = map[string]float64{}
func ModelPrice2JSONString() string { func ModelPrice2JSONString() string {
if len(ModelPrice) == 0 { if len(ModelPrice) == 0 {
...@@ -150,6 +151,9 @@ func GetModelPrice(name string, printErr bool) float64 { ...@@ -150,6 +151,9 @@ func GetModelPrice(name string, printErr bool) float64 {
} }
func ModelRatio2JSONString() string { func ModelRatio2JSONString() string {
if len(ModelRatio) == 0 {
ModelRatio = DefaultModelRatio
}
jsonBytes, err := json.Marshal(ModelRatio) jsonBytes, err := json.Marshal(ModelRatio)
if err != nil { if err != nil {
SysError("error marshalling model ratio: " + err.Error()) SysError("error marshalling model ratio: " + err.Error())
...@@ -163,6 +167,9 @@ func UpdateModelRatioByJSONString(jsonStr string) error { ...@@ -163,6 +167,9 @@ func UpdateModelRatioByJSONString(jsonStr string) error {
} }
func GetModelRatio(name string) float64 { func GetModelRatio(name string) float64 {
if len(ModelRatio) == 0 {
ModelRatio = DefaultModelRatio
}
if strings.HasPrefix(name, "gpt-4-gizmo") { if strings.HasPrefix(name, "gpt-4-gizmo") {
name = "gpt-4-gizmo-*" name = "gpt-4-gizmo-*"
} }
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"prettier": "^2.7.1", "prettier": "2.8.8",
"typescript": "4.4.2" "typescript": "4.4.2"
}, },
"prettier": { "prettier": {
......
...@@ -8,12 +8,11 @@ import LoginForm from './components/LoginForm'; ...@@ -8,12 +8,11 @@ import LoginForm from './components/LoginForm';
import NotFound from './pages/NotFound'; import NotFound from './pages/NotFound';
import Setting from './pages/Setting'; import Setting from './pages/Setting';
import EditUser from './pages/User/EditUser'; import EditUser from './pages/User/EditUser';
import { API, getLogo, getSystemName, showError, showNotice } from './helpers'; import { getLogo, getSystemName } from './helpers';
import PasswordResetForm from './components/PasswordResetForm'; import PasswordResetForm from './components/PasswordResetForm';
import GitHubOAuth from './components/GitHubOAuth'; import GitHubOAuth from './components/GitHubOAuth';
import PasswordResetConfirm from './components/PasswordResetConfirm'; import PasswordResetConfirm from './components/PasswordResetConfirm';
import { UserContext } from './context/User'; import { UserContext } from './context/User';
import { StatusContext } from './context/Status';
import Channel from './pages/Channel'; import Channel from './pages/Channel';
import Token from './pages/Token'; import Token from './pages/Token';
import EditChannel from './pages/Channel/EditChannel'; import EditChannel from './pages/Channel/EditChannel';
...@@ -21,12 +20,13 @@ import Redemption from './pages/Redemption'; ...@@ -21,12 +20,13 @@ import Redemption from './pages/Redemption';
import TopUp from './pages/TopUp'; import TopUp from './pages/TopUp';
import Log from './pages/Log'; import Log from './pages/Log';
import Chat from './pages/Chat'; import Chat from './pages/Chat';
import {Layout} from "@douyinfe/semi-ui"; import { Layout } from '@douyinfe/semi-ui';
import Midjourney from "./pages/Midjourney"; import Midjourney from './pages/Midjourney';
import Detail from "./pages/Detail"; import Detail from './pages/Detail';
const Home = lazy(() => import('./pages/Home')); const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About')); const About = lazy(() => import('./pages/About'));
function App() { function App() {
const [userState, userDispatch] = useContext(UserContext); const [userState, userDispatch] = useContext(UserContext);
// const [statusState, statusDispatch] = useContext(StatusContext); // const [statusState, statusDispatch] = useContext(StatusContext);
...@@ -47,7 +47,7 @@ function App() { ...@@ -47,7 +47,7 @@ function App() {
} }
let logo = getLogo(); let logo = getLogo();
if (logo) { if (logo) {
let linkElement = document.querySelector("link[rel~='icon']"); let linkElement = document.querySelector('link[rel~=\'icon\']');
if (linkElement) { if (linkElement) {
linkElement.href = logo; linkElement.href = logo;
} }
...@@ -59,7 +59,7 @@ function App() { ...@@ -59,7 +59,7 @@ function App() {
<Layout.Content> <Layout.Content>
<Routes> <Routes>
<Route <Route
path='/' path="/"
element={ element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<Home /> <Home />
...@@ -67,7 +67,7 @@ function App() { ...@@ -67,7 +67,7 @@ function App() {
} }
/> />
<Route <Route
path='/channel' path="/channel"
element={ element={
<PrivateRoute> <PrivateRoute>
<Channel /> <Channel />
...@@ -75,7 +75,7 @@ function App() { ...@@ -75,7 +75,7 @@ function App() {
} }
/> />
<Route <Route
path='/channel/edit/:id' path="/channel/edit/:id"
element={ element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<EditChannel /> <EditChannel />
...@@ -83,7 +83,7 @@ function App() { ...@@ -83,7 +83,7 @@ function App() {
} }
/> />
<Route <Route
path='/channel/add' path="/channel/add"
element={ element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<EditChannel /> <EditChannel />
...@@ -91,7 +91,7 @@ function App() { ...@@ -91,7 +91,7 @@ function App() {
} }
/> />
<Route <Route
path='/token' path="/token"
element={ element={
<PrivateRoute> <PrivateRoute>
<Token /> <Token />
...@@ -99,7 +99,7 @@ function App() { ...@@ -99,7 +99,7 @@ function App() {
} }
/> />
<Route <Route
path='/redemption' path="/redemption"
element={ element={
<PrivateRoute> <PrivateRoute>
<Redemption /> <Redemption />
...@@ -107,7 +107,7 @@ function App() { ...@@ -107,7 +107,7 @@ function App() {
} }
/> />
<Route <Route
path='/user' path="/user"
element={ element={
<PrivateRoute> <PrivateRoute>
<User /> <User />
...@@ -115,7 +115,7 @@ function App() { ...@@ -115,7 +115,7 @@ function App() {
} }
/> />
<Route <Route
path='/user/edit/:id' path="/user/edit/:id"
element={ element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<EditUser /> <EditUser />
...@@ -123,7 +123,7 @@ function App() { ...@@ -123,7 +123,7 @@ function App() {
} }
/> />
<Route <Route
path='/user/edit' path="/user/edit"
element={ element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<EditUser /> <EditUser />
...@@ -131,7 +131,7 @@ function App() { ...@@ -131,7 +131,7 @@ function App() {
} }
/> />
<Route <Route
path='/user/reset' path="/user/reset"
element={ element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<PasswordResetConfirm /> <PasswordResetConfirm />
...@@ -139,7 +139,7 @@ function App() { ...@@ -139,7 +139,7 @@ function App() {
} }
/> />
<Route <Route
path='/login' path="/login"
element={ element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<LoginForm /> <LoginForm />
...@@ -147,7 +147,7 @@ function App() { ...@@ -147,7 +147,7 @@ function App() {
} }
/> />
<Route <Route
path='/register' path="/register"
element={ element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<RegisterForm /> <RegisterForm />
...@@ -155,7 +155,7 @@ function App() { ...@@ -155,7 +155,7 @@ function App() {
} }
/> />
<Route <Route
path='/reset' path="/reset"
element={ element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<PasswordResetForm /> <PasswordResetForm />
...@@ -163,7 +163,7 @@ function App() { ...@@ -163,7 +163,7 @@ function App() {
} }
/> />
<Route <Route
path='/oauth/github' path="/oauth/github"
element={ element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<GitHubOAuth /> <GitHubOAuth />
...@@ -171,7 +171,7 @@ function App() { ...@@ -171,7 +171,7 @@ function App() {
} }
/> />
<Route <Route
path='/setting' path="/setting"
element={ element={
<PrivateRoute> <PrivateRoute>
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
...@@ -181,7 +181,7 @@ function App() { ...@@ -181,7 +181,7 @@ function App() {
} }
/> />
<Route <Route
path='/topup' path="/topup"
element={ element={
<PrivateRoute> <PrivateRoute>
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
...@@ -191,7 +191,7 @@ function App() { ...@@ -191,7 +191,7 @@ function App() {
} }
/> />
<Route <Route
path='/log' path="/log"
element={ element={
<PrivateRoute> <PrivateRoute>
<Log /> <Log />
...@@ -199,7 +199,7 @@ function App() { ...@@ -199,7 +199,7 @@ function App() {
} }
/> />
<Route <Route
path='/detail' path="/detail"
element={ element={
<PrivateRoute> <PrivateRoute>
<Detail /> <Detail />
...@@ -207,7 +207,7 @@ function App() { ...@@ -207,7 +207,7 @@ function App() {
} }
/> />
<Route <Route
path='/midjourney' path="/midjourney"
element={ element={
<PrivateRoute> <PrivateRoute>
<Midjourney /> <Midjourney />
...@@ -215,7 +215,7 @@ function App() { ...@@ -215,7 +215,7 @@ function App() {
} }
/> />
<Route <Route
path='/about' path="/about"
element={ element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<About /> <About />
...@@ -223,14 +223,14 @@ function App() { ...@@ -223,14 +223,14 @@ function App() {
} }
/> />
<Route <Route
path='/chat' path="/chat"
element={ element={
<Suspense fallback={<Loading></Loading>}> <Suspense fallback={<Loading></Loading>}>
<Chat /> <Chat />
</Suspense> </Suspense>
} }
/> />
<Route path='*' element={ <Route path="*" element={
<NotFound /> <NotFound />
} /> } />
</Routes> </Routes>
......
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { getFooterHTML, getSystemName } from '../helpers'; import { getFooterHTML, getSystemName } from '../helpers';
import {Layout} from "@douyinfe/semi-ui"; import { Layout } from '@douyinfe/semi-ui';
const Footer = () => { const Footer = () => {
const systemName = getSystemName(); const systemName = getSystemName();
...@@ -29,30 +29,30 @@ const Footer = () => { ...@@ -29,30 +29,30 @@ const Footer = () => {
return ( return (
<Layout> <Layout>
<Layout.Content 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>
) : ( ) : (
<div className='custom-footer'> <div className="custom-footer">
<a <a
href='https://github.com/Calcium-Ion/new-api' href="https://github.com/Calcium-Ion/new-api"
target='_blank' target="_blank" rel="noreferrer"
> >
New API {process.env.REACT_APP_VERSION}{' '} New API {process.env.REACT_APP_VERSION}{' '}
</a> </a>
{' '} {' '}
<a href='https://github.com/Calcium-Ion' target='_blank'> <a href="https://github.com/Calcium-Ion" target="_blank" rel="noreferrer">
Calcium-Ion Calcium-Ion
</a>{' '} </a>{' '}
开发,基于{' '} 开发,基于{' '}
<a href='https://github.com/songquanpeng/one-api' target='_blank'> <a href="https://github.com/songquanpeng/one-api" target="_blank" rel="noreferrer">
One API v0.5.4 One API v0.5.4
</a>{' '} </a>{' '}
,本项目根据{' '} ,本项目根据{' '}
<a href='https://opensource.org/licenses/mit-license.php'> <a href="https://opensource.org/licenses/mit-license.php">
MIT 许可证 MIT 许可证
</a>{' '} </a>{' '}
授权 授权
......
...@@ -49,7 +49,7 @@ const GitHubOAuth = () => { ...@@ -49,7 +49,7 @@ const GitHubOAuth = () => {
return ( return (
<Segment style={{ minHeight: '300px' }}> <Segment style={{ minHeight: '300px' }}>
<Dimmer active inverted> <Dimmer active inverted>
<Loader size='large'>{prompt}</Loader> <Loader size="large">{prompt}</Loader>
</Dimmer> </Dimmer>
</Segment> </Segment>
); );
......
import React, {useContext, useEffect, useRef, useState} from 'react'; import React, { useContext, useEffect, useState } from 'react';
import {Link, useNavigate} from 'react-router-dom'; import { Link, useNavigate } from 'react-router-dom';
import {UserContext} from '../context/User'; import { UserContext } from '../context/User';
import {API, getLogo, getSystemName, isAdmin, isMobile, showSuccess} from '../helpers'; import { API, getLogo, getSystemName, showSuccess } from '../helpers';
import '../index.css'; import '../index.css';
import fireworks from 'react-fireworks'; import fireworks from 'react-fireworks';
import { import { IconHelpCircle, IconKey, IconUser } from '@douyinfe/semi-icons';
IconKey, import { Avatar, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
IconUser, import { stringToColor } from '../helpers/render';
IconHelpCircle
} from '@douyinfe/semi-icons';
import {Nav, Avatar, Dropdown, Layout, Switch} from '@douyinfe/semi-ui';
import {stringToColor} from "../helpers/render";
// HeaderBar Buttons // HeaderBar Buttons
let headerButtons = [ let headerButtons = [
...@@ -21,8 +17,8 @@ let headerButtons = [ ...@@ -21,8 +17,8 @@ let headerButtons = [
text: '关于', text: '关于',
itemKey: 'about', itemKey: 'about',
to: '/about', to: '/about',
icon: <IconHelpCircle/> icon: <IconHelpCircle />
}, }
]; ];
if (localStorage.getItem('chat_link')) { if (localStorage.getItem('chat_link')) {
...@@ -50,13 +46,13 @@ const HeaderBar = () => { ...@@ -50,13 +46,13 @@ const HeaderBar = () => {
setShowSidebar(false); setShowSidebar(false);
await API.get('/api/user/logout'); await API.get('/api/user/logout');
showSuccess('注销成功!'); showSuccess('注销成功!');
userDispatch({type: 'logout'}); userDispatch({ type: 'logout' });
localStorage.removeItem('user'); localStorage.removeItem('user');
navigate('/login'); navigate('/login');
} }
const handleNewYearClick = () => { const handleNewYearClick = () => {
fireworks.init("root",{}); fireworks.init('root', {});
fireworks.start(); fireworks.start();
setTimeout(() => { setTimeout(() => {
fireworks.stop(); fireworks.stop();
...@@ -89,19 +85,19 @@ const HeaderBar = () => { ...@@ -89,19 +85,19 @@ const HeaderBar = () => {
return ( return (
<> <>
<Layout> <Layout>
<div style={{width: '100%'}}> <div style={{ width: '100%' }}>
<Nav <Nav
mode={'horizontal'} mode={'horizontal'}
// bodyStyle={{ height: 100 }} // bodyStyle={{ height: 100 }}
renderWrapper={({itemElement, isSubNav, isInSubNav, props}) => { renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
const routerMap = { const routerMap = {
about: "/about", about: '/about',
login: "/login", login: '/login',
register: "/register", register: '/register'
}; };
return ( return (
<Link <Link
style={{textDecoration: "none"}} style={{ textDecoration: 'none' }}
to={routerMap[props.itemKey]} to={routerMap[props.itemKey]}
> >
{itemElement} {itemElement}
...@@ -125,7 +121,7 @@ const HeaderBar = () => { ...@@ -125,7 +121,7 @@ const HeaderBar = () => {
</Dropdown.Menu> </Dropdown.Menu>
} }
> >
<Nav.Item itemKey={'new-year'} text={'🏮'}/> <Nav.Item itemKey={'new-year'} text={'🏮'} />
</Dropdown> </Dropdown>
} }
<Nav.Item itemKey={'about'} icon={<IconHelpCircle />} /> <Nav.Item itemKey={'about'} icon={<IconHelpCircle />} />
......
import React from 'react'; import React from 'react';
import { Segment, Dimmer, Loader } from 'semantic-ui-react'; import { Dimmer, Loader, Segment } from 'semantic-ui-react';
const Loading = ({ prompt: name = 'page' }) => { const Loading = ({ prompt: name = 'page' }) => {
return ( return (
......
import React, { useContext, useEffect, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
import { Link, useNavigate, useSearchParams } from 'react-router-dom'; import { Link, useNavigate, useSearchParams } from 'react-router-dom';
import { UserContext } from '../context/User'; import { UserContext } from '../context/User';
import { API, getLogo, isMobile, showError, showInfo, showSuccess, showWarning } from '../helpers'; import { API, getLogo, showError, showInfo, showSuccess } from '../helpers';
import { onGitHubOAuthClicked } from './utils'; import { onGitHubOAuthClicked } from './utils';
import Turnstile from "react-turnstile"; import Turnstile from 'react-turnstile';
import { Layout, Card, Image, Form, Button, Divider, Modal, Icon } from '@douyinfe/semi-ui'; import { Button, Card, Divider, Form, Icon, Layout, Modal } from '@douyinfe/semi-ui';
import Title from "@douyinfe/semi-ui/lib/es/typography/title"; import Title from '@douyinfe/semi-ui/lib/es/typography/title';
import Text from "@douyinfe/semi-ui/lib/es/typography/text"; import Text from '@douyinfe/semi-ui/lib/es/typography/text';
import TelegramLoginButton from 'react-telegram-login'; import TelegramLoginButton from 'react-telegram-login';
import { IconGithubLogo } from '@douyinfe/semi-icons'; import { IconGithubLogo } from '@douyinfe/semi-icons';
...@@ -104,7 +104,7 @@ const LoginForm = () => { ...@@ -104,7 +104,7 @@ const LoginForm = () => {
// 添加Telegram登录处理函数 // 添加Telegram登录处理函数
const onTelegramLoginClicked = async (response) => { const onTelegramLoginClicked = async (response) => {
const fields = ["id", "first_name", "last_name", "username", "photo_url", "auth_date", "hash", "lang"]; const fields = ['id', 'first_name', 'last_name', 'username', 'photo_url', 'auth_date', 'hash', 'lang'];
const params = {}; const params = {};
fields.forEach((field) => { fields.forEach((field) => {
if (response[field]) { if (response[field]) {
...@@ -129,7 +129,7 @@ const LoginForm = () => { ...@@ -129,7 +129,7 @@ const LoginForm = () => {
<Layout.Header> <Layout.Header>
</Layout.Header> </Layout.Header>
<Layout.Content> <Layout.Content>
<div style={{ justifyContent: 'center', display: "flex", marginTop: 120 }}> <div style={{ justifyContent: 'center', display: 'flex', marginTop: 120 }}>
<div style={{ width: 500 }}> <div style={{ width: 500 }}>
<Card> <Card>
<Title heading={2} style={{ textAlign: 'center' }}> <Title heading={2} style={{ textAlign: 'center' }}>
...@@ -139,41 +139,41 @@ const LoginForm = () => { ...@@ -139,41 +139,41 @@ const LoginForm = () => {
<Form.Input <Form.Input
field={'username'} field={'username'}
label={'用户名'} label={'用户名'}
placeholder='用户名' placeholder="用户名"
name='username' name="username"
onChange={(value) => handleChange('username', value)} onChange={(value) => handleChange('username', value)}
/> />
<Form.Input <Form.Input
field={'password'} field={'password'}
label={'密码'} label={'密码'}
placeholder='密码' placeholder="密码"
name='password' name="password"
type='password' type="password"
onChange={(value) => handleChange('password', value)} onChange={(value) => handleChange('password', value)}
/> />
<Button theme='solid' style={{ width: '100%' }} type={'primary'} size='large' <Button theme="solid" style={{ width: '100%' }} type={'primary'} size="large"
htmlType={'submit'} onClick={handleSubmit}> htmlType={'submit'} onClick={handleSubmit}>
登录 登录
</Button> </Button>
</Form> </Form>
<div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 20 }}> <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 20 }}>
<Text> <Text>
没有账号请先 <Link to='/register'>注册账号</Link> 没有账号请先 <Link to="/register">注册账号</Link>
</Text> </Text>
<Text> <Text>
忘记密码 <Link to='/reset'>点击重置</Link> 忘记密码 <Link to="/reset">点击重置</Link>
</Text> </Text>
</div> </div>
{status.github_oauth || status.wechat_login || status.telegram_oauth ? ( {status.github_oauth || status.wechat_login || status.telegram_oauth ? (
<> <>
<Divider margin='12px' align='center'> <Divider margin="12px" align="center">
第三方登录 第三方登录
</Divider> </Divider>
<div style={{ display: 'flex', justifyContent: 'center', marginTop: 20 }}> <div style={{ display: 'flex', justifyContent: 'center', marginTop: 20 }}>
{status.github_oauth ? ( {status.github_oauth ? (
<Button <Button
type='primary' type="primary"
icon={<IconGithubLogo />} icon={<IconGithubLogo />}
onClick={() => onGitHubOAuthClicked(status.github_client_id)} onClick={() => onGitHubOAuthClicked(status.github_client_id)}
/> />
...@@ -182,8 +182,8 @@ const LoginForm = () => { ...@@ -182,8 +182,8 @@ const LoginForm = () => {
)} )}
{status.wechat_login ? ( {status.wechat_login ? (
<Button <Button
type='primary' type="primary"
style={{color: 'rgba(var(--semi-green-5), 1)'}} style={{ color: 'rgba(var(--semi-green-5), 1)' }}
icon={<Icon svg={<WeChatIcon />} />} icon={<Icon svg={<WeChatIcon />} />}
onClick={onWeChatLoginClicked} onClick={onWeChatLoginClicked}
/> />
...@@ -212,17 +212,17 @@ const LoginForm = () => { ...@@ -212,17 +212,17 @@ const LoginForm = () => {
centered={true} centered={true}
> >
<div style={{ display: 'flex', alignItem: 'center', flexDirection: 'column' }}> <div style={{ display: 'flex', alignItem: 'center', flexDirection: 'column' }}>
<img src={status.wechat_qrcode}/> <img src={status.wechat_qrcode} />
</div> </div>
<div style={{textAlign: 'center'}}> <div style={{ textAlign: 'center' }}>
<p> <p>
微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效) 微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效)
</p> </p>
</div> </div>
<Form size='large'> <Form size="large">
<Form.Input <Form.Input
field={'wechat_verification_code'} field={'wechat_verification_code'}
placeholder='验证码' placeholder="验证码"
label={'验证码'} label={'验证码'}
value={inputs.wechat_verification_code} value={inputs.wechat_verification_code}
onChange={(value) => handleChange('wechat_verification_code', value)} onChange={(value) => handleChange('wechat_verification_code', value)}
......
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { Col, Row , Form, Button, Banner } from '@douyinfe/semi-ui'; import { Banner, Button, Col, Form, Row } from '@douyinfe/semi-ui';
import { API, showError, showSuccess } from '../helpers'; import { API, showError, showSuccess } from '../helpers';
import { marked } from 'marked'; import { marked } from 'marked';
...@@ -57,8 +57,8 @@ const OtherSetting = () => { ...@@ -57,8 +57,8 @@ const OtherSetting = () => {
await updateOption('Notice', inputs.Notice); await updateOption('Notice', inputs.Notice);
showSuccess('公告已更新'); showSuccess('公告已更新');
} catch (error) { } catch (error) {
console.error("公告更新失败", error); console.error('公告更新失败', error);
showError("公告更新失败") showError('公告更新失败');
} finally { } finally {
setLoadingInput((loadingInput) => ({ ...loadingInput, Notice: false })); setLoadingInput((loadingInput) => ({ ...loadingInput, Notice: false }));
} }
...@@ -72,8 +72,8 @@ const OtherSetting = () => { ...@@ -72,8 +72,8 @@ const OtherSetting = () => {
await updateOption('SystemName', inputs.SystemName); await updateOption('SystemName', inputs.SystemName);
showSuccess('系统名称已更新'); showSuccess('系统名称已更新');
} catch (error) { } catch (error) {
console.error("系统名称更新失败", error); console.error('系统名称更新失败', error);
showError("系统名称更新失败") showError('系统名称更新失败');
} finally { } finally {
setLoadingInput((loadingInput) => ({ ...loadingInput, SystemName: false })); setLoadingInput((loadingInput) => ({ ...loadingInput, SystemName: false }));
} }
...@@ -86,8 +86,8 @@ const OtherSetting = () => { ...@@ -86,8 +86,8 @@ const OtherSetting = () => {
await updateOption('Logo', inputs.Logo); await updateOption('Logo', inputs.Logo);
showSuccess('Logo 已更新'); showSuccess('Logo 已更新');
} catch (error) { } catch (error) {
console.error("Logo 更新失败", error); console.error('Logo 更新失败', error);
showError("Logo 更新失败") showError('Logo 更新失败');
} finally { } finally {
setLoadingInput((loadingInput) => ({ ...loadingInput, Logo: false })); setLoadingInput((loadingInput) => ({ ...loadingInput, Logo: false }));
} }
...@@ -99,8 +99,8 @@ const OtherSetting = () => { ...@@ -99,8 +99,8 @@ const OtherSetting = () => {
await updateOption(key, inputs[key]); await updateOption(key, inputs[key]);
showSuccess('首页内容已更新'); showSuccess('首页内容已更新');
} catch (error) { } catch (error) {
console.error("首页内容更新失败", error); console.error('首页内容更新失败', error);
showError("首页内容更新失败") showError('首页内容更新失败');
} finally { } finally {
setLoadingInput((loadingInput) => ({ ...loadingInput, HomePageContent: false })); setLoadingInput((loadingInput) => ({ ...loadingInput, HomePageContent: false }));
} }
...@@ -112,8 +112,8 @@ const OtherSetting = () => { ...@@ -112,8 +112,8 @@ const OtherSetting = () => {
await updateOption('About', inputs.About); await updateOption('About', inputs.About);
showSuccess('关于内容已更新'); showSuccess('关于内容已更新');
} catch (error) { } catch (error) {
console.error("关于内容更新失败", error); console.error('关于内容更新失败', error);
showError("关于内容更新失败"); showError('关于内容更新失败');
} finally { } finally {
setLoadingInput((loadingInput) => ({ ...loadingInput, About: false })); setLoadingInput((loadingInput) => ({ ...loadingInput, About: false }));
} }
...@@ -125,16 +125,14 @@ const OtherSetting = () => { ...@@ -125,16 +125,14 @@ const OtherSetting = () => {
await updateOption('Footer', inputs.Footer); await updateOption('Footer', inputs.Footer);
showSuccess('页脚内容已更新'); showSuccess('页脚内容已更新');
} catch (error) { } catch (error) {
console.error("页脚内容更新失败", error); console.error('页脚内容更新失败', error);
showError("页脚内容更新失败"); showError('页脚内容更新失败');
} finally { } finally {
setLoadingInput((loadingInput) => ({ ...loadingInput, Footer: false })); setLoadingInput((loadingInput) => ({ ...loadingInput, Footer: false }));
} }
}; };
const openGitHubRelease = () => { const openGitHubRelease = () => {
window.location = window.location =
'https://github.com/songquanpeng/one-api/releases/latest'; 'https://github.com/songquanpeng/one-api/releases/latest';
...@@ -173,16 +171,17 @@ const OtherSetting = () => { ...@@ -173,16 +171,17 @@ const OtherSetting = () => {
} }
}; };
useEffect( () => { useEffect(() => {
getOptions(); getOptions();
}, []); }, []);
return ( return (
<Row > <Row>
<Col span={24}> <Col span={24}>
{/* 通用设置 */} {/* 通用设置 */}
<Form values={inputs} getFormApi={formAPI => formAPISettingGeneral.current = formAPI} style={{marginBottom: 15}}> <Form values={inputs} getFormApi={formAPI => formAPISettingGeneral.current = formAPI}
style={{ marginBottom: 15 }}>
<Form.Section text={'通用设置'}> <Form.Section text={'通用设置'}>
<Form.TextArea <Form.TextArea
label={'公告'} label={'公告'}
...@@ -196,7 +195,8 @@ const OtherSetting = () => { ...@@ -196,7 +195,8 @@ const OtherSetting = () => {
</Form.Section> </Form.Section>
</Form> </Form>
{/* 个性化设置 */} {/* 个性化设置 */}
<Form values={inputs} getFormApi={formAPI => formAPIPersonalization.current = formAPI} style={{marginBottom: 15}}> <Form values={inputs} getFormApi={formAPI => formAPIPersonalization.current = formAPI}
style={{ marginBottom: 15 }}>
<Form.Section text={'个性化设置'}> <Form.Section text={'个性化设置'}>
<Form.Input <Form.Input
label={'系统名称'} label={'系统名称'}
...@@ -220,7 +220,8 @@ const OtherSetting = () => { ...@@ -220,7 +220,8 @@ const OtherSetting = () => {
style={{ fontFamily: 'JetBrains Mono, Consolas' }} style={{ fontFamily: 'JetBrains Mono, Consolas' }}
autosize={{ minRows: 6, maxRows: 12 }} autosize={{ minRows: 6, maxRows: 12 }}
/> />
<Button onClick={() => submitOption('HomePageContent')} loading={loadingInput['HomePageContent']}>设置首页内容</Button> <Button onClick={() => submitOption('HomePageContent')}
loading={loadingInput['HomePageContent']}>设置首页内容</Button>
<Form.TextArea <Form.TextArea
label={'关于'} label={'关于'}
placeholder={'在此输入新的关于内容,支持 Markdown & HTML 代码。如果输入的是一个链接,则会使用该链接作为 iframe 的 src 属性,这允许你设置任意网页作为关于页面。'} placeholder={'在此输入新的关于内容,支持 Markdown & HTML 代码。如果输入的是一个链接,则会使用该链接作为 iframe 的 src 属性,这允许你设置任意网页作为关于页面。'}
......
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Button, Form, Grid, Header, Image, Segment } from 'semantic-ui-react'; import { Button, Form, Grid, Header, Image, Segment } from 'semantic-ui-react';
import { API, copy, showError, showInfo, showNotice, showSuccess } from '../helpers'; import { API, copy, showError, showNotice } from '../helpers';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
const PasswordResetConfirm = () => { const PasswordResetConfirm = () => {
const [inputs, setInputs] = useState({ const [inputs, setInputs] = useState({
email: '', email: '',
token: '', token: ''
}); });
const { email, token } = inputs; const { email, token } = inputs;
...@@ -23,7 +23,7 @@ const PasswordResetConfirm = () => { ...@@ -23,7 +23,7 @@ const PasswordResetConfirm = () => {
let email = searchParams.get('email'); let email = searchParams.get('email');
setInputs({ setInputs({
token, token,
email, email
}); });
}, []); }, []);
...@@ -46,7 +46,7 @@ const PasswordResetConfirm = () => { ...@@ -46,7 +46,7 @@ const PasswordResetConfirm = () => {
setLoading(true); setLoading(true);
const res = await API.post(`/api/user/reset`, { const res = await API.post(`/api/user/reset`, {
email, email,
token, token
}); });
const { success, message } = res.data; const { success, message } = res.data;
if (success) { if (success) {
...@@ -61,29 +61,29 @@ const PasswordResetConfirm = () => { ...@@ -61,29 +61,29 @@ const PasswordResetConfirm = () => {
} }
return ( return (
<Grid textAlign='center' style={{ marginTop: '48px' }}> <Grid textAlign="center" style={{ marginTop: '48px' }}>
<Grid.Column style={{ maxWidth: 450 }}> <Grid.Column style={{ maxWidth: 450 }}>
<Header as='h2' color='' textAlign='center'> <Header as="h2" color="" textAlign="center">
<Image src='/logo.png' /> 密码重置确认 <Image src="/logo.png" /> 密码重置确认
</Header> </Header>
<Form size='large'> <Form size="large">
<Segment> <Segment>
<Form.Input <Form.Input
fluid fluid
icon='mail' icon="mail"
iconPosition='left' iconPosition="left"
placeholder='邮箱地址' placeholder="邮箱地址"
name='email' name="email"
value={email} value={email}
readOnly readOnly
/> />
{newPassword && ( {newPassword && (
<Form.Input <Form.Input
fluid fluid
icon='lock' icon="lock"
iconPosition='left' iconPosition="left"
placeholder='新密码' placeholder="新密码"
name='newPassword' name="newPassword"
value={newPassword} value={newPassword}
readOnly readOnly
onClick={(e) => { onClick={(e) => {
...@@ -94,9 +94,9 @@ const PasswordResetConfirm = () => { ...@@ -94,9 +94,9 @@ const PasswordResetConfirm = () => {
/> />
)} )}
<Button <Button
color='green' color="green"
fluid fluid
size='large' size="large"
onClick={handleSubmit} onClick={handleSubmit}
loading={loading} loading={loading}
disabled={disableButton} disabled={disableButton}
......
...@@ -56,19 +56,19 @@ const PasswordResetForm = () => { ...@@ -56,19 +56,19 @@ const PasswordResetForm = () => {
} }
return ( return (
<Grid textAlign='center' style={{ marginTop: '48px' }}> <Grid textAlign="center" style={{ marginTop: '48px' }}>
<Grid.Column style={{ maxWidth: 450 }}> <Grid.Column style={{ maxWidth: 450 }}>
<Header as='h2' color='' textAlign='center'> <Header as="h2" color="" textAlign="center">
<Image src='/logo.png' /> 密码重置 <Image src="/logo.png" /> 密码重置
</Header> </Header>
<Form size='large'> <Form size="large">
<Segment> <Segment>
<Form.Input <Form.Input
fluid fluid
icon='mail' icon="mail"
iconPosition='left' iconPosition="left"
placeholder='邮箱地址' placeholder="邮箱地址"
name='email' name="email"
value={email} value={email}
onChange={handleChange} onChange={handleChange}
/> />
...@@ -83,9 +83,9 @@ const PasswordResetForm = () => { ...@@ -83,9 +83,9 @@ const PasswordResetForm = () => {
<></> <></>
)} )}
<Button <Button
color='green' color="green"
fluid fluid
size='large' size="large"
onClick={handleSubmit} onClick={handleSubmit}
loading={loading} loading={loading}
disabled={disableButton} disabled={disableButton}
......
...@@ -5,7 +5,7 @@ import { history } from '../helpers'; ...@@ -5,7 +5,7 @@ import { history } from '../helpers';
function PrivateRoute({ children }) { function PrivateRoute({ children }) {
if (!localStorage.getItem('user')) { if (!localStorage.getItem('user')) {
return <Navigate to='/login' state={{ from: history.location }} />; return <Navigate to="/login" state={{ from: history.location }} />;
} }
return children; return children;
} }
......
...@@ -98,49 +98,49 @@ const RegisterForm = () => { ...@@ -98,49 +98,49 @@ const RegisterForm = () => {
}; };
return ( return (
<Grid textAlign='center' style={{ marginTop: '48px' }}> <Grid textAlign="center" style={{ marginTop: '48px' }}>
<Grid.Column style={{ maxWidth: 450 }}> <Grid.Column style={{ maxWidth: 450 }}>
<Header as='h2' color='' textAlign='center'> <Header as="h2" color="" textAlign="center">
<Image src={logo} /> 新用户注 <Image src={logo} /> 新用户注
</Header> </Header>
<Form size='large'> <Form size="large">
<Segment> <Segment>
<Form.Input <Form.Input
fluid fluid
icon='user' icon="user"
iconPosition='left' iconPosition="left"
placeholder='输入用户名,最长 12 位' placeholder="输入用户名,最长 12 位"
onChange={handleChange} onChange={handleChange}
name='username' name="username"
/> />
<Form.Input <Form.Input
fluid fluid
icon='lock' icon="lock"
iconPosition='left' iconPosition="left"
placeholder='输入密码,最短 8 位,最长 20 位' placeholder="输入密码,最短 8 位,最长 20 位"
onChange={handleChange} onChange={handleChange}
name='password' name="password"
type='password' type="password"
/> />
<Form.Input <Form.Input
fluid fluid
icon='lock' icon="lock"
iconPosition='left' iconPosition="left"
placeholder='输入密码,最短 8 位,最长 20 位' placeholder="输入密码,最短 8 位,最长 20 位"
onChange={handleChange} onChange={handleChange}
name='password2' name="password2"
type='password' type="password"
/> />
{showEmailVerification ? ( {showEmailVerification ? (
<> <>
<Form.Input <Form.Input
fluid fluid
icon='mail' icon="mail"
iconPosition='left' iconPosition="left"
placeholder='输入邮箱地址' placeholder="输入邮箱地址"
onChange={handleChange} onChange={handleChange}
name='email' name="email"
type='email' type="email"
action={ action={
<Button onClick={sendVerificationCode} disabled={loading}> <Button onClick={sendVerificationCode} disabled={loading}>
获取验证码 获取验证码
...@@ -149,11 +149,11 @@ const RegisterForm = () => { ...@@ -149,11 +149,11 @@ const RegisterForm = () => {
/> />
<Form.Input <Form.Input
fluid fluid
icon='lock' icon="lock"
iconPosition='left' iconPosition="left"
placeholder='输入验证码' placeholder="输入验证码"
onChange={handleChange} onChange={handleChange}
name='verification_code' name="verification_code"
/> />
</> </>
) : ( ) : (
...@@ -170,9 +170,9 @@ const RegisterForm = () => { ...@@ -170,9 +170,9 @@ const RegisterForm = () => {
<></> <></>
)} )}
<Button <Button
color='green' color="green"
fluid fluid
size='large' size="large"
onClick={handleSubmit} onClick={handleSubmit}
loading={loading} loading={loading}
> >
...@@ -182,7 +182,7 @@ const RegisterForm = () => { ...@@ -182,7 +182,7 @@ const RegisterForm = () => {
</Form> </Form>
<Message> <Message>
已有账户? 已有账户?
<Link to='/login' className='btn btn-link'> <Link to="/login" className="btn btn-link">
点击登录 点击登录
</Link> </Link>
</Message> </Message>
......
import React, { useContext, useEffect, useLayoutEffect, useMemo, useState } from 'react'; import React, { useContext, useEffect, useMemo, useState } from 'react';
import {Link, useNavigate} from 'react-router-dom'; import { Link, useNavigate } from 'react-router-dom';
import {UserContext} from '../context/User'; import { UserContext } from '../context/User';
import { StatusContext } from '../context/Status'; import { StatusContext } from '../context/Status';
import { API, getLogo, getSystemName, isAdmin, isMobile, showError, showSuccess } from '../helpers'; import { API, getLogo, getSystemName, isAdmin, isMobile, showError } from '../helpers';
import '../index.css'; import '../index.css';
import { import {
IconCalendarClock, IconCalendarClock,
IconHistogram, IconComment,
IconCreditCard,
IconGift, IconGift,
IconHistogram,
IconHome,
IconImage,
IconKey, IconKey,
IconUser,
IconLayers, IconLayers,
IconSetting, IconSetting,
IconCreditCard, IconUser
IconComment,
IconHome,
IconImage
} from '@douyinfe/semi-icons'; } from '@douyinfe/semi-icons';
import {Nav, Avatar, Dropdown, Layout} from '@douyinfe/semi-ui'; import { Layout, Nav } from '@douyinfe/semi-ui';
// HeaderBar Buttons // HeaderBar Buttons
...@@ -39,74 +39,74 @@ const SiderBar = () => { ...@@ -39,74 +39,74 @@ const SiderBar = () => {
text: '首页', text: '首页',
itemKey: 'home', itemKey: 'home',
to: '/', to: '/',
icon: <IconHome/> icon: <IconHome />
}, },
{ {
text: '渠道', text: '渠道',
itemKey: 'channel', itemKey: 'channel',
to: '/channel', to: '/channel',
icon: <IconLayers/>, icon: <IconLayers />,
className: isAdmin()?'semi-navigation-item-normal':'tableHiddle', className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle'
}, },
{ {
text: '聊天', text: '聊天',
itemKey: 'chat', itemKey: 'chat',
to: '/chat', to: '/chat',
icon: <IconComment />, icon: <IconComment />,
className: localStorage.getItem('chat_link')?'semi-navigation-item-normal':'tableHiddle', className: localStorage.getItem('chat_link') ? 'semi-navigation-item-normal' : 'tableHiddle'
}, },
{ {
text: '令牌', text: '令牌',
itemKey: 'token', itemKey: 'token',
to: '/token', to: '/token',
icon: <IconKey/> icon: <IconKey />
}, },
{ {
text: '兑换码', text: '兑换码',
itemKey: 'redemption', itemKey: 'redemption',
to: '/redemption', to: '/redemption',
icon: <IconGift/>, icon: <IconGift />,
className: isAdmin()?'semi-navigation-item-normal':'tableHiddle', className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle'
}, },
{ {
text: '钱包', text: '钱包',
itemKey: 'topup', itemKey: 'topup',
to: '/topup', to: '/topup',
icon: <IconCreditCard/> icon: <IconCreditCard />
}, },
{ {
text: '用户管理', text: '用户管理',
itemKey: 'user', itemKey: 'user',
to: '/user', to: '/user',
icon: <IconUser/>, icon: <IconUser />,
className: isAdmin()?'semi-navigation-item-normal':'tableHiddle', className: isAdmin() ? 'semi-navigation-item-normal' : 'tableHiddle'
}, },
{ {
text: '日志', text: '日志',
itemKey: 'log', itemKey: 'log',
to: '/log', to: '/log',
icon: <IconHistogram/> icon: <IconHistogram />
}, },
{ {
text: '数据看板', text: '数据看板',
itemKey: 'detail', itemKey: 'detail',
to: '/detail', to: '/detail',
icon: <IconCalendarClock />, icon: <IconCalendarClock />,
className: localStorage.getItem('enable_data_export') === 'true'?'semi-navigation-item-normal':'tableHiddle', className: localStorage.getItem('enable_data_export') === 'true' ? 'semi-navigation-item-normal' : 'tableHiddle'
}, },
{ {
text: '绘图', text: '绘图',
itemKey: 'midjourney', itemKey: 'midjourney',
to: '/midjourney', to: '/midjourney',
icon: <IconImage/>, icon: <IconImage />,
className: localStorage.getItem('enable_drawing') === 'true'?'semi-navigation-item-normal':'tableHiddle', className: localStorage.getItem('enable_drawing') === 'true' ? 'semi-navigation-item-normal' : 'tableHiddle'
}, },
{ {
text: '设置', text: '设置',
itemKey: 'setting', itemKey: 'setting',
to: '/setting', to: '/setting',
icon: <IconSetting/> icon: <IconSetting />
}, }
// { // {
// text: '关于', // text: '关于',
// itemKey: 'about', // itemKey: 'about',
...@@ -149,12 +149,12 @@ const SiderBar = () => { ...@@ -149,12 +149,12 @@ const SiderBar = () => {
loadStatus().then(() => { loadStatus().then(() => {
setIsCollapsed(isMobile() || localStorage.getItem('default_collapse_sidebar') === 'true'); setIsCollapsed(isMobile() || localStorage.getItem('default_collapse_sidebar') === 'true');
}); });
},[]) }, []);
return ( return (
<> <>
<Layout> <Layout>
<div style={{height: '100%'}}> <div style={{ height: '100%' }}>
<Nav <Nav
// bodyStyle={{ maxWidth: 200 }} // bodyStyle={{ maxWidth: 200 }}
style={{ maxWidth: 200 }} style={{ maxWidth: 200 }}
...@@ -164,24 +164,24 @@ const SiderBar = () => { ...@@ -164,24 +164,24 @@ const SiderBar = () => {
setIsCollapsed(collapsed); setIsCollapsed(collapsed);
}} }}
selectedKeys={selectedKeys} selectedKeys={selectedKeys}
renderWrapper={({itemElement, isSubNav, isInSubNav, props}) => { renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
const routerMap = { const routerMap = {
home: "/", home: '/',
channel: "/channel", channel: '/channel',
token: "/token", token: '/token',
redemption: "/redemption", redemption: '/redemption',
topup: "/topup", topup: '/topup',
user: "/user", user: '/user',
log: "/log", log: '/log',
midjourney: "/midjourney", midjourney: '/midjourney',
setting: "/setting", setting: '/setting',
about: "/about", about: '/about',
chat: "/chat", chat: '/chat',
detail: "/detail", detail: '/detail'
}; };
return ( return (
<Link <Link
style={{textDecoration: "none"}} style={{ textDecoration: 'none' }}
to={routerMap[props.itemKey]} to={routerMap[props.itemKey]}
> >
{itemElement} {itemElement}
...@@ -193,8 +193,8 @@ const SiderBar = () => { ...@@ -193,8 +193,8 @@ const SiderBar = () => {
setSelectedKeys([key.itemKey]); setSelectedKeys([key.itemKey]);
}} }}
header={{ header={{
logo: <img src={logo} alt='logo' style={{marginRight: '0.75em'}}/>, logo: <img src={logo} alt="logo" style={{ marginRight: '0.75em' }} />,
text: systemName, text: systemName
}} }}
// footer={{ // footer={{
// text: '© 2021 NekoAPI', // text: '© 2021 NekoAPI',
......
...@@ -3,14 +3,14 @@ import { Icon } from '@douyinfe/semi-ui'; ...@@ -3,14 +3,14 @@ import { Icon } from '@douyinfe/semi-ui';
const WeChatIcon = () => { const WeChatIcon = () => {
function CustomIcon() { function CustomIcon() {
return <svg t='1709714447384' className='icon' viewBox='0 0 1024 1024' version='1.1' return <svg t="1709714447384" className="icon" viewBox="0 0 1024 1024" version="1.1"
xmlns='http://www.w3.org/2000/svg' p-id='5091' width='16' height='16'> xmlns="http://www.w3.org/2000/svg" p-id="5091" width="16" height="16">
<path <path
d='M690.1 377.4c5.9 0 11.8 0.2 17.6 0.5-24.4-128.7-158.3-227.1-319.9-227.1C209 150.8 64 271.4 64 420.2c0 81.1 43.6 154.2 111.9 203.6 5.5 3.9 9.1 10.3 9.1 17.6 0 2.4-0.5 4.6-1.1 6.9-5.5 20.3-14.2 52.8-14.6 54.3-0.7 2.6-1.7 5.2-1.7 7.9 0 5.9 4.8 10.8 10.8 10.8 2.3 0 4.2-0.9 6.2-2l70.9-40.9c5.3-3.1 11-5 17.2-5 3.2 0 6.4 0.5 9.5 1.4 33.1 9.5 68.8 14.8 105.7 14.8 6 0 11.9-0.1 17.8-0.4-7.1-21-10.9-43.1-10.9-66 0-135.8 132.2-245.8 295.3-245.8z m-194.3-86.5c23.8 0 43.2 19.3 43.2 43.1s-19.3 43.1-43.2 43.1c-23.8 0-43.2-19.3-43.2-43.1s19.4-43.1 43.2-43.1z m-215.9 86.2c-23.8 0-43.2-19.3-43.2-43.1s19.3-43.1 43.2-43.1 43.2 19.3 43.2 43.1-19.4 43.1-43.2 43.1z' d="M690.1 377.4c5.9 0 11.8 0.2 17.6 0.5-24.4-128.7-158.3-227.1-319.9-227.1C209 150.8 64 271.4 64 420.2c0 81.1 43.6 154.2 111.9 203.6 5.5 3.9 9.1 10.3 9.1 17.6 0 2.4-0.5 4.6-1.1 6.9-5.5 20.3-14.2 52.8-14.6 54.3-0.7 2.6-1.7 5.2-1.7 7.9 0 5.9 4.8 10.8 10.8 10.8 2.3 0 4.2-0.9 6.2-2l70.9-40.9c5.3-3.1 11-5 17.2-5 3.2 0 6.4 0.5 9.5 1.4 33.1 9.5 68.8 14.8 105.7 14.8 6 0 11.9-0.1 17.8-0.4-7.1-21-10.9-43.1-10.9-66 0-135.8 132.2-245.8 295.3-245.8z m-194.3-86.5c23.8 0 43.2 19.3 43.2 43.1s-19.3 43.1-43.2 43.1c-23.8 0-43.2-19.3-43.2-43.1s19.4-43.1 43.2-43.1z m-215.9 86.2c-23.8 0-43.2-19.3-43.2-43.1s19.3-43.1 43.2-43.1 43.2 19.3 43.2 43.1-19.4 43.1-43.2 43.1z"
p-id='5092'></path> p-id="5092"></path>
<path <path
d='M866.7 792.7c56.9-41.2 93.2-102 93.2-169.7 0-124-120.8-224.5-269.9-224.5-149 0-269.9 100.5-269.9 224.5S540.9 847.5 690 847.5c30.8 0 60.6-4.4 88.1-12.3 2.6-0.8 5.2-1.2 7.9-1.2 5.2 0 9.9 1.6 14.3 4.1l59.1 34c1.7 1 3.3 1.7 5.2 1.7 2.4 0 4.7-0.9 6.4-2.6 1.7-1.7 2.6-4 2.6-6.4 0-2.2-0.9-4.4-1.4-6.6-0.3-1.2-7.6-28.3-12.2-45.3-0.5-1.9-0.9-3.8-0.9-5.7 0.1-5.9 3.1-11.2 7.6-14.5zM600.2 587.2c-19.9 0-36-16.1-36-35.9 0-19.8 16.1-35.9 36-35.9s36 16.1 36 35.9c0 19.8-16.2 35.9-36 35.9z m179.9 0c-19.9 0-36-16.1-36-35.9 0-19.8 16.1-35.9 36-35.9s36 16.1 36 35.9c-0.1 19.8-16.2 35.9-36 35.9z' d="M866.7 792.7c56.9-41.2 93.2-102 93.2-169.7 0-124-120.8-224.5-269.9-224.5-149 0-269.9 100.5-269.9 224.5S540.9 847.5 690 847.5c30.8 0 60.6-4.4 88.1-12.3 2.6-0.8 5.2-1.2 7.9-1.2 5.2 0 9.9 1.6 14.3 4.1l59.1 34c1.7 1 3.3 1.7 5.2 1.7 2.4 0 4.7-0.9 6.4-2.6 1.7-1.7 2.6-4 2.6-6.4 0-2.2-0.9-4.4-1.4-6.6-0.3-1.2-7.6-28.3-12.2-45.3-0.5-1.9-0.9-3.8-0.9-5.7 0.1-5.9 3.1-11.2 7.6-14.5zM600.2 587.2c-19.9 0-36-16.1-36-35.9 0-19.8 16.1-35.9 36-35.9s36 16.1 36 35.9c0 19.8-16.2 35.9-36 35.9z m179.9 0c-19.9 0-36-16.1-36-35.9 0-19.8 16.1-35.9 36-35.9s36 16.1 36 35.9c-0.1 19.8-16.2 35.9-36 35.9z"
p-id='5093'></path> p-id="5093"></path>
</svg>; </svg>;
} }
......
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useParams, useNavigate } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import {API, downloadTextAsFile, isMobile, showError, showSuccess} from '../../helpers'; import { API, downloadTextAsFile, isMobile, showError, showSuccess } from '../../helpers';
import { renderQuota, renderQuotaWithPrompt } from '../../helpers/render'; import { renderQuotaWithPrompt } from '../../helpers/render';
import {SideSheet, Space, Spin, Button, Input, Typography, AutoComplete, Modal} from "@douyinfe/semi-ui"; import { AutoComplete, Button, Input, Modal, SideSheet, Space, Spin, Typography } from '@douyinfe/semi-ui';
import Title from "@douyinfe/semi-ui/lib/es/typography/title"; import Title from '@douyinfe/semi-ui/lib/es/typography/title';
import {Divider} from "semantic-ui-react"; import { Divider } from 'semantic-ui-react';
const EditRedemption = (props) => { const EditRedemption = (props) => {
const isEdit = props.editingRedemption.id !== undefined; const isEdit = props.editingRedemption.id !== undefined;
const [loading, setLoading] = useState(isEdit); const [loading, setLoading] = useState(isEdit);
const params = useParams(); const params = useParams();
const navigate = useNavigate() const navigate = useNavigate();
const originInputs = { const originInputs = {
name: '', name: '',
quota: 100000, quota: 100000,
...@@ -22,7 +22,7 @@ const EditRedemption = (props) => { ...@@ -22,7 +22,7 @@ const EditRedemption = (props) => {
const handleCancel = () => { const handleCancel = () => {
props.handleClose(); props.handleClose();
} };
const handleInputChange = (name, value) => { const handleInputChange = (name, value) => {
setInputs((inputs) => ({ ...inputs, [name]: value })); setInputs((inputs) => ({ ...inputs, [name]: value }));
...@@ -82,9 +82,9 @@ const EditRedemption = (props) => { ...@@ -82,9 +82,9 @@ const EditRedemption = (props) => {
showError(message); showError(message);
} }
if (!isEdit && data) { if (!isEdit && data) {
let text = ""; let text = '';
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
text += data[i] + "\n"; text += data[i] + '\n';
} }
// downloadTextAsFile(text, `${inputs.name}.txt`); // downloadTextAsFile(text, `${inputs.name}.txt`);
Modal.confirm({ Modal.confirm({
...@@ -108,14 +108,14 @@ const EditRedemption = (props) => { ...@@ -108,14 +108,14 @@ const EditRedemption = (props) => {
<SideSheet <SideSheet
placement={isEdit ? 'right' : 'left'} placement={isEdit ? 'right' : 'left'}
title={<Title level={3}>{isEdit ? '更新兑换码信息' : '创建新的兑换码'}</Title>} title={<Title level={3}>{isEdit ? '更新兑换码信息' : '创建新的兑换码'}</Title>}
headerStyle={{borderBottom: '1px solid var(--semi-color-border)'}} headerStyle={{ borderBottom: '1px solid var(--semi-color-border)' }}
bodyStyle={{borderBottom: '1px solid var(--semi-color-border)'}} bodyStyle={{ borderBottom: '1px solid var(--semi-color-border)' }}
visible={props.visiable} visible={props.visiable}
footer={ footer={
<div style={{display: 'flex', justifyContent: 'flex-end'}}> <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Space> <Space>
<Button theme='solid' size={'large'} onClick={submit}>提交</Button> <Button theme="solid" size={'large'} onClick={submit}>提交</Button>
<Button theme='solid' size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button> <Button theme="solid" size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button>
</Space> </Space>
</div> </div>
} }
...@@ -126,49 +126,49 @@ const EditRedemption = (props) => { ...@@ -126,49 +126,49 @@ const EditRedemption = (props) => {
<Spin spinning={loading}> <Spin spinning={loading}>
<Input <Input
style={{ marginTop: 20 }} style={{ marginTop: 20 }}
label='名称' label="名称"
name='name' name="name"
placeholder={'请输入名称'} placeholder={'请输入名称'}
onChange={value => handleInputChange('name', value)} onChange={value => handleInputChange('name', value)}
value={name} value={name}
autoComplete='new-password' autoComplete="new-password"
required={!isEdit} required={!isEdit}
/> />
<Divider/> <Divider />
<div style={{ marginTop: 20 }}> <div style={{ marginTop: 20 }}>
<Typography.Text>{`额度${renderQuotaWithPrompt(quota)}`}</Typography.Text> <Typography.Text>{`额度${renderQuotaWithPrompt(quota)}`}</Typography.Text>
</div> </div>
<AutoComplete <AutoComplete
style={{ marginTop: 8 }} style={{ marginTop: 8 }}
name='quota' name="quota"
placeholder={'请输入额度'} placeholder={'请输入额度'}
onChange={(value) => handleInputChange('quota', value)} onChange={(value) => handleInputChange('quota', value)}
value={quota} value={quota}
autoComplete='new-password' autoComplete="new-password"
type='number' type="number"
position={'bottom'} position={'bottom'}
data={[ data={[
{value: 500000, label: '1$'}, { value: 500000, label: '1$' },
{value: 5000000, label: '10$'}, { value: 5000000, label: '10$' },
{value: 25000000, label: '50$'}, { value: 25000000, label: '50$' },
{value: 50000000, label: '100$'}, { value: 50000000, label: '100$' },
{value: 250000000, label: '500$'}, { value: 250000000, label: '500$' },
{value: 500000000, label: '1000$'}, { value: 500000000, label: '1000$' }
]} ]}
/> />
{ {
!isEdit && <> !isEdit && <>
<Divider/> <Divider />
<Typography.Text>生成数量</Typography.Text> <Typography.Text>生成数量</Typography.Text>
<Input <Input
style={{ marginTop: 8 }} style={{ marginTop: 8 }}
label='生成数量' label="生成数量"
name='count' name="count"
placeholder={'请输入生成数量'} placeholder={'请输入生成数量'}
onChange={value => handleInputChange('count', value)} onChange={value => handleInputChange('count', value)}
value={count} value={count}
autoComplete='new-password' autoComplete="new-password"
type='number' type="number"
/> />
</> </>
} }
......
import React, {useState} from 'react'; import React, { useState } from 'react';
import {API, isMobile, showError, showSuccess} from '../../helpers'; import { API, isMobile, showError, showSuccess } from '../../helpers';
import Title from "@douyinfe/semi-ui/lib/es/typography/title"; import Title from '@douyinfe/semi-ui/lib/es/typography/title';
import {Button, SideSheet, Space, Input, Spin} from "@douyinfe/semi-ui"; import { Button, Input, SideSheet, Space, Spin } from '@douyinfe/semi-ui';
const AddUser = (props) => { const AddUser = (props) => {
const originInputs = { const originInputs = {
username: '', username: '',
display_name: '', display_name: '',
password: '', password: ''
}; };
const [inputs, setInputs] = useState(originInputs); const [inputs, setInputs] = useState(originInputs);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const {username, display_name, password} = inputs; const { username, display_name, password } = inputs;
const handleInputChange = (name, value) => { const handleInputChange = (name, value) => {
setInputs((inputs) => ({...inputs, [name]: value})); setInputs((inputs) => ({ ...inputs, [name]: value }));
}; };
const submit = async () => { const submit = async () => {
setLoading(true); setLoading(true);
if (inputs.username === '' || inputs.password === '') return; if (inputs.username === '' || inputs.password === '') return;
const res = await API.post(`/api/user/`, inputs); const res = await API.post(`/api/user/`, inputs);
const {success, message} = res.data; const { success, message } = res.data;
if (success) { if (success) {
showSuccess('用户账户创建成功!'); showSuccess('用户账户创建成功!');
setInputs(originInputs); setInputs(originInputs);
...@@ -35,21 +35,21 @@ const AddUser = (props) => { ...@@ -35,21 +35,21 @@ const AddUser = (props) => {
const handleCancel = () => { const handleCancel = () => {
props.handleClose(); props.handleClose();
} };
return ( return (
<> <>
<SideSheet <SideSheet
placement={'left'} placement={'left'}
title={<Title level={3}>{'添加用户'}</Title>} title={<Title level={3}>{'添加用户'}</Title>}
headerStyle={{borderBottom: '1px solid var(--semi-color-border)'}} headerStyle={{ borderBottom: '1px solid var(--semi-color-border)' }}
bodyStyle={{borderBottom: '1px solid var(--semi-color-border)'}} bodyStyle={{ borderBottom: '1px solid var(--semi-color-border)' }}
visible={props.visible} visible={props.visible}
footer={ footer={
<div style={{display: 'flex', justifyContent: 'flex-end'}}> <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Space> <Space>
<Button theme='solid' size={'large'} onClick={submit}>提交</Button> <Button theme="solid" size={'large'} onClick={submit}>提交</Button>
<Button theme='solid' size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button> <Button theme="solid" size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button>
</Space> </Space>
</div> </div>
} }
...@@ -59,7 +59,7 @@ const AddUser = (props) => { ...@@ -59,7 +59,7 @@ const AddUser = (props) => {
> >
<Spin spinning={loading}> <Spin spinning={loading}>
<Input <Input
style={{marginTop: 20}} style={{ marginTop: 20 }}
label="用户名" label="用户名"
name="username" name="username"
addonBefore={'用户名'} addonBefore={'用户名'}
...@@ -69,7 +69,7 @@ const AddUser = (props) => { ...@@ -69,7 +69,7 @@ const AddUser = (props) => {
autoComplete="off" autoComplete="off"
/> />
<Input <Input
style={{marginTop: 20}} style={{ marginTop: 20 }}
addonBefore={'显示名'} addonBefore={'显示名'}
label="显示名称" label="显示名称"
name="display_name" name="display_name"
...@@ -79,7 +79,7 @@ const AddUser = (props) => { ...@@ -79,7 +79,7 @@ const AddUser = (props) => {
value={display_name} value={display_name}
/> />
<Input <Input
style={{marginTop: 20}} style={{ marginTop: 20 }}
label="密 码" label="密 码"
name="password" name="password"
type={'password'} type={'password'}
......
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useParams, useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { API, isMobile, showError, showSuccess } from '../../helpers'; import { API, isMobile, showError, showSuccess } from '../../helpers';
import { renderQuota, renderQuotaWithPrompt } from '../../helpers/render'; import { renderQuotaWithPrompt } from '../../helpers/render';
import Title from "@douyinfe/semi-ui/lib/es/typography/title"; import Title from '@douyinfe/semi-ui/lib/es/typography/title';
import { SideSheet, Space, Button, Spin, Input, Typography, Select, Divider } from "@douyinfe/semi-ui"; import { Button, Divider, Input, Select, SideSheet, Space, Spin, Typography } from '@douyinfe/semi-ui';
const EditUser = (props) => { const EditUser = (props) => {
const userId = props.editingUser.id; const userId = props.editingUser.id;
...@@ -29,7 +29,7 @@ const EditUser = (props) => { ...@@ -29,7 +29,7 @@ const EditUser = (props) => {
let res = await API.get(`/api/group/`); let res = await API.get(`/api/group/`);
setGroupOptions(res.data.data.map((group) => ({ setGroupOptions(res.data.data.map((group) => ({
label: group, label: group,
value: group, value: group
}))); })));
} catch (error) { } catch (error) {
showError(error.message); showError(error.message);
...@@ -38,7 +38,7 @@ const EditUser = (props) => { ...@@ -38,7 +38,7 @@ const EditUser = (props) => {
const navigate = useNavigate(); const navigate = useNavigate();
const handleCancel = () => { const handleCancel = () => {
props.handleClose(); props.handleClose();
} };
const loadUser = async () => { const loadUser = async () => {
setLoading(true); setLoading(true);
let res = undefined; let res = undefined;
...@@ -98,8 +98,8 @@ const EditUser = (props) => { ...@@ -98,8 +98,8 @@ const EditUser = (props) => {
footer={ footer={
<div style={{ display: 'flex', justifyContent: 'flex-end' }}> <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Space> <Space>
<Button theme='solid' size={'large'} onClick={submit}>提交</Button> <Button theme="solid" size={'large'} onClick={submit}>提交</Button>
<Button theme='solid' size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button> <Button theme="solid" size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button>
</Space> </Space>
</div> </div>
} }
...@@ -112,35 +112,35 @@ const EditUser = (props) => { ...@@ -112,35 +112,35 @@ const EditUser = (props) => {
<Typography.Text>用户名</Typography.Text> <Typography.Text>用户名</Typography.Text>
</div> </div>
<Input <Input
label='用户名' label="用户名"
name='username' name="username"
placeholder={'请输入新的用户名'} placeholder={'请输入新的用户名'}
onChange={value => handleInputChange('username', value)} onChange={value => handleInputChange('username', value)}
value={username} value={username}
autoComplete='new-password' autoComplete="new-password"
/> />
<div style={{ marginTop: 20 }}> <div style={{ marginTop: 20 }}>
<Typography.Text>密码</Typography.Text> <Typography.Text>密码</Typography.Text>
</div> </div>
<Input <Input
label='密码' label="密码"
name='password' name="password"
type={'password'} type={'password'}
placeholder={'请输入新的密码,最短 8 位'} placeholder={'请输入新的密码,最短 8 位'}
onChange={value => handleInputChange('password', value)} onChange={value => handleInputChange('password', value)}
value={password} value={password}
autoComplete='new-password' autoComplete="new-password"
/> />
<div style={{ marginTop: 20 }}> <div style={{ marginTop: 20 }}>
<Typography.Text>显示名称</Typography.Text> <Typography.Text>显示名称</Typography.Text>
</div> </div>
<Input <Input
label='显示名称' label="显示名称"
name='display_name' name="display_name"
placeholder={'请输入新的显示名称'} placeholder={'请输入新的显示名称'}
onChange={value => handleInputChange('display_name', value)} onChange={value => handleInputChange('display_name', value)}
value={display_name} value={display_name}
autoComplete='new-password' autoComplete="new-password"
/> />
{ {
userId && <> userId && <>
...@@ -149,7 +149,7 @@ const EditUser = (props) => { ...@@ -149,7 +149,7 @@ const EditUser = (props) => {
</div> </div>
<Select <Select
placeholder={'请选择分组'} placeholder={'请选择分组'}
name='group' name="group"
fluid fluid
search search
selection selection
...@@ -157,19 +157,19 @@ const EditUser = (props) => { ...@@ -157,19 +157,19 @@ const EditUser = (props) => {
additionLabel={'请在系统设置页面编辑分组倍率以添加新的分组:'} additionLabel={'请在系统设置页面编辑分组倍率以添加新的分组:'}
onChange={value => handleInputChange('group', value)} onChange={value => handleInputChange('group', value)}
value={inputs.group} value={inputs.group}
autoComplete='new-password' autoComplete="new-password"
optionList={groupOptions} optionList={groupOptions}
/> />
<div style={{ marginTop: 20 }}> <div style={{ marginTop: 20 }}>
<Typography.Text>{`剩余额度${renderQuotaWithPrompt(quota)}`}</Typography.Text> <Typography.Text>{`剩余额度${renderQuotaWithPrompt(quota)}`}</Typography.Text>
</div> </div>
<Input <Input
name='quota' name="quota"
placeholder={'请输入新的剩余额度'} placeholder={'请输入新的剩余额度'}
onChange={value => handleInputChange('quota', value)} onChange={value => handleInputChange('quota', value)}
value={quota} value={quota}
type={'number'} type={'number'}
autoComplete='new-password' autoComplete="new-password"
/> />
</> </>
} }
...@@ -178,37 +178,37 @@ const EditUser = (props) => { ...@@ -178,37 +178,37 @@ const EditUser = (props) => {
<Typography.Text>已绑定的 GitHub 账户</Typography.Text> <Typography.Text>已绑定的 GitHub 账户</Typography.Text>
</div> </div>
<Input <Input
name='github_id' name="github_id"
value={github_id} value={github_id}
autoComplete='new-password' autoComplete="new-password"
placeholder='此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改' placeholder="此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改"
readonly readonly
/> />
<div style={{ marginTop: 20 }}> <div style={{ marginTop: 20 }}>
<Typography.Text>已绑定的微信账户</Typography.Text> <Typography.Text>已绑定的微信账户</Typography.Text>
</div> </div>
<Input <Input
name='wechat_id' name="wechat_id"
value={wechat_id} value={wechat_id}
autoComplete='new-password' autoComplete="new-password"
placeholder='此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改' placeholder="此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改"
readonly readonly
/> />
<Input <Input
name='telegram_id' name="telegram_id"
value={telegram_id} value={telegram_id}
autoComplete='new-password' autoComplete="new-password"
placeholder='此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改' placeholder="此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改"
readonly readonly
/> />
<div style={{ marginTop: 20 }}> <div style={{ marginTop: 20 }}>
<Typography.Text>已绑定的邮箱账户</Typography.Text> <Typography.Text>已绑定的邮箱账户</Typography.Text>
</div> </div>
<Input <Input
name='email' name="email"
value={email} value={email}
autoComplete='new-password' autoComplete="new-password"
placeholder='此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改' placeholder="此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改"
readonly readonly
/> />
</Spin> </Spin>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment