Merge pull request #1267 from t0ng7u/feature/upstream-ratio-sync
🔄 feat(ratio-sync): introduce upstream ratio synchronisation feature #1220
This commit is contained in:
143
web/src/components/settings/ChannelSelectorModal.js
Normal file
143
web/src/components/settings/ChannelSelectorModal.js
Normal file
@@ -0,0 +1,143 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Modal,
|
||||
Transfer,
|
||||
Input,
|
||||
Space,
|
||||
Checkbox,
|
||||
Avatar,
|
||||
Highlight,
|
||||
} from '@douyinfe/semi-ui';
|
||||
import { IconClose } from '@douyinfe/semi-icons';
|
||||
|
||||
const CHANNEL_STATUS_CONFIG = {
|
||||
1: { color: 'green', text: '启用' },
|
||||
2: { color: 'red', text: '禁用' },
|
||||
3: { color: 'amber', text: '自禁' },
|
||||
default: { color: 'grey', text: '未知' }
|
||||
};
|
||||
|
||||
const getChannelStatusConfig = (status) => {
|
||||
return CHANNEL_STATUS_CONFIG[status] || CHANNEL_STATUS_CONFIG.default;
|
||||
};
|
||||
|
||||
export default function ChannelSelectorModal({
|
||||
t,
|
||||
visible,
|
||||
onCancel,
|
||||
onOk,
|
||||
allChannels = [],
|
||||
selectedChannelIds = [],
|
||||
setSelectedChannelIds,
|
||||
channelEndpoints,
|
||||
updateChannelEndpoint,
|
||||
}) {
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
const ChannelInfo = ({ item, showEndpoint = false, isSelected = false }) => {
|
||||
const channelId = item.key || item.value;
|
||||
const currentEndpoint = channelEndpoints[channelId];
|
||||
const baseUrl = item._originalData?.base_url || '';
|
||||
const status = item._originalData?.status || 0;
|
||||
const statusConfig = getChannelStatusConfig(status);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Avatar color={statusConfig.color} size="small">
|
||||
{statusConfig.text}
|
||||
</Avatar>
|
||||
<div className="info">
|
||||
<div className="name">
|
||||
{isSelected ? (
|
||||
item.label
|
||||
) : (
|
||||
<Highlight sourceString={item.label} searchWords={[searchText]} />
|
||||
)}
|
||||
</div>
|
||||
<div className="email" style={showEndpoint ? { display: 'flex', alignItems: 'center', gap: '4px' } : {}}>
|
||||
<span className="text-xs text-gray-500 truncate max-w-[200px]" title={baseUrl}>
|
||||
{isSelected ? (
|
||||
baseUrl
|
||||
) : (
|
||||
<Highlight sourceString={baseUrl} searchWords={[searchText]} />
|
||||
)}
|
||||
</span>
|
||||
{showEndpoint && (
|
||||
<Input
|
||||
size="small"
|
||||
value={currentEndpoint}
|
||||
onChange={(value) => updateChannelEndpoint(channelId, value)}
|
||||
placeholder="/api/ratio_config"
|
||||
className="flex-1 text-xs"
|
||||
style={{ fontSize: '12px' }}
|
||||
/>
|
||||
)}
|
||||
{isSelected && !showEndpoint && (
|
||||
<span className="text-xs text-gray-700 font-mono bg-gray-100 px-2 py-1 rounded ml-2">
|
||||
{currentEndpoint}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const renderSourceItem = (item) => {
|
||||
return (
|
||||
<div className="components-transfer-source-item" key={item.key}>
|
||||
<Checkbox
|
||||
onChange={item.onChange}
|
||||
checked={item.checked}
|
||||
style={{ height: 52, alignItems: 'center' }}
|
||||
>
|
||||
<ChannelInfo item={item} showEndpoint={true} />
|
||||
</Checkbox>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const renderSelectedItem = (item) => {
|
||||
return (
|
||||
<div className="components-transfer-selected-item" key={item.key}>
|
||||
<ChannelInfo item={item} isSelected={true} />
|
||||
<IconClose style={{ cursor: 'pointer' }} onClick={item.onRemove} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const channelFilter = (input, item) => {
|
||||
const searchLower = input.toLowerCase();
|
||||
return item.label.toLowerCase().includes(searchLower) ||
|
||||
(item._originalData?.base_url || '').toLowerCase().includes(searchLower);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
onCancel={onCancel}
|
||||
onOk={onOk}
|
||||
title={<span className="text-lg font-semibold">{t('选择同步渠道')}</span>}
|
||||
width={1000}
|
||||
>
|
||||
<Space vertical style={{ width: '100%' }}>
|
||||
<Transfer
|
||||
style={{ width: '100%' }}
|
||||
dataSource={allChannels}
|
||||
value={selectedChannelIds}
|
||||
onChange={setSelectedChannelIds}
|
||||
renderSourceItem={renderSourceItem}
|
||||
renderSelectedItem={renderSelectedItem}
|
||||
filter={channelFilter}
|
||||
inputProps={{ placeholder: t('搜索渠道名称或地址') }}
|
||||
onSearch={setSearchText}
|
||||
emptyContent={{
|
||||
left: t('暂无渠道'),
|
||||
right: t('暂无选择'),
|
||||
search: t('无搜索结果'),
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import GroupRatioSettings from '../../pages/Setting/Ratio/GroupRatioSettings.js'
|
||||
import ModelRatioSettings from '../../pages/Setting/Ratio/ModelRatioSettings.js';
|
||||
import ModelSettingsVisualEditor from '../../pages/Setting/Ratio/ModelSettingsVisualEditor.js';
|
||||
import ModelRatioNotSetEditor from '../../pages/Setting/Ratio/ModelRationNotSetEditor.js';
|
||||
import UpstreamRatioSync from '../../pages/Setting/Ratio/UpstreamRatioSync.js';
|
||||
|
||||
import { API, showError } from '../../helpers';
|
||||
|
||||
@@ -21,6 +22,7 @@ const RatioSetting = () => {
|
||||
GroupGroupRatio: '',
|
||||
AutoGroups: '',
|
||||
DefaultUseAutoGroup: false,
|
||||
ExposeRatioEnabled: false,
|
||||
UserUsableGroups: '',
|
||||
});
|
||||
|
||||
@@ -48,7 +50,7 @@ const RatioSetting = () => {
|
||||
// 如果后端返回的不是合法 JSON,直接展示
|
||||
}
|
||||
}
|
||||
if (['DefaultUseAutoGroup'].includes(item.key)) {
|
||||
if (['DefaultUseAutoGroup', 'ExposeRatioEnabled'].includes(item.key)) {
|
||||
newInputs[item.key] = item.value === 'true' ? true : false;
|
||||
} else {
|
||||
newInputs[item.key] = item.value;
|
||||
@@ -78,10 +80,6 @@ const RatioSetting = () => {
|
||||
|
||||
return (
|
||||
<Spin spinning={loading} size='large'>
|
||||
{/* 分组倍率设置 */}
|
||||
<Card style={{ marginTop: '10px' }}>
|
||||
<GroupRatioSettings options={inputs} refresh={onRefresh} />
|
||||
</Card>
|
||||
{/* 模型倍率设置以及可视化编辑器 */}
|
||||
<Card style={{ marginTop: '10px' }}>
|
||||
<Tabs type='line'>
|
||||
@@ -100,8 +98,18 @@ const RatioSetting = () => {
|
||||
refresh={onRefresh}
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab={t('上游倍率同步')} itemKey='upstream_sync'>
|
||||
<UpstreamRatioSync
|
||||
options={inputs}
|
||||
refresh={onRefresh}
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
</Card>
|
||||
{/* 分组倍率设置 */}
|
||||
<Card style={{ marginTop: '10px' }}>
|
||||
<GroupRatioSettings options={inputs} refresh={onRefresh} />
|
||||
</Card>
|
||||
</Spin>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user