Merge branch 'main' into telegram-login

This commit is contained in:
Ehco
2024-03-03 19:42:06 +08:00
committed by GitHub
27 changed files with 233 additions and 116 deletions

View File

@@ -29,7 +29,7 @@ const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
function App() {
const [userState, userDispatch] = useContext(UserContext);
const [statusState, statusDispatch] = useContext(StatusContext);
// const [statusState, statusDispatch] = useContext(StatusContext);
const loadUser = () => {
let user = localStorage.getItem('user');
@@ -38,47 +38,9 @@ function App() {
userDispatch({ type: 'login', payload: data });
}
};
const loadStatus = async () => {
const res = await API.get('/api/status');
const { success, data } = res.data;
if (success) {
localStorage.setItem('status', JSON.stringify(data));
statusDispatch({ type: 'set', payload: data });
localStorage.setItem('system_name', data.system_name);
localStorage.setItem('logo', data.logo);
localStorage.setItem('footer_html', data.footer_html);
localStorage.setItem('quota_per_unit', data.quota_per_unit);
localStorage.setItem('display_in_currency', data.display_in_currency);
localStorage.setItem('enable_drawing', data.enable_drawing);
localStorage.setItem('enable_data_export', data.enable_data_export);
localStorage.setItem('data_export_default_time', data.data_export_default_time);
if (data.chat_link) {
localStorage.setItem('chat_link', data.chat_link);
} else {
localStorage.removeItem('chat_link');
}
if (data.chat_link2) {
localStorage.setItem('chat_link2', data.chat_link2);
} else {
localStorage.removeItem('chat_link2');
}
// if (
// data.version !== process.env.REACT_APP_VERSION &&
// data.version !== 'v0.0.0' &&
// process.env.REACT_APP_VERSION !== ''
// ) {
// showNotice(
// `新版本可用:${data.version},请使用快捷键 Shift + F5 刷新页面`
// );
// }
} else {
showError('无法正常连接至服务器!');
}
};
useEffect(() => {
loadUser();
loadStatus().then();
let systemName = getSystemName();
if (systemName) {
document.title = systemName;

View File

@@ -257,6 +257,7 @@ const ChannelsTable = () => {
const [idSort, setIdSort] = useState(false);
const [searchKeyword, setSearchKeyword] = useState('');
const [searchGroup, setSearchGroup] = useState('');
const [searchModel, setSearchModel] = useState('');
const [searching, setSearching] = useState(false);
const [updatingBalance, setUpdatingBalance] = useState(false);
const [pageSize, setPageSize] = useState(ITEMS_PER_PAGE);
@@ -440,15 +441,15 @@ const ChannelsTable = () => {
}
};
const searchChannels = async (searchKeyword, searchGroup) => {
if (searchKeyword === '' && searchGroup === '') {
const searchChannels = async (searchKeyword, searchGroup, searchModel) => {
if (searchKeyword === '' && searchGroup === '' && searchModel === '') {
// if keyword is blank, load files instead.
await loadChannels(0, pageSize, idSort);
setActivePage(1);
return;
}
setSearching(true);
const res = await API.get(`/api/channel/search?keyword=${searchKeyword}&group=${searchGroup}`);
const res = await API.get(`/api/channel/search?keyword=${searchKeyword}&group=${searchGroup}&model=${searchModel}`);
const {success, message, data} = res.data;
if (success) {
setChannels(data);
@@ -625,13 +626,12 @@ const ChannelsTable = () => {
return (
<>
<EditChannel refresh={refresh} visible={showEdit} handleClose={closeEdit} editingChannel={editingChannel}/>
<Form onSubmit={() => {searchChannels(searchKeyword, searchGroup)}} labelPosition='left'>
<Form onSubmit={() => {searchChannels(searchKeyword, searchGroup, searchModel)}} labelPosition='left'>
<div style={{display: 'flex'}}>
<Space>
<Form.Input
field='search'
label='关键词'
field='search_keyword'
label='搜索渠道关键词'
placeholder='ID名称和密钥 ...'
value={searchKeyword}
loading={searching}
@@ -639,10 +639,22 @@ const ChannelsTable = () => {
setSearchKeyword(v.trim())
}}
/>
<Form.Input
field='search_model'
label='模型'
placeholder='模型关键字'
value={searchModel}
loading={searching}
onChange={(v)=>{
setSearchModel(v.trim())
}}
/>
<Form.Select field="group" label='分组' optionList={groupOptions} onChange={(v) => {
setSearchGroup(v)
searchChannels(searchKeyword, v)
searchChannels(searchKeyword, v, searchModel)
}}/>
<Button label='查询' type="primary" htmlType="submit" className="btn-margin-right"
style={{marginRight: 8}}>查询</Button>
</Space>
</div>
</Form>

View File

@@ -27,6 +27,7 @@ const OperationSetting = () => {
DataExportEnabled: '',
DataExportDefaultTime: 'hour',
DataExportInterval: 5,
DefaultCollapseSidebar: '', // 默认折叠侧边栏
RetryTimes: 0
});
const [originInputs, setOriginInputs] = useState({});
@@ -65,6 +66,10 @@ const OperationSetting = () => {
if (key.endsWith('Enabled')) {
value = inputs[key] === 'true' ? 'false' : 'true';
}
if (key === 'DefaultCollapseSidebar') {
value = inputs[key] === 'true' ? 'false' : 'true';
}
console.log(key, value)
const res = await API.put('/api/option/', {
key,
value
@@ -79,7 +84,7 @@ const OperationSetting = () => {
};
const handleInputChange = async (e, {name, value}) => {
if (name.endsWith('Enabled') || name === 'DataExportInterval' || name === 'DataExportDefaultTime') {
if (name.endsWith('Enabled') || name === 'DataExportInterval' || name === 'DataExportDefaultTime' || name === 'DefaultCollapseSidebar') {
if (name === 'DataExportDefaultTime') {
localStorage.setItem('data_export_default_time', value);
}
@@ -243,6 +248,12 @@ const OperationSetting = () => {
name='DrawingEnabled'
onChange={handleInputChange}
/>
<Form.Checkbox
checked={inputs.DefaultCollapseSidebar === 'true'}
label='默认折叠侧边栏'
name='DefaultCollapseSidebar'
onChange={handleInputChange}
/>
</Form.Group>
<Form.Button onClick={() => {
submitConfig('general').then();

View File

@@ -1,8 +1,8 @@
import React, {useContext, useMemo, useState} from 'react';
import React, { useContext, useEffect, useLayoutEffect, useMemo, useState } from 'react';
import {Link, useNavigate} from 'react-router-dom';
import {UserContext} from '../context/User';
import {API, getLogo, getSystemName, isAdmin, isMobile, showSuccess} from '../helpers';
import { API, getLogo, getSystemName, isAdmin, isMobile, showError, showSuccess } from '../helpers';
import '../index.css';
import {
@@ -24,11 +24,14 @@ import {Nav, Avatar, Dropdown, Layout} from '@douyinfe/semi-ui';
const SiderBar = () => {
const [userState, userDispatch] = useContext(UserContext);
const defaultIsCollapsed = isMobile() || localStorage.getItem('default_collapse_sidebar') === 'true';
let navigate = useNavigate();
const [selectedKeys, setSelectedKeys] = useState(['home']);
const [showSidebar, setShowSidebar] = useState(false);
const systemName = getSystemName();
const logo = getLogo();
const [isCollapsed, setIsCollapsed] = useState(defaultIsCollapsed);
const headerButtons = useMemo(() => [
{
text: '首页',
@@ -110,15 +113,41 @@ const SiderBar = () => {
// }
], [localStorage.getItem('enable_data_export'), localStorage.getItem('enable_drawing'), localStorage.getItem('chat_link'), isAdmin()]);
const loadStatus = async () => {
const res = await API.get('/api/status');
const { success, data } = res.data;
if (success) {
localStorage.setItem('status', JSON.stringify(data));
// statusDispatch({ type: 'set', payload: data });
localStorage.setItem('system_name', data.system_name);
localStorage.setItem('logo', data.logo);
localStorage.setItem('footer_html', data.footer_html);
localStorage.setItem('quota_per_unit', data.quota_per_unit);
localStorage.setItem('display_in_currency', data.display_in_currency);
localStorage.setItem('enable_drawing', data.enable_drawing);
localStorage.setItem('enable_data_export', data.enable_data_export);
localStorage.setItem('data_export_default_time', data.data_export_default_time);
localStorage.setItem('default_collapse_sidebar', data.default_collapse_sidebar);
if (data.chat_link) {
localStorage.setItem('chat_link', data.chat_link);
} else {
localStorage.removeItem('chat_link');
}
if (data.chat_link2) {
localStorage.setItem('chat_link2', data.chat_link2);
} else {
localStorage.removeItem('chat_link2');
}
} else {
showError('无法正常连接至服务器!');
}
};
async function logout() {
setShowSidebar(false);
await API.get('/api/user/logout');
showSuccess('注销成功!');
userDispatch({type: 'logout'});
localStorage.removeItem('user');
navigate('/login');
}
useEffect(() => {
loadStatus().then(() => {
setIsCollapsed(isMobile() || localStorage.getItem('default_collapse_sidebar') === 'true');
});
},[])
return (
<>
@@ -127,7 +156,12 @@ const SiderBar = () => {
<Nav
// mode={'horizontal'}
// bodyStyle={{ height: 100 }}
defaultIsCollapsed={isMobile()}
defaultIsCollapsed={isMobile() || localStorage.getItem('default_collapse_sidebar') === 'true'}
isCollapsed={isCollapsed}
onCollapseChange={collapsed => {
console.log(collapsed);
setIsCollapsed(collapsed);
}}
selectedKeys={selectedKeys}
renderWrapper={({itemElement, isSubNav, isInSubNav, props}) => {
const routerMap = {

View File

@@ -20,8 +20,10 @@ const SystemSetting = () => {
EpayId: '',
EpayKey: '',
Price: 7.3,
MinTopUp: 1,
TopupGroupRatio: '',
PayAddress: '',
CustomCallbackAddress: '',
Footer: '',
WeChatAuthEnabled: '',
WeChatServerAddress: '',
@@ -292,8 +294,8 @@ const SystemSetting = () => {
<Form.Button onClick={submitServerAddress}>
更新服务器地址
</Form.Button>
<Divider />
<Header as='h3'>支付设置当前仅支持易支付接口使用上方服务器地址作为回调地址</Header>
<Divider/>
<Header as='h3'>支付设置当前仅支持易支付接口默认使用上方服务器地址作为回调地址</Header>
<Form.Group widths='equal'>
<Form.Input
label='支付地址,不填写则不启用在线支付'
@@ -316,14 +318,31 @@ const SystemSetting = () => {
name='EpayKey'
onChange={handleInputChange}
/>
<Form.Input
label='充值价格x元/美金)'
placeholder='例如7就是7元/美金'
value={inputs.Price}
name='Price'
min={0}
onChange={handleInputChange}
</Form.Group>
<Form.Group widths='equal'>
<Form.Input
label='回调地址,不填写则使用上方服务器地址作为回调地址'
placeholder='例如https://yourdomain.com'
value={inputs.CustomCallbackAddress}
name='CustomCallbackAddress'
onChange={handleInputChange}
/>
<Form.Input
label='充值价格x元/美金)'
placeholder='例如7就是7元/美金'
value={inputs.Price}
name='Price'
min={0}
onChange={handleInputChange}
/>
<Form.Input
label='最低充值数量'
placeholder='例如2就是最低充值2$'
value={inputs.MinTopUp}
name='MinTopUp'
min={1}
onChange={handleInputChange}
/>
</Form.Group>
<Form.Group widths='equal'>

View File

@@ -153,7 +153,7 @@ const TokensTable = () => {
[
{node: 'item', key: 'next', disabled: !localStorage.getItem('chat_link'), name: 'ChatGPT Next Web', onClick: () => {onOpenLink('next', record.key)}},
{node: 'item', key: 'next-mj', disabled: !localStorage.getItem('chat_link2'), name: 'ChatGPT Web & Midjourney', onClick: () => {onOpenLink('next-mj', record.key)}},
{node: 'item', key: 'ama', name: 'AMA 问天BotGrem', onClick: () => {onOpenLink('ama', record.key)}},
{node: 'item', key: 'ama', name: 'AMA 问天BotGem', onClick: () => {onOpenLink('ama', record.key)}},
{node: 'item', key: 'opencat', name: 'OpenCat', onClick: () => {onOpenLink('opencat', record.key)}},
]
}

View File

@@ -132,6 +132,8 @@ export const modelColorMap = {
'gpt-4-0314': 'rgb(70,130,180)', // 钢蓝色
'gpt-4-0613': 'rgb(100,149,237)', // 矢车菊蓝
'gpt-4-1106-preview': 'rgb(30,144,255)', // 道奇蓝
'gpt-4-0125-preview': 'rgb(2,177,236)', // 深天蓝
'gpt-4-turbo-preview': 'rgb(2,177,255)', // 深天蓝
'gpt-4-32k': 'rgb(104,111,238)', // 中紫色
'gpt-4-32k-0314': 'rgb(90,105,205)', // 暗灰蓝色
'gpt-4-32k-0613': 'rgb(61,71,139)', // 暗蓝灰色

View File

@@ -10,6 +10,7 @@ const TopUp = () => {
const [topUpCount, setTopUpCount] = useState(10);
const [minTopupCount, setMinTopUpCount] = useState(1);
const [amount, setAmount] = useState(0.0);
const [minTopUp, setMinTopUp] = useState(1);
const [topUpLink, setTopUpLink] = useState('');
const [enableOnlineTopUp, setEnableOnlineTopUp] = useState(false);
const [userQuota, setUserQuota] = useState(0);
@@ -61,6 +62,10 @@ const TopUp = () => {
if (amount === 0) {
await getAmount();
}
if (topUpCount < minTopUp) {
showInfo('充值数量不能小于' + minTopUp);
return;
}
setPayWay(payment)
setOpen(true);
}
@@ -69,6 +74,10 @@ const TopUp = () => {
if (amount === 0) {
await getAmount();
}
if (topUpCount < minTopUp) {
showInfo('充值数量不能小于' + minTopUp);
return;
}
setOpen(false);
try {
const res = await API.post('/api/user/pay', {
@@ -132,6 +141,9 @@ const TopUp = () => {
if (status.top_up_link) {
setTopUpLink(status.top_up_link);
}
if (status.min_topup) {
setMinTopUp(status.min_topup);
}
if (status.enable_online_topup) {
setEnableOnlineTopUp(status.enable_online_topup);
}
@@ -239,12 +251,13 @@ const TopUp = () => {
disabled={!enableOnlineTopUp}
field={'redemptionCount'}
label={'实付金额:' + renderAmount()}
placeholder='充值数量'
placeholder={'充值数量,最低' + minTopUp + '$'}
name='redemptionCount'
type={'number'}
value={topUpCount}
suffix={'$'}
min={1}
min={minTopUp}
defaultValue={minTopUp}
max={100000}
onChange={async (value) => {
if (value < 1) {