Skip to content

Commit 71c603f

Browse files
committed
将ChallengeContributePage从步骤式表单改回单页面布局,优化UI界面
1 parent a409cdb commit 71c603f

File tree

2 files changed

+125
-172
lines changed

2 files changed

+125
-172
lines changed

src/components/ChallengeContributePage/index.tsx

Lines changed: 81 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
2-
import { useCallback, useEffect, useMemo, useState } from 'react';
3-
import { Form, Steps, Button, Card, Space, Affix, message, Progress, Badge, notification } from 'antd';
4-
import { SaveOutlined, ArrowLeftOutlined, ArrowRightOutlined, CheckOutlined, InfoCircleOutlined } from '@ant-design/icons';
2+
import { useCallback, useEffect, useState } from 'react';
3+
import { Form, Button, Card, Space, Affix, message, Progress, Badge, notification, Divider, Typography } from 'antd';
4+
import { SaveOutlined, FileTextOutlined, InfoCircleOutlined } from '@ant-design/icons';
55
import { ChallengeFormData } from './types';
66

77
// 导入钩子函数
@@ -27,7 +27,7 @@ import ResponsiveContainer from './components/ResponsiveContainer';
2727
// 导入样式
2828
import { styles } from './styles';
2929

30-
const { Step } = Steps;
30+
const { Title, Text } = Typography;
3131

