|
@@ -67,6 +67,7 @@ import SecureVerificationModal from '../../../common/modals/SecureVerificationMo
|
|
|
import StatusCodeRiskGuardModal from './StatusCodeRiskGuardModal';
|
|
import StatusCodeRiskGuardModal from './StatusCodeRiskGuardModal';
|
|
|
import ChannelKeyDisplay from '../../../common/ui/ChannelKeyDisplay';
|
|
import ChannelKeyDisplay from '../../../common/ui/ChannelKeyDisplay';
|
|
|
import { useSecureVerification } from '../../../../hooks/common/useSecureVerification';
|
|
import { useSecureVerification } from '../../../../hooks/common/useSecureVerification';
|
|
|
|
|
+import { parseChannelConnectionString } from '../../../../helpers/token';
|
|
|
import { createApiCalls } from '../../../../services/secureVerification';
|
|
import { createApiCalls } from '../../../../services/secureVerification';
|
|
|
import {
|
|
import {
|
|
|
collectInvalidStatusCodeEntries,
|
|
collectInvalidStatusCodeEntries,
|
|
@@ -398,6 +399,9 @@ const EditChannelModal = (props) => {
|
|
|
[],
|
|
[],
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
|
|
+ // 剪贴板连接信息自动检测
|
|
|
|
|
+ const [clipboardConfig, setClipboardConfig] = useState(null);
|
|
|
|
|
+
|
|
|
// 高级设置折叠状态
|
|
// 高级设置折叠状态
|
|
|
const [advancedSettingsOpen, setAdvancedSettingsOpen] = useState(false);
|
|
const [advancedSettingsOpen, setAdvancedSettingsOpen] = useState(false);
|
|
|
const formContainerRef = useRef(null);
|
|
const formContainerRef = useRef(null);
|
|
@@ -538,6 +542,35 @@ const EditChannelModal = (props) => {
|
|
|
handleInputChange('settings', settingsJson);
|
|
handleInputChange('settings', settingsJson);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ const applyClipboardConfig = (config) => {
|
|
|
|
|
+ if (!config) return;
|
|
|
|
|
+ setInputs((prev) => ({
|
|
|
|
|
+ ...prev,
|
|
|
|
|
+ key: config.key,
|
|
|
|
|
+ base_url: config.url,
|
|
|
|
|
+ }));
|
|
|
|
|
+ if (formApiRef.current) {
|
|
|
|
|
+ formApiRef.current.setValue('key', config.key);
|
|
|
|
|
+ formApiRef.current.setValue('base_url', config.url);
|
|
|
|
|
+ }
|
|
|
|
|
+ setClipboardConfig(null);
|
|
|
|
|
+ showSuccess(t('连接信息已填入'));
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const pasteFromClipboard = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const text = await navigator.clipboard.readText();
|
|
|
|
|
+ const parsed = parseChannelConnectionString(text);
|
|
|
|
|
+ if (parsed) {
|
|
|
|
|
+ applyClipboardConfig(parsed);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ showInfo(t('剪贴板中未检测到连接信息'));
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ showError(t('无法读取剪贴板'));
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
const isIonetLocked = isIonetChannel && isEdit;
|
|
const isIonetLocked = isIonetChannel && isEdit;
|
|
|
|
|
|
|
|
const handleInputChange = (name, value) => {
|
|
const handleInputChange = (name, value) => {
|
|
@@ -1269,6 +1302,13 @@ const EditChannelModal = (props) => {
|
|
|
loadChannel();
|
|
loadChannel();
|
|
|
} else {
|
|
} else {
|
|
|
formApiRef.current?.setValues(getInitValues());
|
|
formApiRef.current?.setValues(getInitValues());
|
|
|
|
|
+ // best-effort clipboard auto-detect for new channels
|
|
|
|
|
+ navigator.clipboard.readText().then((text) => {
|
|
|
|
|
+ const parsed = parseChannelConnectionString(text);
|
|
|
|
|
+ if (parsed) {
|
|
|
|
|
+ setClipboardConfig(parsed);
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(() => {});
|
|
|
}
|
|
}
|
|
|
fetchModelGroups();
|
|
fetchModelGroups();
|
|
|
// 重置手动输入模式状态
|
|
// 重置手动输入模式状态
|
|
@@ -1329,6 +1369,8 @@ const EditChannelModal = (props) => {
|
|
|
setInputs(getInitValues());
|
|
setInputs(getInitValues());
|
|
|
// 重置密钥显示状态
|
|
// 重置密钥显示状态
|
|
|
resetKeyDisplayState();
|
|
resetKeyDisplayState();
|
|
|
|
|
+ // 重置剪贴板检测状态
|
|
|
|
|
+ setClipboardConfig(null);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const handleVertexUploadChange = ({ fileList }) => {
|
|
const handleVertexUploadChange = ({ fileList }) => {
|
|
@@ -2077,14 +2119,27 @@ const EditChannelModal = (props) => {
|
|
|
<SideSheet
|
|
<SideSheet
|
|
|
placement={isEdit ? 'right' : 'left'}
|
|
placement={isEdit ? 'right' : 'left'}
|
|
|
title={
|
|
title={
|
|
|
- <Space>
|
|
|
|
|
- <Tag color='blue' shape='circle'>
|
|
|
|
|
- {isEdit ? t('编辑') : t('新建')}
|
|
|
|
|
- </Tag>
|
|
|
|
|
- <Title heading={4} className='m-0'>
|
|
|
|
|
- {isEdit ? t('更新渠道信息') : t('创建新的渠道')}
|
|
|
|
|
- </Title>
|
|
|
|
|
- </Space>
|
|
|
|
|
|
|
+ <div className='flex items-center justify-between w-full'>
|
|
|
|
|
+ <Space>
|
|
|
|
|
+ <Tag color='blue' shape='circle'>
|
|
|
|
|
+ {isEdit ? t('编辑') : t('新建')}
|
|
|
|
|
+ </Tag>
|
|
|
|
|
+ <Title heading={4} className='m-0'>
|
|
|
|
|
+ {isEdit ? t('更新渠道信息') : t('创建新的渠道')}
|
|
|
|
|
+ </Title>
|
|
|
|
|
+ </Space>
|
|
|
|
|
+ {!isEdit && (
|
|
|
|
|
+ <Button
|
|
|
|
|
+ size='small'
|
|
|
|
|
+ type='tertiary'
|
|
|
|
|
+ className='ec-dbcd0a3c01b55203 shrink-0'
|
|
|
|
|
+ icon={<IconBolt />}
|
|
|
|
|
+ onClick={pasteFromClipboard}
|
|
|
|
|
+ >
|
|
|
|
|
+ {t('从剪贴板粘贴配置')}
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
}
|
|
}
|
|
|
bodyStyle={{ padding: '0' }}
|
|
bodyStyle={{ padding: '0' }}
|
|
|
visible={props.visible}
|
|
visible={props.visible}
|
|
@@ -2446,6 +2501,34 @@ const EditChannelModal = (props) => {
|
|
|
<>
|
|
<>
|
|
|
<Spin spinning={loading}>
|
|
<Spin spinning={loading}>
|
|
|
<div className='p-2 space-y-3' ref={formContainerRef}>
|
|
<div className='p-2 space-y-3' ref={formContainerRef}>
|
|
|
|
|
+ {!isEdit && clipboardConfig && (
|
|
|
|
|
+ <Banner
|
|
|
|
|
+ type='info'
|
|
|
|
|
+ className='ec-dbcd0a3c01b55203'
|
|
|
|
|
+ description={
|
|
|
|
|
+ <div className='flex items-center justify-between gap-2'>
|
|
|
|
|
+ <span>{t('检测到剪贴板中的连接信息')}</span>
|
|
|
|
|
+ <div className='flex gap-1'>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ size='small'
|
|
|
|
|
+ theme='solid'
|
|
|
|
|
+ type='primary'
|
|
|
|
|
+ onClick={() => applyClipboardConfig(clipboardConfig)}
|
|
|
|
|
+ >
|
|
|
|
|
+ {t('自动填入')}
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ size='small'
|
|
|
|
|
+ type='tertiary'
|
|
|
|
|
+ onClick={() => setClipboardConfig(null)}
|
|
|
|
|
+ >
|
|
|
|
|
+ {t('忽略')}
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ }
|
|
|
|
|
+ />
|
|
|
|
|
+ )}
|
|
|
{/* Core Configuration Card - Always Visible */}
|
|
{/* Core Configuration Card - Always Visible */}
|
|
|
<Card className='!rounded-2xl shadow-sm border-0'>
|
|
<Card className='!rounded-2xl shadow-sm border-0'>
|
|
|
{/* Header */}
|
|
{/* Header */}
|