mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-20 06:08:38 +00:00
🎨 chore(web): apply ESLint and Prettier auto-fixes (baseline)
- Ran: bun run eslint:fix && bun run lint:fix - Inserted AGPL license header via eslint-plugin-header - Enforced no-multiple-empty-lines and other lint rules - Formatted code using Prettier v3 (@so1ve/prettier-config) - No functional changes; formatting-only baseline across JS/JSX files
This commit is contained in:
@@ -35,19 +35,22 @@ import {
|
||||
Col,
|
||||
Badge,
|
||||
Progress,
|
||||
Card
|
||||
Card,
|
||||
} from '@douyinfe/semi-ui';
|
||||
import { IllustrationNoResult, IllustrationNoResultDark } from '@douyinfe/semi-illustrations';
|
||||
import { API, showError, showSuccess, timestamp2string } from '../../../../helpers';
|
||||
import {
|
||||
IllustrationNoResult,
|
||||
IllustrationNoResultDark,
|
||||
} from '@douyinfe/semi-illustrations';
|
||||
import {
|
||||
API,
|
||||
showError,
|
||||
showSuccess,
|
||||
timestamp2string,
|
||||
} from '../../../../helpers';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
const MultiKeyManageModal = ({
|
||||
visible,
|
||||
onCancel,
|
||||
channel,
|
||||
onRefresh
|
||||
}) => {
|
||||
const MultiKeyManageModal = ({ visible, onCancel, channel, onRefresh }) => {
|
||||
const { t } = useTranslation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [keyStatusList, setKeyStatusList] = useState([]);
|
||||
@@ -68,7 +71,11 @@ const MultiKeyManageModal = ({
|
||||
const [statusFilter, setStatusFilter] = useState(null); // null=all, 1=enabled, 2=manual_disabled, 3=auto_disabled
|
||||
|
||||
// Load key status data
|
||||
const loadKeyStatus = async (page = currentPage, size = pageSize, status = statusFilter) => {
|
||||
const loadKeyStatus = async (
|
||||
page = currentPage,
|
||||
size = pageSize,
|
||||
status = statusFilter,
|
||||
) => {
|
||||
if (!channel?.id) return;
|
||||
|
||||
setLoading(true);
|
||||
@@ -77,7 +84,7 @@ const MultiKeyManageModal = ({
|
||||
channel_id: channel.id,
|
||||
action: 'get_key_status',
|
||||
page: page,
|
||||
page_size: size
|
||||
page_size: size,
|
||||
};
|
||||
|
||||
// Add status filter if specified
|
||||
@@ -113,13 +120,13 @@ const MultiKeyManageModal = ({
|
||||
// Disable a specific key
|
||||
const handleDisableKey = async (keyIndex) => {
|
||||
const operationId = `disable_${keyIndex}`;
|
||||
setOperationLoading(prev => ({ ...prev, [operationId]: true }));
|
||||
setOperationLoading((prev) => ({ ...prev, [operationId]: true }));
|
||||
|
||||
try {
|
||||
const res = await API.post('/api/channel/multi_key/manage', {
|
||||
channel_id: channel.id,
|
||||
action: 'disable_key',
|
||||
key_index: keyIndex
|
||||
key_index: keyIndex,
|
||||
});
|
||||
|
||||
if (res.data.success) {
|
||||
@@ -132,20 +139,20 @@ const MultiKeyManageModal = ({
|
||||
} catch (error) {
|
||||
showError(t('禁用密钥失败'));
|
||||
} finally {
|
||||
setOperationLoading(prev => ({ ...prev, [operationId]: false }));
|
||||
setOperationLoading((prev) => ({ ...prev, [operationId]: false }));
|
||||
}
|
||||
};
|
||||
|
||||
// Enable a specific key
|
||||
const handleEnableKey = async (keyIndex) => {
|
||||
const operationId = `enable_${keyIndex}`;
|
||||
setOperationLoading(prev => ({ ...prev, [operationId]: true }));
|
||||
setOperationLoading((prev) => ({ ...prev, [operationId]: true }));
|
||||
|
||||
try {
|
||||
const res = await API.post('/api/channel/multi_key/manage', {
|
||||
channel_id: channel.id,
|
||||
action: 'enable_key',
|
||||
key_index: keyIndex
|
||||
key_index: keyIndex,
|
||||
});
|
||||
|
||||
if (res.data.success) {
|
||||
@@ -158,18 +165,18 @@ const MultiKeyManageModal = ({
|
||||
} catch (error) {
|
||||
showError(t('启用密钥失败'));
|
||||
} finally {
|
||||
setOperationLoading(prev => ({ ...prev, [operationId]: false }));
|
||||
setOperationLoading((prev) => ({ ...prev, [operationId]: false }));
|
||||
}
|
||||
};
|
||||
|
||||
// Enable all disabled keys
|
||||
const handleEnableAll = async () => {
|
||||
setOperationLoading(prev => ({ ...prev, enable_all: true }));
|
||||
setOperationLoading((prev) => ({ ...prev, enable_all: true }));
|
||||
|
||||
try {
|
||||
const res = await API.post('/api/channel/multi_key/manage', {
|
||||
channel_id: channel.id,
|
||||
action: 'enable_all_keys'
|
||||
action: 'enable_all_keys',
|
||||
});
|
||||
|
||||
if (res.data.success) {
|
||||
@@ -184,18 +191,18 @@ const MultiKeyManageModal = ({
|
||||
} catch (error) {
|
||||
showError(t('启用所有密钥失败'));
|
||||
} finally {
|
||||
setOperationLoading(prev => ({ ...prev, enable_all: false }));
|
||||
setOperationLoading((prev) => ({ ...prev, enable_all: false }));
|
||||
}
|
||||
};
|
||||
|
||||
// Disable all enabled keys
|
||||
const handleDisableAll = async () => {
|
||||
setOperationLoading(prev => ({ ...prev, disable_all: true }));
|
||||
setOperationLoading((prev) => ({ ...prev, disable_all: true }));
|
||||
|
||||
try {
|
||||
const res = await API.post('/api/channel/multi_key/manage', {
|
||||
channel_id: channel.id,
|
||||
action: 'disable_all_keys'
|
||||
action: 'disable_all_keys',
|
||||
});
|
||||
|
||||
if (res.data.success) {
|
||||
@@ -210,18 +217,18 @@ const MultiKeyManageModal = ({
|
||||
} catch (error) {
|
||||
showError(t('禁用所有密钥失败'));
|
||||
} finally {
|
||||
setOperationLoading(prev => ({ ...prev, disable_all: false }));
|
||||
setOperationLoading((prev) => ({ ...prev, disable_all: false }));
|
||||
}
|
||||
};
|
||||
|
||||
// Delete all disabled keys
|
||||
const handleDeleteDisabledKeys = async () => {
|
||||
setOperationLoading(prev => ({ ...prev, delete_disabled: true }));
|
||||
setOperationLoading((prev) => ({ ...prev, delete_disabled: true }));
|
||||
|
||||
try {
|
||||
const res = await API.post('/api/channel/multi_key/manage', {
|
||||
channel_id: channel.id,
|
||||
action: 'delete_disabled_keys'
|
||||
action: 'delete_disabled_keys',
|
||||
});
|
||||
|
||||
if (res.data.success) {
|
||||
@@ -236,7 +243,7 @@ const MultiKeyManageModal = ({
|
||||
} catch (error) {
|
||||
showError(t('删除禁用密钥失败'));
|
||||
} finally {
|
||||
setOperationLoading(prev => ({ ...prev, delete_disabled: false }));
|
||||
setOperationLoading((prev) => ({ ...prev, delete_disabled: false }));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -246,7 +253,7 @@ const MultiKeyManageModal = ({
|
||||
loadKeyStatus(page, pageSize);
|
||||
};
|
||||
|
||||
// Handle page size change
|
||||
// Handle page size change
|
||||
const handlePageSizeChange = (size) => {
|
||||
setPageSize(size);
|
||||
setCurrentPage(1); // Reset to first page
|
||||
@@ -283,9 +290,12 @@ const MultiKeyManageModal = ({
|
||||
}, [visible]);
|
||||
|
||||
// Percentages for progress display
|
||||
const enabledPercent = total > 0 ? Math.round((enabledCount / total) * 100) : 0;
|
||||
const manualDisabledPercent = total > 0 ? Math.round((manualDisabledCount / total) * 100) : 0;
|
||||
const autoDisabledPercent = total > 0 ? Math.round((autoDisabledCount / total) * 100) : 0;
|
||||
const enabledPercent =
|
||||
total > 0 ? Math.round((enabledCount / total) * 100) : 0;
|
||||
const manualDisabledPercent =
|
||||
total > 0 ? Math.round((manualDisabledCount / total) * 100) : 0;
|
||||
const autoDisabledPercent =
|
||||
total > 0 ? Math.round((autoDisabledCount / total) * 100) : 0;
|
||||
|
||||
// 取消饼图:不再需要图表数据与配置
|
||||
|
||||
@@ -293,13 +303,29 @@ const MultiKeyManageModal = ({
|
||||
const renderStatusTag = (status) => {
|
||||
switch (status) {
|
||||
case 1:
|
||||
return <Tag color='green' shape='circle' size='small'>{t('已启用')}</Tag>;
|
||||
return (
|
||||
<Tag color='green' shape='circle' size='small'>
|
||||
{t('已启用')}
|
||||
</Tag>
|
||||
);
|
||||
case 2:
|
||||
return <Tag color='red' shape='circle' size='small'>{t('已禁用')}</Tag>;
|
||||
return (
|
||||
<Tag color='red' shape='circle' size='small'>
|
||||
{t('已禁用')}
|
||||
</Tag>
|
||||
);
|
||||
case 3:
|
||||
return <Tag color='orange' shape='circle' size='small'>{t('自动禁用')}</Tag>;
|
||||
return (
|
||||
<Tag color='orange' shape='circle' size='small'>
|
||||
{t('自动禁用')}
|
||||
</Tag>
|
||||
);
|
||||
default:
|
||||
return <Tag color='grey' shape='circle' size='small'>{t('未知状态')}</Tag>;
|
||||
return (
|
||||
<Tag color='grey' shape='circle' size='small'>
|
||||
{t('未知状态')}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -349,9 +375,7 @@ const MultiKeyManageModal = ({
|
||||
}
|
||||
return (
|
||||
<Tooltip content={timestamp2string(time)}>
|
||||
<Text style={{ fontSize: '12px' }}>
|
||||
{timestamp2string(time)}
|
||||
</Text>
|
||||
<Text style={{ fontSize: '12px' }}>{timestamp2string(time)}</Text>
|
||||
</Tooltip>
|
||||
);
|
||||
},
|
||||
@@ -393,14 +417,18 @@ const MultiKeyManageModal = ({
|
||||
<Space>
|
||||
<Text>{t('多密钥管理')}</Text>
|
||||
{channel?.name && (
|
||||
<Tag size='small' shape='circle' color='white'>{channel.name}</Tag>
|
||||
<Tag size='small' shape='circle' color='white'>
|
||||
{channel.name}
|
||||
</Tag>
|
||||
)}
|
||||
<Tag size='small' shape='circle' color='white'>
|
||||
{t('总密钥数')}: {total}
|
||||
</Tag>
|
||||
{channel?.channel_info?.multi_key_mode && (
|
||||
<Tag size='small' shape='circle' color='white'>
|
||||
{channel.channel_info.multi_key_mode === 'random' ? t('随机模式') : t('轮询模式')}
|
||||
{channel.channel_info.multi_key_mode === 'random'
|
||||
? t('随机模式')
|
||||
: t('轮询模式')}
|
||||
</Tag>
|
||||
)}
|
||||
</Space>
|
||||
@@ -410,60 +438,123 @@ const MultiKeyManageModal = ({
|
||||
width={900}
|
||||
footer={null}
|
||||
>
|
||||
<div className="flex flex-col mb-5">
|
||||
<div className='flex flex-col mb-5'>
|
||||
{/* Stats & Mode */}
|
||||
<div
|
||||
className="rounded-xl p-4 mb-3"
|
||||
className='rounded-xl p-4 mb-3'
|
||||
style={{
|
||||
background: 'var(--semi-color-bg-1)',
|
||||
border: '1px solid var(--semi-color-border)'
|
||||
border: '1px solid var(--semi-color-border)',
|
||||
}}
|
||||
>
|
||||
<Row gutter={16} align="middle">
|
||||
<Row gutter={16} align='middle'>
|
||||
<Col span={8}>
|
||||
<div style={{ background: 'var(--semi-color-bg-0)', border: '1px solid var(--semi-color-border)', borderRadius: 12, padding: 12 }}>
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div
|
||||
style={{
|
||||
background: 'var(--semi-color-bg-0)',
|
||||
border: '1px solid var(--semi-color-border)',
|
||||
borderRadius: 12,
|
||||
padding: 12,
|
||||
}}
|
||||
>
|
||||
<div className='flex items-center gap-2 mb-2'>
|
||||
<Badge dot type='success' />
|
||||
<Text type='tertiary'>{t('已启用')}</Text>
|
||||
</div>
|
||||
<div className="flex items-end gap-2 mb-2">
|
||||
<Text style={{ fontSize: 18, fontWeight: 700, color: '#22c55e' }}>{enabledCount}</Text>
|
||||
<Text style={{ fontSize: 18, color: 'var(--semi-color-text-2)' }}>/ {total}</Text>
|
||||
<div className='flex items-end gap-2 mb-2'>
|
||||
<Text
|
||||
style={{ fontSize: 18, fontWeight: 700, color: '#22c55e' }}
|
||||
>
|
||||
{enabledCount}
|
||||
</Text>
|
||||
<Text
|
||||
style={{ fontSize: 18, color: 'var(--semi-color-text-2)' }}
|
||||
>
|
||||
/ {total}
|
||||
</Text>
|
||||
</div>
|
||||
<Progress percent={enabledPercent} showInfo={false} size="small" stroke="#22c55e" style={{ height: 6, borderRadius: 999 }} />
|
||||
<Progress
|
||||
percent={enabledPercent}
|
||||
showInfo={false}
|
||||
size='small'
|
||||
stroke='#22c55e'
|
||||
style={{ height: 6, borderRadius: 999 }}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<div style={{ background: 'var(--semi-color-bg-0)', border: '1px solid var(--semi-color-border)', borderRadius: 12, padding: 12 }}>
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div
|
||||
style={{
|
||||
background: 'var(--semi-color-bg-0)',
|
||||
border: '1px solid var(--semi-color-border)',
|
||||
borderRadius: 12,
|
||||
padding: 12,
|
||||
}}
|
||||
>
|
||||
<div className='flex items-center gap-2 mb-2'>
|
||||
<Badge dot type='danger' />
|
||||
<Text type='tertiary'>{t('手动禁用')}</Text>
|
||||
</div>
|
||||
<div className="flex items-end gap-2 mb-2">
|
||||
<Text style={{ fontSize: 18, fontWeight: 700, color: '#ef4444' }}>{manualDisabledCount}</Text>
|
||||
<Text style={{ fontSize: 18, color: 'var(--semi-color-text-2)' }}>/ {total}</Text>
|
||||
<div className='flex items-end gap-2 mb-2'>
|
||||
<Text
|
||||
style={{ fontSize: 18, fontWeight: 700, color: '#ef4444' }}
|
||||
>
|
||||
{manualDisabledCount}
|
||||
</Text>
|
||||
<Text
|
||||
style={{ fontSize: 18, color: 'var(--semi-color-text-2)' }}
|
||||
>
|
||||
/ {total}
|
||||
</Text>
|
||||
</div>
|
||||
<Progress percent={manualDisabledPercent} showInfo={false} size="small" stroke="#ef4444" style={{ height: 6, borderRadius: 999 }} />
|
||||
<Progress
|
||||
percent={manualDisabledPercent}
|
||||
showInfo={false}
|
||||
size='small'
|
||||
stroke='#ef4444'
|
||||
style={{ height: 6, borderRadius: 999 }}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<div style={{ background: 'var(--semi-color-bg-0)', border: '1px solid var(--semi-color-border)', borderRadius: 12, padding: 12 }}>
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div
|
||||
style={{
|
||||
background: 'var(--semi-color-bg-0)',
|
||||
border: '1px solid var(--semi-color-border)',
|
||||
borderRadius: 12,
|
||||
padding: 12,
|
||||
}}
|
||||
>
|
||||
<div className='flex items-center gap-2 mb-2'>
|
||||
<Badge dot type='warning' />
|
||||
<Text type='tertiary'>{t('自动禁用')}</Text>
|
||||
</div>
|
||||
<div className="flex items-end gap-2 mb-2">
|
||||
<Text style={{ fontSize: 18, fontWeight: 700, color: '#f59e0b' }}>{autoDisabledCount}</Text>
|
||||
<Text style={{ fontSize: 18, color: 'var(--semi-color-text-2)' }}>/ {total}</Text>
|
||||
<div className='flex items-end gap-2 mb-2'>
|
||||
<Text
|
||||
style={{ fontSize: 18, fontWeight: 700, color: '#f59e0b' }}
|
||||
>
|
||||
{autoDisabledCount}
|
||||
</Text>
|
||||
<Text
|
||||
style={{ fontSize: 18, color: 'var(--semi-color-text-2)' }}
|
||||
>
|
||||
/ {total}
|
||||
</Text>
|
||||
</div>
|
||||
<Progress percent={autoDisabledPercent} showInfo={false} size="small" stroke="#f59e0b" style={{ height: 6, borderRadius: 999 }} />
|
||||
<Progress
|
||||
percent={autoDisabledPercent}
|
||||
showInfo={false}
|
||||
size='small'
|
||||
stroke='#f59e0b'
|
||||
style={{ height: 6, borderRadius: 999 }}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
{/* Table */}
|
||||
<div className="flex-1 flex flex-col min-h-0">
|
||||
<div className='flex-1 flex flex-col min-h-0'>
|
||||
<Spin spinning={loading}>
|
||||
<Card className='!rounded-xl'>
|
||||
<Table
|
||||
@@ -478,15 +569,26 @@ const MultiKeyManageModal = ({
|
||||
size='small'
|
||||
placeholder={t('全部状态')}
|
||||
>
|
||||
<Select.Option value={null}>{t('全部状态')}</Select.Option>
|
||||
<Select.Option value={1}>{t('已启用')}</Select.Option>
|
||||
<Select.Option value={2}>{t('手动禁用')}</Select.Option>
|
||||
<Select.Option value={3}>{t('自动禁用')}</Select.Option>
|
||||
<Select.Option value={null}>
|
||||
{t('全部状态')}
|
||||
</Select.Option>
|
||||
<Select.Option value={1}>
|
||||
{t('已启用')}
|
||||
</Select.Option>
|
||||
<Select.Option value={2}>
|
||||
{t('手动禁用')}
|
||||
</Select.Option>
|
||||
<Select.Option value={3}>
|
||||
{t('自动禁用')}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col span={10} style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||
<Col
|
||||
span={10}
|
||||
style={{ display: 'flex', justifyContent: 'flex-end' }}
|
||||
>
|
||||
<Space>
|
||||
<Button
|
||||
size='small'
|
||||
@@ -496,7 +598,7 @@ const MultiKeyManageModal = ({
|
||||
>
|
||||
{t('刷新')}
|
||||
</Button>
|
||||
{(manualDisabledCount + autoDisabledCount) > 0 && (
|
||||
{manualDisabledCount + autoDisabledCount > 0 && (
|
||||
<Popconfirm
|
||||
title={t('确定要启用所有密钥吗?')}
|
||||
onConfirm={handleEnableAll}
|
||||
@@ -529,7 +631,9 @@ const MultiKeyManageModal = ({
|
||||
)}
|
||||
<Popconfirm
|
||||
title={t('确定要删除所有已自动禁用的密钥吗?')}
|
||||
content={t('此操作不可撤销,将永久删除已自动禁用的密钥')}
|
||||
content={t(
|
||||
'此操作不可撤销,将永久删除已自动禁用的密钥',
|
||||
)}
|
||||
onConfirm={handleDeleteDisabledKeys}
|
||||
okType={'danger'}
|
||||
position={'topRight'}
|
||||
@@ -562,7 +666,7 @@ const MultiKeyManageModal = ({
|
||||
onShowSizeChange: (current, size) => {
|
||||
setCurrentPage(1);
|
||||
handlePageSizeChange(size);
|
||||
}
|
||||
},
|
||||
}}
|
||||
size='small'
|
||||
bordered={false}
|
||||
@@ -570,8 +674,16 @@ const MultiKeyManageModal = ({
|
||||
scroll={{ x: 'max-content' }}
|
||||
empty={
|
||||
<Empty
|
||||
image={<IllustrationNoResult style={{ width: 140, height: 140 }} />}
|
||||
darkModeImage={<IllustrationNoResultDark style={{ width: 140, height: 140 }} />}
|
||||
image={
|
||||
<IllustrationNoResult
|
||||
style={{ width: 140, height: 140 }}
|
||||
/>
|
||||
}
|
||||
darkModeImage={
|
||||
<IllustrationNoResultDark
|
||||
style={{ width: 140, height: 140 }}
|
||||
/>
|
||||
}
|
||||
title={t('暂无密钥数据')}
|
||||
description={t('请检查渠道配置或刷新重试')}
|
||||
style={{ padding: 30 }}
|
||||
@@ -586,4 +698,4 @@ const MultiKeyManageModal = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default MultiKeyManageModal;
|
||||
export default MultiKeyManageModal;
|
||||
|
||||
Reference in New Issue
Block a user