Skip to content

Commit 7d85b31

Browse files
authored
Merge pull request #5 from JSREP/dev
优化图片预览和解决方案提示
2 parents 89b1f37 + 23397f4 commit 7d85b31

File tree

9 files changed

+513
-146
lines changed

9 files changed

+513
-146
lines changed

src/components/ChallengeContributePage/components/YamlImportSection.tsx

Lines changed: 64 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,52 @@ const YamlImportSection: React.FC<YamlImportSectionProps> = ({
117117
return;
118118
}
119119

120-
if (validateYaml(yamlText)) {
121-
onImportYaml(yamlText);
122-
message.success('粘贴的YAML导入成功');
123-
setIsModalVisible(false);
120+
setIsLoading(true);
121+
try {
122+
if (validateYaml(yamlText)) {
123+
onImportYaml(yamlText);
124+
message.success('粘贴的YAML导入成功');
125+
setIsModalVisible(false);
126+
}
127+
} finally {
128+
setIsLoading(false);
124129
}
125130
};
126131

132+
// 根据当前标签页渲染底部按钮
133+
const renderFooterButtons = () => {
134+
const cancelButton = (
135+
<Button key="cancel" onClick={handleCancel}>
136+
取消
137+
</Button>
138+
);
139+
140+
// 不同标签页的确认按钮
141+
const actionButton = activeTab === 'text' ? (
142+
<Button
143+
key="text-import"
144+
type="primary"
145+
onClick={handleTextImport}
146+
loading={isLoading}
147+
disabled={!yamlText.trim()}
148+
>
149+
粘贴导入
150+
</Button>
151+
) : (
152+
<Button
153+
key="import"
154+
type="primary"
155+
onClick={handleImport}
156+
loading={isLoading}
157+
disabled={activeTab === 'file'}
158+
>
159+
导入
160+
</Button>
161+
);
162+
163+
return [cancelButton, actionButton];
164+
};
165+
127166
// 选择当前活动的导入方式
128167
const handleImport = () => {
129168
switch (activeTab) {
@@ -156,22 +195,7 @@ const YamlImportSection: React.FC<YamlImportSectionProps> = ({
156195
title="导入YAML"
157196
open={isModalVisible}
158197
onCancel={handleCancel}
159-
footer={[
160-
<Button key="cancel" onClick={handleCancel}>
161-
取消
162-
</Button>,
163-
activeTab !== 'text' ? (
164-
<Button
165-
key="import"
166-
type="primary"
167-
onClick={handleImport}
168-
loading={isLoading}
169-
disabled={activeTab === 'file'}
170-
>
171-
导入
172-
</Button>
173-
) : null
174-
].filter(Boolean)}
198+
footer={renderFooterButtons()}
175199
width={600}
176200
>
177201
<Tabs activeKey={activeTab} onChange={setActiveTab}>
@@ -196,9 +220,14 @@ const YamlImportSection: React.FC<YamlImportSectionProps> = ({
196220
</p>
197221
<p className="ant-upload-text">点击或拖拽文件到此区域上传</p>
198222
<p className="ant-upload-hint">
199-
支持 .yml 或 .yaml 格式文件,包括单个挑战或包含多个挑战的集合文件(将导入第一个挑战)
223+
支持 .yml 或 .yaml 格式文件
200224
</p>
201225
</Upload.Dragger>
226+
<div style={{ display: 'flex', alignItems: 'center', marginTop: 16 }}>
227+
<p style={{ color: '#999', margin: 0, flex: 1 }}>
228+
点击或拖拽YAML文件到上方区域。支持单个挑战或包含多个挑战的集合文件(将导入第一个挑战)。
229+
</p>
230+
</div>
202231
</div>
203232
</TabPane>
204233

@@ -220,9 +249,9 @@ const YamlImportSection: React.FC<YamlImportSectionProps> = ({
220249
prefix={<LinkOutlined />}
221250
allowClear
222251
/>
223-
<div>
224-
<p style={{ color: '#999', marginTop: 8 }}>
225-
输入包含YAML内容的文件URL,点击导入按钮获取并解析内容
252+
<div style={{ display: 'flex', alignItems: 'center', marginTop: 8 }}>
253+
<p style={{ color: '#999', margin: 0, flex: 1 }}>
254+
输入包含YAML内容的文件URL,点击底部的【导入】按钮获取并解析内容
226255
支持单个挑战或包含多个挑战的集合文件(将导入第一个挑战)。
227256
</p>
228257
</div>
@@ -245,23 +274,23 @@ const YamlImportSection: React.FC<YamlImportSectionProps> = ({
245274
placeholder="粘贴YAML内容到此处"
246275
value={yamlText}
247276
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setYamlText(e.target.value)}
248-
autoSize={{ minRows: 6, maxRows: 12 }}
277+
autoSize={{ minRows: 8, maxRows: 16 }}
278+
style={{
279+
resize: 'none',
280+
backgroundColor: '#fafafa',
281+
border: '1px dashed #d9d9d9',
282+
borderRadius: '4px',
283+
padding: '12px'
284+
}}
249285
onPaste={(e: React.ClipboardEvent<HTMLTextAreaElement>) => {
250286
console.log('粘贴事件触发');
251287
}}
252288
/>
253-
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
254-
<p style={{ color: '#999', margin: '8px 0 0 0' }}>
255-
将YAML内容复制粘贴到文本框中,点击导入按钮解析内容
289+
<div style={{ display: 'flex', alignItems: 'center', marginTop: 16 }}>
290+
<p style={{ color: '#999', margin: 0, flex: 1 }}>
291+
将YAML内容复制粘贴到文本框中,点击底部的【粘贴导入】按钮解析内容
256292
支持单个挑战或包含多个挑战的集合文件(将导入第一个挑战)。
257293
</p>
258-
<Button
259-
type="primary"
260-
onClick={handleTextImport}
261-
disabled={!yamlText.trim()}
262-
>
263-
粘贴导入
264-
</Button>
265294
</div>
266295
</Space>
267296
</div>

src/components/ChallengeContributePage/index.tsx

Lines changed: 74 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ const ChallengeContributePage: React.FC = () => {
127127
const values = form.getFieldsValue(true);
128128
console.log('当前表单值:', values);
129129

130+
// 更新update-time为当前时间
131+
const currentDateTime = new Date().toISOString().replace('T', ' ').substring(0, 19);
132+
130133
// 检查是否有原始YAML
131134
if (!values.rawYaml) {
132135
console.log('没有原始YAML,使用默认格式生成');
@@ -142,12 +145,15 @@ const ChallengeContributePage: React.FC = () => {
142145
'base64-url': values.base64Url,
143146
'is-expired': values.isExpired === undefined ? false : values.isExpired,
144147
'tags': values.tags || [],
145-
'solutions': (values.solutions || [])?.filter(s => s.title && s.url).map(s => ({
148+
'solutions': (values.solutions || [])?.filter((s: any) => s.title && s.url).map((s: any) => ({
146149
title: s.title,
147150
url: s.url,
148151
...(s.source ? {source: s.source} : {}),
149152
...(s.author ? {author: s.author} : {})
150-
}))
153+
})),
154+
// 添加或更新时间字段
155+
'create-time': values.createTime || currentDateTime,
156+
'update-time': currentDateTime
151157
};
152158

153159
const yamlString = YAML.stringify(yamlObj, {
@@ -180,7 +186,10 @@ const ChallengeContributePage: React.FC = () => {
180186
url: s.url,
181187
...(s.source ? {source: s.source} : {}),
182188
...(s.author ? {author: s.author} : {})
183-
}))
189+
})),
190+
// 更新时间字段
191+
'create-time': values.createTime || currentDateTime,
192+
'update-time': currentDateTime
184193
};
185194

186195
// 分析原始YAML文件结构,但保留完整内容
@@ -515,86 +524,75 @@ const ChallengeContributePage: React.FC = () => {
515524
// 解析YAML函数
516525
const parseYaml = (yamlContent: string): ChallengeFormData | null => {
517526
try {
518-
// 解析YAML字符串
519-
const yamlData = YAML.parse(yamlContent);
527+
// 保存原始YAML内容
528+
const rawYaml = yamlContent;
520529

521-
if (!yamlData) {
522-
console.error('YAML解析结果为空');
523-
return null;
524-
}
525-
526-
console.log('原始YAML数据结构:', yamlData);
527-
528-
// 检查是否是集合格式的YAML
529-
let challengeData;
530-
let originalYaml = yamlContent; // 默认保存完整原始YAML
531-
532-
if (yamlData.challenges && Array.isArray(yamlData.challenges) && yamlData.challenges.length > 0) {
533-
// 从集合中提取第一个挑战
534-
console.log('从集合中提取挑战数据:', yamlData.challenges[0]);
535-
challengeData = yamlData.challenges[0];
536-
537-
// 尝试获取仅包含这个挑战的YAML部分,但仍然保留原始集合格式
538-
try {
539-
// 为了保留挑战集合的结构和注释,我们保留整个YAML
540-
originalYaml = yamlContent;
541-
} catch (e) {
542-
console.error('提取单个挑战的YAML失败:', e);
543-
// 继续使用完整的原始YAML
530+
// 尝试解析YAML内容
531+
const yamlData = YAML.parse(yamlContent);
532+
console.log('解析的YAML数据:', yamlData);
533+
534+
// 检查是否为挑战集合
535+
if (yamlData && typeof yamlData === 'object' && 'challenges' in yamlData && Array.isArray(yamlData.challenges)) {
536+
console.log('检测到挑战集合,提取第一个挑战');
537+
// 提取第一个挑战
538+
if (yamlData.challenges.length === 0) {
539+
throw new Error('挑战集合为空');
544540
}
545-
} else if (yamlData.id !== undefined) {
546-
// 单个挑战格式
547-
challengeData = yamlData;
548-
} else {
549-
console.error('无法识别的YAML格式,没有找到challenges数组或id字段');
550-
return null;
541+
542+
const firstChallenge = yamlData.challenges[0];
543+
// 递归处理
544+
return parseYaml(YAML.stringify(firstChallenge));
551545
}
552546

553-
// 处理base64-url字段
554-
let base64Url = challengeData['base64-url'] || '';
555-
console.log('提取到的base64-url:', base64Url);
556-
557-
// 打印关键字段检查
558-
console.log('挑战数据关键字段:', {
559-
id: challengeData.id,
560-
name: challengeData.name,
561-
platform: challengeData.platform,
562-
'id-alias': challengeData['id-alias'],
563-
tags: challengeData.tags,
564-
'difficulty-level': challengeData['difficulty-level'],
565-
'description-markdown': challengeData['description-markdown']?.substring(0, 100),
566-
'base64-url': challengeData['base64-url'],
567-
solutions: challengeData.solutions
568-
});
547+
// 检查是否是单个挑战
548+
if (!yamlData || typeof yamlData !== 'object') {
549+
throw new Error('YAML格式错误,期望得到一个对象');
550+
}
551+
552+
// 将YAML对象转换为表单数据
553+
const challengeData = yamlData as any;
569554

570-
// 创建表单数据
555+
// 开始构建表单数据
571556
const formData: ChallengeFormData = {
572-
id: challengeData.id !== undefined ? Number(challengeData.id) : null,
557+
// 保留原始的YAML内容
558+
rawYaml: rawYaml,
559+
560+
// 基本信息
561+
id: challengeData.id || null,
573562
idAlias: challengeData['id-alias'] || '',
574563
platform: challengeData.platform || 'Web',
575564
name: challengeData.name || '',
576565
nameEn: challengeData.name_en || '',
577-
difficultyLevel: Number(challengeData['difficulty-level']) || 1,
578-
// 处理描述字段,兼容多种格式
579-
description: challengeData['description-markdown'] || challengeData.description || '',
580-
descriptionEn: challengeData['description-markdown_en'] || challengeData.descriptionEn || '',
581-
descriptionMarkdown: challengeData['description-markdown'] || challengeData.description || '',
582-
descriptionMarkdownEn: challengeData['description-markdown_en'] || challengeData.descriptionEn || '',
583-
// 处理base64Url字段,确保正确映射
566+
567+
// 描述信息
568+
description: challengeData['description-markdown'] || '',
569+
descriptionMarkdown: challengeData['description-markdown'] || '',
570+
descriptionEn: challengeData['description-markdown_en'] || '',
571+
descriptionMarkdownEn: challengeData['description-markdown_en'] || '',
572+
573+
// 难度级别
574+
difficultyLevel: challengeData['difficulty-level'] || 1,
575+
576+
// URL处理
584577
base64Url: challengeData['base64-url'] || '',
578+
585579
// 处理过期标志
586580
isExpired: challengeData['is-expired'] === true || false,
581+
582+
// 标签处理
587583
tags: challengeData.tags || [],
584+
585+
// 解决方案处理
588586
solutions: (challengeData.solutions || []).map((solution: any) => ({
589587
title: solution.title || '',
590588
url: solution.url || '',
591589
source: solution.source || '',
592590
author: solution.author || ''
593591
})),
594-
example: '',
595-
testCases: [],
596-
comments: [],
597-
rawYaml: originalYaml
592+
593+
// 时间字段处理
594+
createTime: challengeData['create-time'] || '',
595+
updateTime: challengeData['update-time'] || ''
598596
};
599597

600598
console.log('转换后的表单数据:', formData);
@@ -627,6 +625,19 @@ const ChallengeContributePage: React.FC = () => {
627625
formValues.id = calculateNextId();
628626
}
629627

628+
// 更新时间字段为当前时间
629+
const currentDateTime = new Date().toISOString().replace('T', ' ').substring(0, 19);
630+
formValues.updateTime = currentDateTime;
631+
632+
// 如果原始YAML存在,也需要更新其中的update-time字段
633+
if (formValues.rawYaml) {
634+
// 使用正则表达式更新update-time字段
635+
formValues.rawYaml = formValues.rawYaml.replace(
636+
/update-time:.*$/m,
637+
`update-time: ${currentDateTime}`
638+
);
639+
}
640+
630641
console.log('正在设置表单值:', formValues);
631642
console.log('原始YAML是否已保存:', !!formValues.rawYaml);
632643

src/components/ChallengeContributePage/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ export interface ChallengeFormData {
5252
comments?: string[];
5353
// 原始YAML文本(用于保留注释)
5454
rawYaml?: string;
55+
// 创建时间
56+
createTime?: string;
57+
// 更新时间
58+
updateTime?: string;
5559
}
5660

5761
export interface ChallengeData {

0 commit comments

Comments
 (0)