3232
/**
3333
* 备份历史模态框组件
@@ -115,8 +115,7 @@ const ChallengeContributePage: React.FC = () => {
115115
// 表单实例
116116
const [form] = Form.useForm<ChallengeFormData>();
117117

118-
// 步骤状态
119-
const [currentStep, setCurrentStep] = useState<number>(0);
118+
// 状态
120119
const [isBackupModalVisible, setIsBackupModalVisible] = useState<boolean>(false);
121120
const [formCompletion, setFormCompletion] = useState<number>(0);
122121
const [autoSaveVisible, setAutoSaveVisible] = useState<boolean>(false);
@@ -285,117 +284,10 @@ const ChallengeContributePage: React.FC = () => {
285284
};
286285
}, [isFormDirty]);
287286

288-
// 步骤定义
289-
const steps = [
290-
{
291-
title: '基本信息',
292-
content: (
293-
<>
294-
<div style={styles.stepTitle}>步骤 1:填写基本信息</div>
295-
<div style={styles.stepDescription}>
296-
请填写挑战的基本信息,包括ID、平台类型、名称等必要信息。这些信息将用于在列表页展示和搜索。
297-
</div>
298-
<BasicInfo form={form} />
299-
<DifficultySelector form={form} />
300-
</>
301-
),
302-
validationFields: ['id', 'platform', 'name', 'difficultyLevel']
303-
},
304-
{
305-
title: '详细描述',
306-
content: (
307-
<>
308-
<div style={styles.stepTitle}>步骤 2:填写详细描述</div>
309-
<div style={styles.stepDescription}>
310-
请提供挑战的详细描述和目标网站URL(将自动转为Base64编码)。描述应尽可能详细,包括挑战要求和技术背景。
311-
</div>
312-
<DescriptionFields form={form} />
313-
<UrlInput form={form} />
314-
</>
315-
),
316-
validationFields: ['description', 'base64Url']
317-
},
318-
{
319-
title: '标签与解决方案',
320-
content: (
321-
<>
322-
<div style={styles.stepTitle}>步骤 3:添加标签和解决方案</div>
323-
<div style={styles.stepDescription}>
324-
添加相关技术标签和解决方案链接,帮助其他用户快速识别和解决挑战。好的标签和解决方案资源能显著提高挑战的价值。
325-
</div>
326-
<TagsSelector
327-
form={form}
328-
onChange={handleTagsChange}
329-
/>
330-
<SolutionsSection
331-
form={form}
332-
onChange={handleSolutionsChange}
333-
/>
334-
</>
335-
),
336-
validationFields: ['tags']
337-
},
338-
{
339-
title: 'YAML预览',
340-
content: (
341-
<>
342-
<div style={styles.stepTitle}>步骤 4:生成和检查YAML</div>
343-
<div style={styles.stepDescription}>
344-
检查自动生成的YAML内容,确保所有信息正确。您可以复制YAML用于提交挑战。如需修改信息,可以返回前面的步骤进行编辑。
345-
</div>
346-
<YamlPreviewSection
347-
yamlOutput={yamlOutput}
348-
onGenerateYaml={generateYaml}
349-
onCopyYaml={handleCopyYaml}
350-
/>
351-
</>
352-
),
353-
validationFields: []
354-
}
355-
];
356-
357-
// 处理步骤变更前的验证
358-
const handleStepChange = async (step: number) => {
359-
// 如果是向后移动,验证当前步骤的字段
360-
if (step > currentStep) {
361-
try {
362-
// 获取当前步骤所需验证的字段
363-
const fieldsToValidate = steps[currentStep].validationFields;
364-
if (fieldsToValidate.length > 0) {
365-
await form.validateFields(fieldsToValidate);
366-
}
367-
// 验证通过,可以移动到下一步
368-
setCurrentStep(step);
369-
// 如果移动到最后一步,自动生成YAML
370-
if (step === steps.length - 1) {
371-
setTimeout(() => {
372-
generateYaml();
373-
}, 300);
374-
}
375-
} catch (error) {
376-
// 验证失败,显示错误消息
377-
message.error('请填写所有必填字段后再继续');
378-
}
379-
} else {
380-
// 向前移动不需要验证
381-
setCurrentStep(step);
382-
}
383-
};
384-
385-
// 前进到下一步
386-
const goNext = () => {
387-
handleStepChange(currentStep + 1);
388-
};
389-
390-
// 返回上一步
391-
const goPrevious = () => {
392-
handleStepChange(currentStep - 1);
393-
};
394-
395287
return (
396288
<ResponsiveContainer>
397289
{/* 进度指示器 */}
398-
<div style={{ marginBottom: 16 }}>
290+
<div style={styles.progressContainer}>
399291
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
400292
<span>表单完成度: {formCompletion}%</span>
401293
<Badge
@@ -424,15 +316,6 @@ const ChallengeContributePage: React.FC = () => {
424316
onShowBackups={showBackupHistory}
425317
/>
426318

427-
{/* 步骤导航 */}
428-
<Card style={{ marginBottom: 20, ...styles.stepCard }}>
429-
<Steps current={currentStep} onChange={handleStepChange} responsive={true} style={styles.stepsNav}>
430-
{steps.map(step => (
431-
<Step key={step.title} title={step.title} />
432-
))}
433-
</Steps>
434-
</Card>
435-
436319
{/* 表单内容 */}
437320
<Form
438321
form={form}
@@ -446,12 +329,74 @@ const ChallengeContributePage: React.FC = () => {
446329
<input type="hidden" />
447330
</Form.Item>
448331

449-
{/* 当前步骤内容 */}
450-
<Card style={styles.stepCard}>
451-
{steps[currentStep].content}
452-
</Card>
332+
<div style={styles.formSection}>
333+
{/* 基本信息部分 */}
334+
<Card style={styles.stepCard} title={<Title level={4}>基本信息</Title>}>
335+
<div style={styles.formSectionContent}>
336+
<Text type="secondary" style={{ display: 'block', marginBottom: 16 }}>
337+
请填写挑战的基本信息,包括ID、平台类型、名称等必要信息。这些信息将用于在列表页展示和搜索。
338+
</Text>
339+
<BasicInfo form={form} />
340+
<DifficultySelector form={form} />
341+
</div>
342+
</Card>
343+
</div>
344+
345+
<Divider style={styles.divider} />
346+
347+
<div style={styles.formSection}>
348+
{/* 详细描述部分 */}
349+
<Card style={styles.stepCard} title={<Title level={4}>详细描述</Title>}>
350+
<div style={styles.formSectionContent}>
351+
<Text type="secondary" style={{ display: 'block', marginBottom: 16 }}>
352+
请提供挑战的详细描述和目标网站URL(将自动转为Base64编码)。描述应尽可能详细,包括挑战要求和技术背景。
353+
</Text>
354+
<DescriptionFields form={form} />
355+
<UrlInput form={form} />
356+
</div>
357+
</Card>
358+
</div>
359+
360+
<Divider style={styles.divider} />
361+
362+
<div style={styles.formSection}>
363+
{/* 标签与解决方案部分 */}
364+
<Card style={styles.stepCard} title={<Title level={4}>标签与解决方案</Title>}>
365+
<div style={styles.formSectionContent}>
366+
<Text type="secondary" style={{ display: 'block', marginBottom: 16 }}>
367+
添加相关技术标签和解决方案链接,帮助其他用户快速识别和解决挑战。好的标签和解决方案资源能显著提高挑战的价值。
368+
</Text>
369+
<TagsSelector
370+
form={form}
371+
onChange={handleTagsChange}
372+
/>
373+
<SolutionsSection
374+
form={form}
375+
onChange={handleSolutionsChange}
376+
/>
377+
</div>
378+
</Card>
379+
</div>
380+
381+
<Divider style={styles.divider} />
382+
383+
<div style={styles.formBottom}>
384+
{/* YAML预览部分 */}
385+
<Card style={styles.stepCard} title={<Title level={4}>YAML生成预览</Title>}>
386+
<div style={styles.formSectionContent}>
387+
<Text type="secondary" style={{ display: 'block', marginBottom: 16 }}>
388+
检查自动生成的YAML内容,确保所有信息正确。您可以复制YAML用于提交挑战。
389+
</Text>
390+
<YamlPreviewSection
391+
yamlOutput={yamlOutput}
392+
onGenerateYaml={generateYaml}
393+
onCopyYaml={handleCopyYaml}
394+
/>
395+
</div>
396+
</Card>
397+
</div>
453398

454-
{/* 步骤操作按钮 */}
399+
{/* 底部固定操作按钮 */}
455400
<Affix offsetBottom={20}>
456401
<Card style={styles.footerButtons}>
457402
<Space>
@@ -460,40 +405,17 @@ const ChallengeContributePage: React.FC = () => {
460405
onClick={handleManualSave}
461406
loading={isSaving}
462407
>
463-
保存
408+
保存表单
464409
</Button>
465410
</Space>
466411

467-
<Space>
468-
{currentStep > 0 && (
469-
<Button
470-
icon={<ArrowLeftOutlined />}
471-
onClick={goPrevious}
472-
>
473-
上一步
474-
</Button>
475-
)}
476-
477-
{currentStep < steps.length - 1 && (
478-
<Button
479-
type="primary"
480-
onClick={goNext}
481-
icon={<ArrowRightOutlined />}
482-
>
483-
下一步
484-
</Button>
485-
)}
486-
487-
{currentStep === steps.length - 1 && (
488-
<Button
489-
type="primary"
490-
onClick={generateYaml}
491-
icon={<CheckOutlined />}
492-
>
493-
生成YAML
494-
</Button>
495-
)}
496-
</Space>
412+
<Button
413+
type="primary"
414+
onClick={generateYaml}
415+
icon={<FileTextOutlined />}
416+
>
417+
生成YAML
418+
</Button>
497419
</Card>
498420
</Affix>
499421
</Form>

src/components/ChallengeContributePage/styles.ts

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,25 @@ export const styles: Record<string, CSSProperties> = {
5050
color: '#666',
5151
marginBottom: 24
5252
},
53-
// 步骤卡片
53+
// 卡片样式
5454
stepCard: {
55-
marginBottom: 20,
55+
marginBottom: 24,
5656
boxShadow: '0 1px 5px rgba(0,0,0,0.05)',
5757
borderRadius: 8
5858
},
59-
// 步骤导航
60-
stepsNav: {
61-
marginBottom: 24
59+
// 卡片标题
60+
cardTitle: {
61+
display: 'flex',
62+
alignItems: 'center',
63+
gap: 8,
64+
marginBottom: 16
65+
},
66+
// 表单分组标题
67+
sectionTitle: {
68+
fontSize: 16,
69+
fontWeight: 500,
70+
marginBottom: 16,
71+
color: '#1890ff'
6272
},
6373
// 底部固定按钮区
6474
footerButtons: {
@@ -67,19 +77,15 @@ export const styles: Record<string, CSSProperties> = {
6777
display: 'flex',
6878
justifyContent: 'space-between',
6979
backgroundColor: '#fff',
70-
borderRadius: '0 0 8px 8px'
80+
borderRadius: '0 0 8px 8px',
81+
width: '100%',
82+
maxWidth: 1000,
83+
margin: '0 auto'
7184
},
7285
// 响应式设计 - 移动端适配
7386
mobileContainer: {
7487
padding: '16px 12px'
7588
},
76-
// 表单分组标题
77-
sectionTitle: {
78-
fontSize: 16,
79-
fontWeight: 500,
80-
marginBottom: 16,
81-
color: '#1890ff'
82-
},
8389
// YAML预览区样式
8490
yamlPreview: {
8591
fontFamily: 'monospace',
@@ -96,5 +102,30 @@ export const styles: Record<string, CSSProperties> = {
96102
highlight: {
97103
color: '#1890ff',
98104
fontWeight: 500
105+
},
106+
// 分隔线样式
107+
divider: {
108+
margin: '32px 0'
109+
},
110+
// 表单区块容器
111+
formSection: {
112+
marginBottom: 40
113+
},
114+
// 表单区块内部内容
115+
formSectionContent: {
116+
padding: '0 16px'
117+
},
118+
// 表单底部区域
119+
formBottom: {
120+
marginTop: 40,
121+
marginBottom: 80 // 给底部固定按钮留空间
122+
},
123+
// 进度指示器容器
124+
progressContainer: {
125+
marginBottom: 24,
126+
padding: '12px 16px',
127+
backgroundColor: '#f9f9f9',
128+
borderRadius: '8px',
129+
boxShadow: '0 1px 2px rgba(0,0,0,0.03)'
99130
}
100131
};

0 commit comments

Comments
 (0)