feat: jump between section on channel edit page

This commit is contained in:
JoeyLearnsToCode 2025-09-19 18:09:26 +08:00
parent d77aa81f4f
commit a23955a025

View File

@ -66,6 +66,8 @@ import {
IconCode, IconCode,
IconGlobe, IconGlobe,
IconBolt, IconBolt,
IconChevronUp,
IconChevronDown,
} from '@douyinfe/semi-icons'; } from '@douyinfe/semi-icons';
const { Text, Title } = Typography; const { Text, Title } = Typography;
@ -184,6 +186,18 @@ const EditChannelModal = (props) => {
const [verifyCode, setVerifyCode] = useState(''); const [verifyCode, setVerifyCode] = useState('');
const [verifyLoading, setVerifyLoading] = useState(false); const [verifyLoading, setVerifyLoading] = useState(false);
//
const formSectionRefs = useRef({
basicInfo: null,
apiConfig: null,
modelConfig: null,
advancedSettings: null,
channelExtraSettings: null,
});
const [currentSectionIndex, setCurrentSectionIndex] = useState(0);
const formSections = ['basicInfo', 'apiConfig', 'modelConfig', 'advancedSettings', 'channelExtraSettings'];
const formContainerRef = useRef(null);
// 2FA // 2FA
const updateTwoFAState = (updates) => { const updateTwoFAState = (updates) => {
setTwoFAState((prev) => ({ ...prev, ...updates })); setTwoFAState((prev) => ({ ...prev, ...updates }));
@ -207,6 +221,37 @@ const EditChannelModal = (props) => {
setVerifyLoading(false); setVerifyLoading(false);
}; };
//
const scrollToSection = (sectionKey) => {
const sectionElement = formSectionRefs.current[sectionKey];
if (sectionElement) {
sectionElement.scrollIntoView({
behavior: 'smooth',
block: 'start',
inline: 'nearest'
});
}
};
const navigateToSection = (direction) => {
const availableSections = formSections.filter(section => {
if (section === 'apiConfig') {
return showApiConfigCard;
}
return true;
});
let newIndex;
if (direction === 'up') {
newIndex = currentSectionIndex > 0 ? currentSectionIndex - 1 : availableSections.length - 1;
} else {
newIndex = currentSectionIndex < availableSections.length - 1 ? currentSectionIndex + 1 : 0;
}
setCurrentSectionIndex(newIndex);
scrollToSection(availableSections[newIndex]);
};
// //
const [channelSettings, setChannelSettings] = useState({ const [channelSettings, setChannelSettings] = useState({
force_format: false, force_format: false,
@ -672,6 +717,8 @@ const EditChannelModal = (props) => {
fetchModelGroups(); fetchModelGroups();
// //
setUseManualInput(false); setUseManualInput(false);
//
setCurrentSectionIndex(0);
} else { } else {
// //
resetModalState(); resetModalState();
@ -1108,7 +1155,41 @@ const EditChannelModal = (props) => {
visible={props.visible} visible={props.visible}
width={isMobile ? '100%' : 600} width={isMobile ? '100%' : 600}
footer={ footer={
<div className='flex justify-end bg-white'> <div className='flex justify-between items-center bg-white'>
<div className='flex gap-2'>
<Button
size='small'
type='tertiary'
icon={<IconChevronUp />}
onClick={() => navigateToSection('up')}
style={{
borderRadius: '50%',
width: '32px',
height: '32px',
padding: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
title={t('上一个表单块')}
/>
<Button
size='small'
type='tertiary'
icon={<IconChevronDown />}
onClick={() => navigateToSection('down')}
style={{
borderRadius: '50%',
width: '32px',
height: '32px',
padding: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
title={t('下一个表单块')}
/>
</div>
<Space> <Space>
<Button <Button
theme='solid' theme='solid'
@ -1139,10 +1220,14 @@ const EditChannelModal = (props) => {
> >
{() => ( {() => (
<Spin spinning={loading}> <Spin spinning={loading}>
<div className='p-2'> <div
<Card className='!rounded-2xl shadow-sm border-0 mb-6'> className='p-2'
{/* Header: Basic Info */} ref={formContainerRef}
<div className='flex items-center mb-2'> >
<div ref={el => formSectionRefs.current.basicInfo = el}>
<Card className='!rounded-2xl shadow-sm border-0 mb-6'>
{/* Header: Basic Info */}
<div className='flex items-center mb-2'>
<Avatar <Avatar
size='small' size='small'
color='blue' color='blue'
@ -1596,13 +1681,15 @@ const EditChannelModal = (props) => {
} }
/> />
)} )}
</Card> </Card>
</div>
{/* API Configuration Card */} {/* API Configuration Card */}
{showApiConfigCard && ( {showApiConfigCard && (
<Card className='!rounded-2xl shadow-sm border-0 mb-6'> <div ref={el => formSectionRefs.current.apiConfig = el}>
{/* Header: API Config */} <Card className='!rounded-2xl shadow-sm border-0 mb-6'>
<div className='flex items-center mb-2'> {/* Header: API Config */}
<div className='flex items-center mb-2'>
<Avatar <Avatar
size='small' size='small'
color='green' color='green'
@ -1789,13 +1876,15 @@ const EditChannelModal = (props) => {
/> />
</div> </div>
)} )}
</Card> </Card>
</div>
)} )}
{/* Model Configuration Card */} {/* Model Configuration Card */}
<Card className='!rounded-2xl shadow-sm border-0 mb-6'> <div ref={el => formSectionRefs.current.modelConfig = el}>
{/* Header: Model Config */} <Card className='!rounded-2xl shadow-sm border-0 mb-6'>
<div className='flex items-center mb-2'> {/* Header: Model Config */}
<div className='flex items-center mb-2'>
<Avatar <Avatar
size='small' size='small'
color='purple' color='purple'
@ -1988,12 +2077,14 @@ const EditChannelModal = (props) => {
formApi={formApiRef.current} formApi={formApiRef.current}
extraText={t('键为请求中的模型名称,值为要替换的模型名称')} extraText={t('键为请求中的模型名称,值为要替换的模型名称')}
/> />
</Card> </Card>
</div>
{/* Advanced Settings Card */} {/* Advanced Settings Card */}
<Card className='!rounded-2xl shadow-sm border-0 mb-6'> <div ref={el => formSectionRefs.current.advancedSettings = el}>
{/* Header: Advanced Settings */} <Card className='!rounded-2xl shadow-sm border-0 mb-6'>
<div className='flex items-center mb-2'> {/* Header: Advanced Settings */}
<div className='flex items-center mb-2'>
<Avatar <Avatar
size='small' size='small'
color='orange' color='orange'
@ -2206,12 +2297,14 @@ const EditChannelModal = (props) => {
'键为原状态码,值为要复写的状态码,仅影响本地判断', '键为原状态码,值为要复写的状态码,仅影响本地判断',
)} )}
/> />
</Card> </Card>
</div>
{/* Channel Extra Settings Card */} {/* Channel Extra Settings Card */}
<Card className='!rounded-2xl shadow-sm border-0 mb-6'> <div ref={el => formSectionRefs.current.channelExtraSettings = el}>
{/* Header: Channel Extra Settings */} <Card className='!rounded-2xl shadow-sm border-0 mb-6'>
<div className='flex items-center mb-2'> {/* Header: Channel Extra Settings */}
<div className='flex items-center mb-2'>
<Avatar <Avatar
size='small' size='small'
color='violet' color='violet'
@ -2309,7 +2402,8 @@ const EditChannelModal = (props) => {
'如果用户请求中包含系统提示词,则使用此设置拼接到用户的系统提示词前面', '如果用户请求中包含系统提示词,则使用此设置拼接到用户的系统提示词前面',
)} )}
/> />
</Card> </Card>
</div>
</div> </div>
</Spin> </Spin>
)} )}