Skip to content

Commit c8cc9ba

Browse files
authored
Merge pull request #10 from JSREP/dev
feat(challenge-contribute): 恢复和优化挑战贡献页面组件
2 parents 70d34a8 + 0900fca commit c8cc9ba

File tree

14 files changed

+223
-89
lines changed

14 files changed

+223
-89
lines changed

docs/challenges/jsjiami JS最牛加密-V7.yml

Lines changed: 12 additions & 0 deletions
Large diffs are not rendered by default.

docs/challenges/meta.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ challenges:
1818
- jsvmp
1919

2020
# 挑战目标网站类型(枚举值,必填)
21-
# 允许值: Web / Android / iOS
21+
# 允许值: Web / Android / iOS / WeChat-MiniProgram / Electron / Windows-Native / Mac-Native / Linux-Native
2222
platform: Web
2323

2424
# 挑战名称(必填)
@@ -101,4 +101,4 @@ challenges:
101101

102102
# 是否忽略该挑战
103103
# 设置为true时,该挑战不会在列表中显示,并且编译构建时也会忽略不会被打包
104-
ignored: true
104+
ignored: false

docs/challenges/sojson加密结果逆向.yml

Lines changed: 16 additions & 0 deletions
Large diffs are not rendered by default.

docs/challenges/微店登录参数分析.yml

Lines changed: 15 additions & 0 deletions
Large diffs are not rendered by default.

docs/challenges/网易易盾.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,8 @@ challenges:
4141
特点:多种验证方式结合,设备指纹识别与行为分析相结合。
4242
4343
破解难点:需要绕过多层验证机制,处理动态变化的验证逻辑。
44-
45-
# 挑战目标网站URL的base64编码
46-
base64-url: aHR0cHM6Ly9kLnlpZHVuLmNvbS8=
44+
45+
base64-url: aHR0cHM6Ly9kdW4uMTYzLmNvbS8=
4746

4847
# 链接有效性状态(布尔值)
4948
# 标记挑战链接是否失效,true表示已失效

src/components/ChallengeListPage/ChallengeControls.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,16 @@ import StarRating from '../StarRating';
66
import { useMediaQuery } from 'react-responsive';
77

88
// 定义平台枚举值
9-
const PLATFORM_TYPES = ['Web', 'Android', 'iOS'];
9+
const PLATFORM_TYPES = [
10+
'Web',
11+
'Android',
12+
'iOS',
13+
'WeChat-MiniProgram',
14+
'Electron',
15+
'Windows-Native',
16+
'Mac-Native',
17+
'Linux-Native'
18+
];
1019

1120
interface ChallengeControlsProps {
1221
/**
@@ -147,7 +156,8 @@ const ChallengeControls: React.FC<ChallengeControlsProps> = ({
147156
const platformMenu = (
148157
<Menu
149158
selectedKeys={[selectedPlatform]}
150-
onClick={({ key }) => onPlatformChange(key)}
159+
onClick={({ key }) => onPlatformChange(key.toString())}
160+
multiple={false}
151161
>
152162
<Menu.Item key="all">{t('challenges.filters.allPlatforms')}</Menu.Item>
153163
{/* 使用固定的平台枚举列表,而不是从挑战中提取的 */}

src/components/ChallengeListPage/ChallengeFilters.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ const ChallengeFilters: React.FC<ChallengeFiltersProps> = ({
124124
margin: isMobile ? '0 4px 4px 0' : '0 8px 8px 0'
125125
}}
126126
>
127-
{isMobile ? selectedPlatform : `${t('challenge.detail.targetWebsite')}: ${selectedPlatform}`}
127+
{isMobile ? selectedPlatform : `${t('challenge.detail.platform')}: ${selectedPlatform}`}
128128
</Tag>
129129
)}
130130

src/components/ChallengeListPage/index.tsx

