Commit add3b05d by CaIon

chore: reformat code

parent 7c547cbc
......@@ -13,7 +13,7 @@ import (
// TODO: when a new api is enabled, check the pricing here
// 1 === $0.002 / 1K tokens
// 1 === ¥0.014 / 1k tokens
var ModelRatio = map[string]float64{
var DefaultModelRatio = map[string]float64{
//"midjourney": 50,
"gpt-4-gizmo-*": 15,
"gpt-4": 15,
......@@ -115,6 +115,7 @@ var DefaultModelPrice = map[string]float64{
}
var ModelPrice = map[string]float64{}
var ModelRatio = map[string]float64{}
func ModelPrice2JSONString() string {
if len(ModelPrice) == 0 {
......@@ -150,6 +151,9 @@ func GetModelPrice(name string, printErr bool) float64 {
}
func ModelRatio2JSONString() string {
if len(ModelRatio) == 0 {
ModelRatio = DefaultModelRatio
}
jsonBytes, err := json.Marshal(ModelRatio)
if err != nil {
SysError("error marshalling model ratio: " + err.Error())
......@@ -163,6 +167,9 @@ func UpdateModelRatioByJSONString(jsonStr string) error {
}
func GetModelRatio(name string) float64 {
if len(ModelRatio) == 0 {
ModelRatio = DefaultModelRatio
}
if strings.HasPrefix(name, "gpt-4-gizmo") {
name = "gpt-4-gizmo-*"
}
......
......@@ -49,7 +49,7 @@
]
},
"devDependencies": {
"prettier": "^2.7.1",
"prettier": "2.8.8",
"typescript": "4.4.2"
},
"prettier": {
......
import React, { useEffect, useState } from 'react';
import { getFooterHTML, getSystemName } from '../helpers';
import {Layout} from "@douyinfe/semi-ui";
import { Layout } from '@douyinfe/semi-ui';
const Footer = () => {
const systemName = getSystemName();
......@@ -29,30 +29,30 @@ const Footer = () => {
return (
<Layout>
<Layout.Content style={{textAlign: 'center'}}>
<Layout.Content style={{ textAlign: 'center' }}>
{footer ? (
<div
className='custom-footer'
className="custom-footer"
dangerouslySetInnerHTML={{ __html: footer }}
></div>
) : (
<div className='custom-footer'>
<div className="custom-footer">
<a
href='https://github.com/Calcium-Ion/new-api'
target='_blank'
href="https://github.com/Calcium-Ion/new-api"
target="_blank" rel="noreferrer"
>
New API {process.env.REACT_APP_VERSION}{' '}
</a>
{' '}
<a href='https://github.com/Calcium-Ion' target='_blank'>
<a href="https://github.com/Calcium-Ion" target="_blank" rel="noreferrer">
Calcium-Ion
</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
</a>{' '}
,本项目根据{' '}
<a href='https://opensource.org/licenses/mit-license.php'>
<a href="https://opensource.org/licenses/mit-license.php">
MIT 许可证
</a>{' '}
授权
......
......@@ -49,7 +49,7 @@ const GitHubOAuth = () => {
return (
<Segment style={{ minHeight: '300px' }}>
<Dimmer active inverted>
<Loader size='large'>{prompt}</Loader>
<Loader size="large">{prompt}</Loader>
</Dimmer>
</Segment>
);
......
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' }) => {
return (
......
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 { marked } from 'marked';
......@@ -57,8 +57,8 @@ const OtherSetting = () => {
await updateOption('Notice', inputs.Notice);
showSuccess('公告已更新');
} catch (error) {
console.error("公告更新失败", error);
showError("公告更新失败")
console.error('公告更新失败', error);
showError('公告更新失败');
} finally {
setLoadingInput((loadingInput) => ({ ...loadingInput, Notice: false }));
}
......@@ -72,8 +72,8 @@ const OtherSetting = () => {
await updateOption('SystemName', inputs.SystemName);
showSuccess('系统名称已更新');
} catch (error) {
console.error("系统名称更新失败", error);
showError("系统名称更新失败")
console.error('系统名称更新失败', error);
showError('系统名称更新失败');
} finally {
setLoadingInput((loadingInput) => ({ ...loadingInput, SystemName: false }));
}
......@@ -86,8 +86,8 @@ const OtherSetting = () => {
await updateOption('Logo', inputs.Logo);
showSuccess('Logo 已更新');
} catch (error) {
console.error("Logo 更新失败", error);
showError("Logo 更新失败")
console.error('Logo 更新失败', error);
showError('Logo 更新失败');
} finally {
setLoadingInput((loadingInput) => ({ ...loadingInput, Logo: false }));
}
......@@ -99,8 +99,8 @@ const OtherSetting = () => {
await updateOption(key, inputs[key]);
showSuccess('首页内容已更新');
} catch (error) {
console.error("首页内容更新失败", error);
showError("首页内容更新失败")
console.error('首页内容更新失败', error);
showError('首页内容更新失败');
} finally {
setLoadingInput((loadingInput) => ({ ...loadingInput, HomePageContent: false }));
}
......@@ -112,8 +112,8 @@ const OtherSetting = () => {
await updateOption('About', inputs.About);
showSuccess('关于内容已更新');
} catch (error) {
console.error("关于内容更新失败", error);
showError("关于内容更新失败");
console.error('关于内容更新失败', error);
showError('关于内容更新失败');
} finally {
setLoadingInput((loadingInput) => ({ ...loadingInput, About: false }));
}
......@@ -125,16 +125,14 @@ const OtherSetting = () => {
await updateOption('Footer', inputs.Footer);
showSuccess('页脚内容已更新');
} catch (error) {
console.error("页脚内容更新失败", error);
showError("页脚内容更新失败");
console.error('页脚内容更新失败', error);
showError('页脚内容更新失败');
} finally {
setLoadingInput((loadingInput) => ({ ...loadingInput, Footer: false }));
}
};
const openGitHubRelease = () => {
window.location =
'https://github.com/songquanpeng/one-api/releases/latest';
......@@ -173,16 +171,17 @@ const OtherSetting = () => {
}
};
useEffect( () => {
useEffect(() => {
getOptions();
}, []);
return (
<Row >
<Row>
<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.TextArea
label={'公告'}
......@@ -191,26 +190,27 @@ const OtherSetting = () => {
onChange={handleInputChange}
style={{ fontFamily: 'JetBrains Mono, Consolas' }}
autosize={{ minRows: 6, maxRows: 12 }}
/>
/>
<Button onClick={submitNotice} loading={loadingInput['Notice']}>设置公告</Button>
</Form.Section>
</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.Input
label={'系统名称'}
placeholder={'在此输入系统名称'}
field={'SystemName'}
onChange={handleInputChange}
/>
/>
<Button onClick={submitSystemName} loading={loadingInput['SystemName']}>设置系统名称</Button>
<Form.Input
label={'Logo 图片地址'}
placeholder={'在此输入 Logo 图片地址'}
field={'Logo'}
onChange={handleInputChange}
/>
/>
<Button onClick={submitLogo} loading={loadingInput['Logo']}>设置 Logo</Button>
<Form.TextArea
label={'首页内容'}
......@@ -219,8 +219,9 @@ const OtherSetting = () => {
onChange={handleInputChange}
style={{ fontFamily: 'JetBrains Mono, Consolas' }}
autosize={{ minRows: 6, maxRows: 12 }}
/>
<Button onClick={() => submitOption('HomePageContent')} loading={loadingInput['HomePageContent']}>设置首页内容</Button>
/>
<Button onClick={() => submitOption('HomePageContent')}
loading={loadingInput['HomePageContent']}>设置首页内容</Button>
<Form.TextArea
label={'关于'}
placeholder={'在此输入新的关于内容,支持 Markdown & HTML 代码。如果输入的是一个链接,则会使用该链接作为 iframe 的 src 属性,这允许你设置任意网页作为关于页面。'}
......@@ -228,7 +229,7 @@ const OtherSetting = () => {
onChange={handleInputChange}
style={{ fontFamily: 'JetBrains Mono, Consolas' }}
autosize={{ minRows: 6, maxRows: 12 }}
/>
/>
<Button onClick={submitAbout} loading={loadingInput['About']}>设置关于</Button>
{/* */}
<Banner
......@@ -236,14 +237,14 @@ const OtherSetting = () => {
type="info"
description="移除 One API 的版权标识必须首先获得授权,项目维护需要花费大量精力,如果本项目对你有意义,请主动支持本项目。"
closeIcon={null}
style={{ marginTop: 15 }}
style={{ marginTop: 15 }}
/>
<Form.Input
label={'页脚'}
placeholder={'在此输入新的页脚,留空则使用默认页脚,支持 HTML 代码'}
field={'Footer'}
onChange={handleInputChange}
/>
/>
<Button onClick={submitFooter} loading={loadingInput['Footer']}>设置页脚</Button>
</Form.Section>
</Form>
......@@ -270,7 +271,7 @@ const OtherSetting = () => {
{/* />*/}
{/* </Modal.Actions>*/}
{/*</Modal>*/}
</Row>
</Row>
);
};
......
import React, { useEffect, useState } from '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';
const PasswordResetConfirm = () => {
const [inputs, setInputs] = useState({
email: '',
token: '',
token: ''
});
const { email, token } = inputs;
......@@ -23,7 +23,7 @@ const PasswordResetConfirm = () => {
let email = searchParams.get('email');
setInputs({
token,
email,
email
});
}, []);
......@@ -37,7 +37,7 @@ const PasswordResetConfirm = () => {
setDisableButton(false);
setCountdown(30);
}
return () => clearInterval(countdownInterval);
return () => clearInterval(countdownInterval);
}, [disableButton, countdown]);
async function handleSubmit(e) {
......@@ -46,7 +46,7 @@ const PasswordResetConfirm = () => {
setLoading(true);
const res = await API.post(`/api/user/reset`, {
email,
token,
token
});
const { success, message } = res.data;
if (success) {
......@@ -59,44 +59,44 @@ const PasswordResetConfirm = () => {
}
setLoading(false);
}
return (
<Grid textAlign='center' style={{ marginTop: '48px' }}>
<Grid textAlign="center" style={{ marginTop: '48px' }}>
<Grid.Column style={{ maxWidth: 450 }}>
<Header as='h2' color='' textAlign='center'>
<Image src='/logo.png' /> 密码重置确认
<Header as="h2" color="" textAlign="center">
<Image src="/logo.png" /> 密码重置确认
</Header>
<Form size='large'>
<Form size="large">
<Segment>
<Form.Input
fluid
icon='mail'
iconPosition='left'
placeholder='邮箱地址'
name='email'
icon="mail"
iconPosition="left"
placeholder="邮箱地址"
name="email"
value={email}
readOnly
/>
{newPassword && (
<Form.Input
fluid
icon='lock'
iconPosition='left'
placeholder='新密码'
name='newPassword'
value={newPassword}
readOnly
onClick={(e) => {
e.target.select();
navigator.clipboard.writeText(newPassword);
showNotice(`密码已复制到剪贴板:${newPassword}`);
}}
/>
fluid
icon="lock"
iconPosition="left"
placeholder="新密码"
name="newPassword"
value={newPassword}
readOnly
onClick={(e) => {
e.target.select();
navigator.clipboard.writeText(newPassword);
showNotice(`密码已复制到剪贴板:${newPassword}`);
}}
/>
)}
<Button
color='green'
color="green"
fluid
size='large'
size="large"
onClick={handleSubmit}
loading={loading}
disabled={disableButton}
......@@ -107,7 +107,7 @@ const PasswordResetConfirm = () => {
</Form>
</Grid.Column>
</Grid>
);
);
};
export default PasswordResetConfirm;
......@@ -56,19 +56,19 @@ const PasswordResetForm = () => {
}
return (
<Grid textAlign='center' style={{ marginTop: '48px' }}>
<Grid textAlign="center" style={{ marginTop: '48px' }}>
<Grid.Column style={{ maxWidth: 450 }}>
<Header as='h2' color='' textAlign='center'>
<Image src='/logo.png' /> 密码重置
<Header as="h2" color="" textAlign="center">
<Image src="/logo.png" /> 密码重置
</Header>
<Form size='large'>
<Form size="large">
<Segment>
<Form.Input
fluid
icon='mail'
iconPosition='left'
placeholder='邮箱地址'
name='email'
icon="mail"
iconPosition="left"
placeholder="邮箱地址"
name="email"
value={email}
onChange={handleChange}
/>
......@@ -83,9 +83,9 @@ const PasswordResetForm = () => {
<></>
)}
<Button
color='green'
color="green"
fluid
size='large'
size="large"
onClick={handleSubmit}
loading={loading}
disabled={disableButton}
......
......@@ -5,7 +5,7 @@ import { history } from '../helpers';
function PrivateRoute({ children }) {
if (!localStorage.getItem('user')) {
return <Navigate to='/login' state={{ from: history.location }} />;
return <Navigate to="/login" state={{ from: history.location }} />;
}
return children;
}
......
......@@ -98,49 +98,49 @@ const RegisterForm = () => {
};
return (
<Grid textAlign='center' style={{ marginTop: '48px' }}>
<Grid textAlign="center" style={{ marginTop: '48px' }}>
<Grid.Column style={{ maxWidth: 450 }}>
<Header as='h2' color='' textAlign='center'>
<Header as="h2" color="" textAlign="center">
<Image src={logo} /> 新用户注
</Header>
<Form size='large'>
<Form size="large">
<Segment>
<Form.Input
fluid
icon='user'
iconPosition='left'
placeholder='输入用户名,最长 12 位'
icon="user"
iconPosition="left"
placeholder="输入用户名,最长 12 位"
onChange={handleChange}
name='username'
name="username"
/>
<Form.Input
fluid
icon='lock'
iconPosition='left'
placeholder='输入密码,最短 8 位,最长 20 位'
icon="lock"
iconPosition="left"
placeholder="输入密码,最短 8 位,最长 20 位"
onChange={handleChange}
name='password'
type='password'
name="password"
type="password"
/>
<Form.Input
fluid
icon='lock'
iconPosition='left'
placeholder='输入密码,最短 8 位,最长 20 位'
icon="lock"
iconPosition="left"
placeholder="输入密码,最短 8 位,最长 20 位"
onChange={handleChange}
name='password2'
type='password'
name="password2"
type="password"
/>
{showEmailVerification ? (
<>
<Form.Input
fluid
icon='mail'
iconPosition='left'
placeholder='输入邮箱地址'
icon="mail"
iconPosition="left"
placeholder="输入邮箱地址"
onChange={handleChange}
name='email'
type='email'
name="email"
type="email"
action={
<Button onClick={sendVerificationCode} disabled={loading}>
获取验证码
......@@ -149,11 +149,11 @@ const RegisterForm = () => {
/>
<Form.Input
fluid
icon='lock'
iconPosition='left'
placeholder='输入验证码'
icon="lock"
iconPosition="left"
placeholder="输入验证码"
onChange={handleChange}
name='verification_code'
name="verification_code"
/>
</>
) : (
......@@ -170,9 +170,9 @@ const RegisterForm = () => {
<></>
)}
<Button
color='green'
color="green"
fluid
size='large'
size="large"
onClick={handleSubmit}
loading={loading}
>
......@@ -182,7 +182,7 @@ const RegisterForm = () => {
</Form>
<Message>
已有账户?
<Link to='/login' className='btn btn-link'>
<Link to="/login" className="btn btn-link">
点击登录
</Link>
</Message>
......
......@@ -3,14 +3,14 @@ import { Icon } from '@douyinfe/semi-ui';
const WeChatIcon = () => {
function CustomIcon() {
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'>
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">
<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'
p-id='5092'></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"
p-id="5092"></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'
p-id='5093'></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"
p-id="5093"></path>
</svg>;
}
......
import React, { useEffect, useState } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import {API, downloadTextAsFile, isMobile, showError, showSuccess} from '../../helpers';
import { renderQuota, renderQuotaWithPrompt } from '../../helpers/render';
import {SideSheet, Space, Spin, Button, Input, Typography, AutoComplete, Modal} from "@douyinfe/semi-ui";
import Title from "@douyinfe/semi-ui/lib/es/typography/title";
import {Divider} from "semantic-ui-react";
import { useNavigate, useParams } from 'react-router-dom';
import { API, downloadTextAsFile, isMobile, showError, showSuccess } from '../../helpers';
import { renderQuotaWithPrompt } from '../../helpers/render';
import { AutoComplete, Button, Input, Modal, SideSheet, Space, Spin, Typography } from '@douyinfe/semi-ui';
import Title from '@douyinfe/semi-ui/lib/es/typography/title';
import { Divider } from 'semantic-ui-react';
const EditRedemption = (props) => {
const isEdit = props.editingRedemption.id !== undefined;
const [loading, setLoading] = useState(isEdit);
const params = useParams();
const navigate = useNavigate()
const navigate = useNavigate();
const originInputs = {
name: '',
quota: 100000,
......@@ -22,8 +22,8 @@ const EditRedemption = (props) => {
const handleCancel = () => {
props.handleClose();
}
};
const handleInputChange = (name, value) => {
setInputs((inputs) => ({ ...inputs, [name]: value }));
};
......@@ -43,9 +43,9 @@ const EditRedemption = (props) => {
useEffect(() => {
if (isEdit) {
loadRedemption().then(
() => {
// console.log(inputs);
}
() => {
// console.log(inputs);
}
);
} else {
setInputs(originInputs);
......@@ -82,21 +82,21 @@ const EditRedemption = (props) => {
showError(message);
}
if (!isEdit && data) {
let text = "";
let text = '';
for (let i = 0; i < data.length; i++) {
text += data[i] + "\n";
text += data[i] + '\n';
}
// downloadTextAsFile(text, `${inputs.name}.txt`);
Modal.confirm({
title: '兑换码创建成功',
content: (
<div>
<p>兑换码创建成功,是否下载兑换码?</p>
<p>兑换码将以文本文件的形式下载,文件名为兑换码的名称。</p>
</div>
<div>
<p>兑换码创建成功,是否下载兑换码?</p>
<p>兑换码将以文本文件的形式下载,文件名为兑换码的名称。</p>
</div>
),
onOk: () => {
downloadTextAsFile(text, `${inputs.name}.txt`);
downloadTextAsFile(text, `${inputs.name}.txt`);
}
});
}
......@@ -106,71 +106,71 @@ const EditRedemption = (props) => {
return (
<>
<SideSheet
placement={isEdit ? 'right' : 'left'}
title={<Title level={3}>{isEdit ? '更新兑换码信息' : '创建新的兑换码'}</Title>}
headerStyle={{borderBottom: '1px solid var(--semi-color-border)'}}
bodyStyle={{borderBottom: '1px solid var(--semi-color-border)'}}
visible={props.visiable}
footer={
<div style={{display: 'flex', justifyContent: 'flex-end'}}>
<Space>
<Button theme='solid' size={'large'} onClick={submit}>提交</Button>
<Button theme='solid' size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button>
</Space>
</div>
}
closeIcon={null}
onCancel={() => handleCancel()}
width={isMobile() ? '100%' : 600}
placement={isEdit ? 'right' : 'left'}
title={<Title level={3}>{isEdit ? '更新兑换码信息' : '创建新的兑换码'}</Title>}
headerStyle={{ borderBottom: '1px solid var(--semi-color-border)' }}
bodyStyle={{ borderBottom: '1px solid var(--semi-color-border)' }}
visible={props.visiable}
footer={
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Space>
<Button theme="solid" size={'large'} onClick={submit}>提交</Button>
<Button theme="solid" size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button>
</Space>
</div>
}
closeIcon={null}
onCancel={() => handleCancel()}
width={isMobile() ? '100%' : 600}
>
<Spin spinning={loading}>
<Input
style={{ marginTop: 20 }}
label='名称'
name='name'
placeholder={'请输入名称'}
onChange={value => handleInputChange('name', value)}
value={name}
autoComplete='new-password'
required={!isEdit}
style={{ marginTop: 20 }}
label="名称"
name="name"
placeholder={'请输入名称'}
onChange={value => handleInputChange('name', value)}
value={name}
autoComplete="new-password"
required={!isEdit}
/>
<Divider/>
<Divider />
<div style={{ marginTop: 20 }}>
<Typography.Text>{`额度${renderQuotaWithPrompt(quota)}`}</Typography.Text>
</div>
<AutoComplete
style={{ marginTop: 8 }}
name='quota'
placeholder={'请输入额度'}
onChange={(value) => handleInputChange('quota', value)}
value={quota}
autoComplete='new-password'
type='number'
position={'bottom'}
data={[
{value: 500000, label: '1$'},
{value: 5000000, label: '10$'},
{value: 25000000, label: '50$'},
{value: 50000000, label: '100$'},
{value: 250000000, label: '500$'},
{value: 500000000, label: '1000$'},
]}
style={{ marginTop: 8 }}
name="quota"
placeholder={'请输入额度'}
onChange={(value) => handleInputChange('quota', value)}
value={quota}
autoComplete="new-password"
type="number"
position={'bottom'}
data={[
{ value: 500000, label: '1$' },
{ value: 5000000, label: '10$' },
{ value: 25000000, label: '50$' },
{ value: 50000000, label: '100$' },
{ value: 250000000, label: '500$' },
{ value: 500000000, label: '1000$' }
]}
/>
{
!isEdit && <>
<Divider/>
<Typography.Text>生成数量</Typography.Text>
<Input
style={{ marginTop: 8 }}
label='生成数量'
name='count'
placeholder={'请输入生成数量'}
onChange={value => handleInputChange('count', value)}
value={count}
autoComplete='new-password'
type='number'
/>
</>
!isEdit && <>
<Divider />
<Typography.Text>生成数量</Typography.Text>
<Input
style={{ marginTop: 8 }}
label="生成数量"
name="count"
placeholder={'请输入生成数量'}
onChange={value => handleInputChange('count', value)}
value={count}
autoComplete="new-password"
type="number"
/>
</>
}
</Spin>
</SideSheet>
......
import React, {useState} from 'react';
import {API, isMobile, showError, showSuccess} from '../../helpers';
import Title from "@douyinfe/semi-ui/lib/es/typography/title";
import {Button, SideSheet, Space, Input, Spin} from "@douyinfe/semi-ui";
import React, { useState } from 'react';
import { API, isMobile, showError, showSuccess } from '../../helpers';
import Title from '@douyinfe/semi-ui/lib/es/typography/title';
import { Button, Input, SideSheet, Space, Spin } from '@douyinfe/semi-ui';
const AddUser = (props) => {
const originInputs = {
username: '',
display_name: '',
password: '',
};
const [inputs, setInputs] = useState(originInputs);
const [loading, setLoading] = useState(false);
const {username, display_name, password} = inputs;
const originInputs = {
username: '',
display_name: '',
password: ''
};
const [inputs, setInputs] = useState(originInputs);
const [loading, setLoading] = useState(false);
const { username, display_name, password } = inputs;
const handleInputChange = (name, value) => {
setInputs((inputs) => ({...inputs, [name]: value}));
};
const handleInputChange = (name, value) => {
setInputs((inputs) => ({ ...inputs, [name]: value }));
};
const submit = async () => {
setLoading(true);
if (inputs.username === '' || inputs.password === '') return;
const res = await API.post(`/api/user/`, inputs);
const {success, message} = res.data;
if (success) {
showSuccess('用户账户创建成功!');
setInputs(originInputs);
props.refresh();
props.handleClose();
} else {
showError(message);
}
setLoading(false);
};
const handleCancel = () => {
props.handleClose();
const submit = async () => {
setLoading(true);
if (inputs.username === '' || inputs.password === '') return;
const res = await API.post(`/api/user/`, inputs);
const { success, message } = res.data;
if (success) {
showSuccess('用户账户创建成功!');
setInputs(originInputs);
props.refresh();
props.handleClose();
} else {
showError(message);
}
setLoading(false);
};
return (
<>
<SideSheet
placement={'left'}
title={<Title level={3}>{'添加用户'}</Title>}
headerStyle={{borderBottom: '1px solid var(--semi-color-border)'}}
bodyStyle={{borderBottom: '1px solid var(--semi-color-border)'}}
visible={props.visible}
footer={
<div style={{display: 'flex', justifyContent: 'flex-end'}}>
<Space>
<Button theme='solid' size={'large'} onClick={submit}>提交</Button>
<Button theme='solid' size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button>
</Space>
</div>
}
closeIcon={null}
onCancel={() => handleCancel()}
width={isMobile() ? '100%' : 600}
>
<Spin spinning={loading}>
<Input
style={{marginTop: 20}}
label="用户名"
name="username"
addonBefore={'用户名'}
placeholder={'请输入用户名'}
onChange={value => handleInputChange('username', value)}
value={username}
autoComplete="off"
/>
<Input
style={{marginTop: 20}}
addonBefore={'显示名'}
label="显示名称"
name="display_name"
autoComplete="off"
placeholder={'请输入显示名称'}
onChange={value => handleInputChange('display_name', value)}
value={display_name}
/>
<Input
style={{marginTop: 20}}
label="密 码"
name="password"
type={'password'}
addonBefore={'密码'}
placeholder={'请输入密码'}
onChange={value => handleInputChange('password', value)}
value={password}
autoComplete="off"
/>
</Spin>
</SideSheet>
</>
);
const handleCancel = () => {
props.handleClose();
};
return (
<>
<SideSheet
placement={'left'}
title={<Title level={3}>{'添加用户'}</Title>}
headerStyle={{ borderBottom: '1px solid var(--semi-color-border)' }}
bodyStyle={{ borderBottom: '1px solid var(--semi-color-border)' }}
visible={props.visible}
footer={
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Space>
<Button theme="solid" size={'large'} onClick={submit}>提交</Button>
<Button theme="solid" size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button>
</Space>
</div>
}
closeIcon={null}
onCancel={() => handleCancel()}
width={isMobile() ? '100%' : 600}
>
<Spin spinning={loading}>
<Input
style={{ marginTop: 20 }}
label="用户名"
name="username"
addonBefore={'用户名'}
placeholder={'请输入用户名'}
onChange={value => handleInputChange('username', value)}
value={username}
autoComplete="off"
/>
<Input
style={{ marginTop: 20 }}
addonBefore={'显示名'}
label="显示名称"
name="display_name"
autoComplete="off"
placeholder={'请输入显示名称'}
onChange={value => handleInputChange('display_name', value)}
value={display_name}
/>
<Input
style={{ marginTop: 20 }}
label="密 码"
name="password"
type={'password'}
addonBefore={'密码'}
placeholder={'请输入密码'}
onChange={value => handleInputChange('password', value)}
value={password}
autoComplete="off"
/>
</Spin>
</SideSheet>
</>
);
};
export default AddUser;
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 { renderQuota, renderQuotaWithPrompt } from '../../helpers/render';
import Title from "@douyinfe/semi-ui/lib/es/typography/title";
import { SideSheet, Space, Button, Spin, Input, Typography, Select, Divider } from "@douyinfe/semi-ui";
import { renderQuotaWithPrompt } from '../../helpers/render';
import Title from '@douyinfe/semi-ui/lib/es/typography/title';
import { Button, Divider, Input, Select, SideSheet, Space, Spin, Typography } from '@douyinfe/semi-ui';
const EditUser = (props) => {
const userId = props.editingUser.id;
......@@ -29,7 +29,7 @@ const EditUser = (props) => {
let res = await API.get(`/api/group/`);
setGroupOptions(res.data.data.map((group) => ({
label: group,
value: group,
value: group
})));
} catch (error) {
showError(error.message);
......@@ -38,7 +38,7 @@ const EditUser = (props) => {
const navigate = useNavigate();
const handleCancel = () => {
props.handleClose();
}
};
const loadUser = async () => {
setLoading(true);
let res = undefined;
......@@ -98,8 +98,8 @@ const EditUser = (props) => {
footer={
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Space>
<Button theme='solid' size={'large'} onClick={submit}>提交</Button>
<Button theme='solid' size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button>
<Button theme="solid" size={'large'} onClick={submit}>提交</Button>
<Button theme="solid" size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button>
</Space>
</div>
}
......@@ -112,35 +112,35 @@ const EditUser = (props) => {
<Typography.Text>用户名</Typography.Text>
</div>
<Input
label='用户名'
name='username'
label="用户名"
name="username"
placeholder={'请输入新的用户名'}
onChange={value => handleInputChange('username', value)}
value={username}
autoComplete='new-password'
autoComplete="new-password"
/>
<div style={{ marginTop: 20 }}>
<Typography.Text>密码</Typography.Text>
</div>
<Input
label='密码'
name='password'
label="密码"
name="password"
type={'password'}
placeholder={'请输入新的密码,最短 8 位'}
onChange={value => handleInputChange('password', value)}
value={password}
autoComplete='new-password'
autoComplete="new-password"
/>
<div style={{ marginTop: 20 }}>
<Typography.Text>显示名称</Typography.Text>
</div>
<Input
label='显示名称'
name='display_name'
label="显示名称"
name="display_name"
placeholder={'请输入新的显示名称'}
onChange={value => handleInputChange('display_name', value)}
value={display_name}
autoComplete='new-password'
autoComplete="new-password"
/>
{
userId && <>
......@@ -149,7 +149,7 @@ const EditUser = (props) => {
</div>
<Select
placeholder={'请选择分组'}
name='group'
name="group"
fluid
search
selection
......@@ -157,19 +157,19 @@ const EditUser = (props) => {
additionLabel={'请在系统设置页面编辑分组倍率以添加新的分组:'}
onChange={value => handleInputChange('group', value)}
value={inputs.group}
autoComplete='new-password'
autoComplete="new-password"
optionList={groupOptions}
/>
<div style={{ marginTop: 20 }}>
<Typography.Text>{`剩余额度${renderQuotaWithPrompt(quota)}`}</Typography.Text>
</div>
<Input
name='quota'
name="quota"
placeholder={'请输入新的剩余额度'}
onChange={value => handleInputChange('quota', value)}
value={quota}
type={'number'}
autoComplete='new-password'
autoComplete="new-password"
/>
</>
}
......@@ -178,37 +178,37 @@ const EditUser = (props) => {
<Typography.Text>已绑定的 GitHub 账户</Typography.Text>
</div>
<Input
name='github_id'
name="github_id"
value={github_id}
autoComplete='new-password'
placeholder='此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改'
autoComplete="new-password"
placeholder="此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改"
readonly
/>
<div style={{ marginTop: 20 }}>
<Typography.Text>已绑定的微信账户</Typography.Text>
</div>
<Input
name='wechat_id'
name="wechat_id"
value={wechat_id}
autoComplete='new-password'
placeholder='此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改'
autoComplete="new-password"
placeholder="此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改"
readonly
/>
<Input
name='telegram_id'
name="telegram_id"
value={telegram_id}
autoComplete='new-password'
placeholder='此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改'
autoComplete="new-password"
placeholder="此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改"
readonly
/>
<div style={{ marginTop: 20 }}>
<Typography.Text>已绑定的邮箱账户</Typography.Text>
</div>
<Input
name='email'
name="email"
value={email}
autoComplete='new-password'
placeholder='此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改'
autoComplete="new-password"
placeholder="此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改"
readonly
/>
</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