11import * 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' ;
55import { ChallengeFormData } from './types' ;
66
77// 导入钩子函数
@@ -27,7 +27,7 @@ import ResponsiveContainer from './components/ResponsiveContainer';
2727// 导入样式
2828import { 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 >
0 commit comments