Lines changed: 86 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ const ChallengeListPage = () => {
4242

4343
// 过滤掉被标记为忽略的挑战
4444
const visibleChallenges = useMemo(() => {
45-
return challenges.filter(challenge => !challenge.ignored);
45+
console.log(`总挑战数量: ${challenges.length}`);
46+
const visible = challenges.filter(challenge => challenge.ignored !== true);
47+
console.log(`可见挑战数量(排除ignored=true): ${visible.length}`);
48+
return visible;
4649
}, [challenges]);
4750

4851
// 初始化搜索服务
@@ -71,8 +74,10 @@ const ChallengeListPage = () => {
7174
}
7275

7376
// 设置平台
74-
if (parsedFilters.platform && parsedFilters.platform !== 'all') {
75-
newSearchParams.set('platform', parsedFilters.platform);
77+
if (parsedFilters.platform && parsedFilters.platform.length > 0) {
78+
parsedFilters.platform.forEach((platform: string) => {
79+
newSearchParams.append('platform', platform);
80+
});
7681
}
7782

7883
// 设置标签
@@ -151,10 +156,54 @@ const ChallengeListPage = () => {
151156
saveFilterPreferences({ ...filters, difficulty: filters.difficulty });
152157
};
153158

159+
// 从URL同步过滤器状态
160+
useEffect(() => {
161+
const tags = searchParams.getAll('tags');
162+
let difficultyParams = searchParams.getAll('difficulty');
163+
const platformParam = searchParams.get('platform') || 'all';
164+
165+
console.log('URL平台参数:', platformParam);
166+
167+
// 处理特殊难度字符串转换
168+
if (difficultyParams.length === 1) {
169+
const diffParam = difficultyParams[0];
170+
if (diffParam === 'easy') {
171+
difficultyParams = ['1'];
172+
} else if (diffParam === 'medium') {
173+
difficultyParams = ['2', '3'];
174+
} else if (diffParam === 'hard') {
175+
difficultyParams = ['4', '5'];
176+
}
177+
}
178+
179+
const newFilters = {
180+
tags,
181+
difficulty: difficultyParams,
182+
platform: platformParam
183+
};
184+
185+
console.log('设置新筛选条件:', newFilters);
186+
setFilters(newFilters);
187+
188+
// 当URL发生变化时,同步到本地存储
189+
if (searchParams.toString()) {
190+
saveFilterPreferences(newFilters);
191+
}
192+
}, [searchParams]);
193+
154194
// 处理平台筛选
155195
const handlePlatformChange = (platform: string) => {
196+
console.log('处理平台筛选变化:', platform);
197+
156198
const newSearchParams = new URLSearchParams(searchParams);
157-
newSearchParams.set('platform', platform);
199+
newSearchParams.delete('platform');
200+
201+
// 如果选择的不是"all",则添加平台参数
202+
if (platform !== 'all') {
203+
newSearchParams.append('platform', platform);
204+
}
205+
206+
console.log('新URL参数:', newSearchParams.toString());
158207
navigate(`/challenges?${newSearchParams.toString()}`);
159208

160209
// 保存筛选设置到本地存储
@@ -204,33 +253,6 @@ const ChallengeListPage = () => {
204253
setDrawerVisible(false);
205254
};
206255

207-
// 从URL同步过滤器状态
208-
useEffect(() => {
209-
const tags = searchParams.getAll('tags');
210-
let difficultyParams = searchParams.getAll('difficulty');
211-
const platform = searchParams.get('platform') || 'all';
212-
213-
// 处理特殊难度字符串转换
214-
if (difficultyParams.length === 1) {
215-
const diffParam = difficultyParams[0];
216-
if (diffParam === 'easy') {
217-
difficultyParams = ['1', '2'];
218-
} else if (diffParam === 'medium') {
219-
difficultyParams = ['3', '4'];
220-
} else if (diffParam === 'hard') {
221-
difficultyParams = ['5'];
222-
}
223-
}
224-
225-
const newFilters = { tags, difficulty: difficultyParams, platform };
226-
setFilters(newFilters);
227-
228-
// 当URL发生变化时,同步到本地存储
229-
if (searchParams.toString()) {
230-
saveFilterPreferences(newFilters);
231-
}
232-
}, [searchParams]);
233-
234256
// 获取所有可用标签
235257
const allTags = useMemo(() => {
236258
const tags = new Set<string>();
@@ -252,12 +274,22 @@ const ChallengeListPage = () => {
252274
// 使用Fuse.js过滤和排序挑战
253275
const filteredChallenges = useMemo(() => {
254276
// 使用搜索服务过滤
277+
console.log(`过滤前挑战数量: ${visibleChallenges.length}`);
278+
console.log(`过滤条件:`, {
279+
tags: filters.tags,
280+
difficulty: filters.difficulty.join(','),
281+
platform: filters.platform,
282+
query: searchQuery
283+
});
284+
255285
const filtered = searchService.filterChallenges(visibleChallenges, {
256286
tags: filters.tags,
257287
difficulty: filters.difficulty.join(','),
258288
platform: filters.platform,
259289
query: searchQuery
260290
});
291+
292+
console.log(`过滤后挑战数量: ${filtered.length}`);
261293

262294
// 排序
263295
return filtered.sort((a: Challenge, b: Challenge) => {
@@ -347,22 +379,25 @@ const ChallengeListPage = () => {
347379
};
348380

349381
// 渲染控制面板(桌面或移动)
350-
const renderControls = () => (
351-
<ChallengeControls
352-
allTags={allTags}
353-
allPlatforms={allPlatforms}
354-
selectedTags={filters.tags}
355-
selectedDifficulty={filters.difficulty}
356-
selectedPlatform={filters.platform}
357-
sortBy={sortBy}
358-
sortOrder={sortOrder}
359-
onTagsChange={handleTagsChange}
360-
onDifficultyChange={handleDifficultyClick}
361-
onPlatformChange={handlePlatformChange}
362-
onSortByChange={handleSortByChange}
363-
onSortOrderChange={handleSortOrderChange}
364-
/>
365-
);
382+
const renderControls = () => {
383+
console.log('渲染控制面板,当前平台选择:', filters.platform);
384+
return (
385+
<ChallengeControls
386+
allTags={allTags}
387+
allPlatforms={allPlatforms}
388+
selectedTags={filters.tags}
389+
selectedDifficulty={filters.difficulty}
390+
selectedPlatform={filters.platform}
391+
sortBy={sortBy}
392+
sortOrder={sortOrder}
393+
onTagsChange={handleTagsChange}
394+
onDifficultyChange={handleDifficultyClick}
395+
onPlatformChange={handlePlatformChange}
396+
onSortByChange={handleSortByChange}
397+
onSortOrderChange={handleSortOrderChange}
398+
/>
399+
);
400+
};
366401

367402
// 渲染过滤器(适用于桌面和移动视图)
368403
const renderFilters = () => (
@@ -386,6 +421,9 @@ const ChallengeListPage = () => {
386421
<Col span={24}>
387422
<h1 style={{ fontSize: isMobile ? '1.5rem' : '2rem', marginBottom: '1rem' }}>
388423
{t('challenges.title')}
424+
<span style={{ fontWeight: 'normal', fontSize: isMobile ? '1.2rem' : '1.6rem', marginLeft: '8px' }}>
425+
({filteredChallenges.length})
426+
</span>
389427
</h1>
390428

391429
{/* 移动端搜索和过滤器 */}
@@ -422,7 +460,7 @@ const ChallengeListPage = () => {
422460
onPaginationChange={handlePaginationChange}
423461
onTagClick={handleTagClick}
424462
onDifficultyClick={(difficulty) => handleDifficultyClick(difficulty.toString())}
425-
onPlatformClick={handlePlatformChange}
463+
onPlatformClick={(platform) => handlePlatformChange(platform)}
426464
onChallengeClick={(id) => navigate(`/challenge/${id}`)}
427465
hidePagination={false}
428466
/>

src/components/HomePage/HeroSection.tsx

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ const { Title, Text, Paragraph } = Typography;
2424
interface HeroSectionProps {
2525
challenges: number;
2626
difficultyCounts: {
27-
easy: number;
28-
medium: number;
29-
hard: number;
27+
beginner: number;
28+
intermediate: number;
29+
advanced: number;
3030
};
3131
animatedStats: boolean;
3232
}
@@ -40,10 +40,10 @@ const HeroSection: React.FC<HeroSectionProps> = ({ challenges, difficultyCounts,
4040
const isMobile = useMediaQuery({ maxWidth: 768 });
4141

4242
// 计算每个难度级别的百分比
43-
const total = difficultyCounts.easy + difficultyCounts.medium + difficultyCounts.hard || 1;
44-
const easyPercent = Math.round((difficultyCounts.easy / total) * 100);
45-
const mediumPercent = Math.round((difficultyCounts.medium / total) * 100);
46-
const hardPercent = Math.round((difficultyCounts.hard / total) * 100);
43+
const total = difficultyCounts.beginner + difficultyCounts.intermediate + difficultyCounts.advanced || 1;
44+
const beginnerPercent = Math.round((difficultyCounts.beginner / total) * 100);
45+
const intermediatePercent = Math.round((difficultyCounts.intermediate / total) * 100);
46+
const advancedPercent = Math.round((difficultyCounts.advanced / total) * 100);
4747

4848
// 难度级别卡片样式
4949
const difficultyCardStyle = {
@@ -174,7 +174,7 @@ const HeroSection: React.FC<HeroSectionProps> = ({ challenges, difficultyCounts,
174174
<Row gutter={[isMobile ? 8 : 16, isMobile ? 8 : 16]}>
175175
{/* 初级难度 */}
176176
<Col span={24} sm={8}>
177-
<Tooltip title={`${easyPercent}% ${t('home.hero.stats.ofTotal')}`}>
177+
<Tooltip title={`${beginnerPercent}% ${t('home.hero.stats.ofTotal')}`}>
178178
<div
179179
style={{
180180
...difficultyCardStyle,
@@ -200,10 +200,10 @@ const HeroSection: React.FC<HeroSectionProps> = ({ challenges, difficultyCounts,
200200
marginBottom: '8px',
201201
textShadow: '0 0 10px rgba(82, 196, 26, 0.4)'
202202
}}>
203-
{difficultyCounts.easy}
203+
{difficultyCounts.beginner}
204204
</div>
205205
<Progress
206-
percent={easyPercent}
206+
percent={beginnerPercent}
207207
showInfo={false}
208208
strokeColor="#52c41a"
209209
trailColor="rgba(255,255,255,0.1)"
@@ -215,7 +215,7 @@ const HeroSection: React.FC<HeroSectionProps> = ({ challenges, difficultyCounts,
215215

216216
{/* 中级难度 */}
217217
<Col span={24} sm={8}>
218-
<Tooltip title={`${mediumPercent}% ${t('home.hero.stats.ofTotal')}`}>
218+
<Tooltip title={`${intermediatePercent}% ${t('home.hero.stats.ofTotal')}`}>
219219
<div
220220
style={{
221221
...difficultyCardStyle,
@@ -241,10 +241,10 @@ const HeroSection: React.FC<HeroSectionProps> = ({ challenges, difficultyCounts,
241241
marginBottom: '8px',
242242
textShadow: '0 0 10px rgba(250, 173, 20, 0.4)'
243243
}}>
244-
{difficultyCounts.medium}
244+
{difficultyCounts.intermediate}
245245
</div>
246246
<Progress
247-
percent={mediumPercent}
247+
percent={intermediatePercent}
248248
showInfo={false}
249249
strokeColor="#faad14"
250250
trailColor="rgba(255,255,255,0.1)"
@@ -256,7 +256,7 @@ const HeroSection: React.FC<HeroSectionProps> = ({ challenges, difficultyCounts,
256256

257257
{/* 高级难度 */}
258258
<Col span={24} sm={8}>
259-
<Tooltip title={`${hardPercent}% ${t('home.hero.stats.ofTotal')}`}>
259+
<Tooltip title={`${advancedPercent}% ${t('home.hero.stats.ofTotal')}`}>
260260
<div
261261
style={{
262262
...difficultyCardStyle,
@@ -282,10 +282,10 @@ const HeroSection: React.FC<HeroSectionProps> = ({ challenges, difficultyCounts,
282282
marginBottom: '8px',
283283
textShadow: '0 0 10px rgba(245, 34, 45, 0.4)'
284284
}}>
285-
{difficultyCounts.hard}
285+
{difficultyCounts.advanced}
286286
</div>
287287
<Progress
288-
percent={hardPercent}
288+
percent={advancedPercent}
289289
showInfo={false}
290290
strokeColor="#f5222d"
291291
trailColor="rgba(255,255,255,0.1)"

0 commit comments

Comments
 (0)