merge upstream

Signed-off-by: wozulong <>
This commit is contained in:
wozulong
2024-04-05 22:10:07 +08:00
27 changed files with 386 additions and 159 deletions

1
web/.prettierrc.mjs Normal file
View File

@@ -0,0 +1 @@
module.exports = require("@so1ve/prettier-config");

View File

@@ -1 +0,0 @@
module.exports = require("@so1ve/prettier-config");

View File

@@ -471,10 +471,10 @@ const LogsTable = () => {
});
};
const refresh = async (localLogType) => {
const refresh = async () => {
// setLoading(true);
setActivePage(1);
await loadLogs(0, pageSize, localLogType);
await loadLogs(0, pageSize, logType);
};
const copyText = async (text) => {
@@ -637,7 +637,7 @@ const LogsTable = () => {
style={{ width: 120 }}
onChange={(value) => {
setLogType(parseInt(value));
refresh(parseInt(value)).then();
loadLogs(0, pageSize, parseInt(value));
}}
>
<Select.Option value='0'>全部</Select.Option>

View File

@@ -8,39 +8,41 @@ export function renderText(text, limit) {
return text;
}
/**
* Render group tags based on the input group string
* @param {string} group - The input group string
* @returns {JSX.Element} - The rendered group tags
*/
export function renderGroup(group) {
if (group === '') {
return <Tag size='large'>default</Tag>;
return (
<Tag size='large' key='default'>
unknown
</Tag>
);
}
let groups = group.split(',');
groups.sort();
const tagColors = {
vip: 'yellow',
pro: 'yellow',
svip: 'red',
premium: 'red',
};
const groups = group.split(',').sort();
return (
<>
{groups.map((group) => {
if (group === 'vip' || group === 'pro') {
return (
<Tag size='large' color='yellow'>
{group}
</Tag>
);
} else if (group === 'svip' || group === 'premium') {
return (
<Tag size='large' color='red'>
{group}
</Tag>
);
}
if (group === 'default') {
return <Tag size='large'>{group}</Tag>;
} else {
return (
<Tag size='large' color={stringToColor(group)}>
{group}
</Tag>
);
}
})}
</>
<span key={group}>
{groups.map((group) => (
<Tag
size='large'
color={tagColors[group] || stringToColor(group)}
key={group}
>
{group}
</Tag>
))}
</span>
);
}
@@ -99,12 +101,29 @@ export function getQuotaPerUnit() {
return quotaPerUnit;
}
export function renderUnitWithQuota(quota) {
let quotaPerUnit = localStorage.getItem('quota_per_unit');
quotaPerUnit = parseFloat(quotaPerUnit);
quota = parseFloat(quota);
return quotaPerUnit * quota;
}
export function getQuotaWithUnit(quota, digits = 6) {
let quotaPerUnit = localStorage.getItem('quota_per_unit');
quotaPerUnit = parseFloat(quotaPerUnit);
return (quota / quotaPerUnit).toFixed(digits);
}
export function renderQuotaWithAmount(amount) {
let displayInCurrency = localStorage.getItem('display_in_currency');
displayInCurrency = displayInCurrency === 'true';
if (displayInCurrency) {
return '$' + amount;
} else {
return renderUnitWithQuota(amount);
}
}
export function renderQuota(quota, digits = 2) {
let quotaPerUnit = localStorage.getItem('quota_per_unit');
let displayInCurrency = localStorage.getItem('display_in_currency');

View File

@@ -63,6 +63,7 @@ const EditChannel = (props) => {
model_mapping: '',
models: [],
auto_ban: 1,
test_model: '',
groups: ['default'],
};
const [batch, setBatch] = useState(false);
@@ -669,6 +670,17 @@ const EditChannel = (props) => {
}}
value={inputs.openai_organization}
/>
<div style={{ marginTop: 10 }}>
<Typography.Text strong>默认测试模型</Typography.Text>
</div>
<Input
name='test_model'
placeholder='不填则为模型列表第一个'
onChange={(value) => {
handleInputChange('test_model', value);
}}
value={inputs.test_model}
/>
<div style={{ marginTop: 10, display: 'flex' }}>
<Space>
<Checkbox

View File

@@ -1,17 +1,21 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { Layout, TabPane, Tabs } from '@douyinfe/semi-ui';
import { useNavigate, useLocation } from 'react-router-dom';
import SystemSetting from '../../components/SystemSetting';
import { isRoot } from '../../helpers';
import OtherSetting from '../../components/OtherSetting';
import PersonalSetting from '../../components/PersonalSetting';
import OperationSetting from '../../components/OperationSetting';
import { Layout, TabPane, Tabs } from '@douyinfe/semi-ui';
const Setting = () => {
const navigate = useNavigate();
const location = useLocation();
const [tabActiveKey, setTabActiveKey] = useState('1');
let panes = [
{
tab: '个人设置',
content: <PersonalSetting />,
itemKey: '1',
itemKey: 'personal',
},
];
@@ -19,28 +23,44 @@ const Setting = () => {
panes.push({
tab: '运营设置',
content: <OperationSetting />,
itemKey: '2',
itemKey: 'operation',
});
panes.push({
tab: '系统设置',
content: <SystemSetting />,
itemKey: '3',
itemKey: 'system',
});
panes.push({
tab: '其他设置',
content: <OtherSetting />,
itemKey: '4',
itemKey: 'other',
});
}
const onChangeTab = (key) => {
setTabActiveKey(key);
navigate(`?tab=${key}`);
};
useEffect(() => {
const searchParams = new URLSearchParams(window.location.search);
const tab = searchParams.get('tab');
if (tab) {
setTabActiveKey(tab);
} else {
onChangeTab('personal');
}
}, [location.search]);
return (
<div>
<Layout>
<Layout.Content>
<Tabs type='line' defaultActiveKey='1'>
<Tabs
type='line'
activeKey={tabActiveKey}
onChange={(key) => onChangeTab(key)}
>
{panes.map((pane) => (
<TabPane itemKey={pane.itemKey} tab={pane.tab} key={pane.itemKey}>
{pane.content}
{tabActiveKey === pane.itemKey && pane.content}
</TabPane>
))}
</Tabs>