Skip to content

Commit 0248754

Browse files
committed
feat: 将难度筛选改为多选模式,支持easy/medium/hard特定字符串筛选
1 parent 4adcd5f commit 0248754

File tree

4 files changed

+78
-20
lines changed

4 files changed

+78
-20
lines changed

src/components/ChallengeListPage/ChallengeControls.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ interface ChallengeControlsProps {
2727
/**
2828
* 选中的难度
2929
*/
30-
selectedDifficulty: string;
30+
selectedDifficulty: string[];
3131

3232
/**
3333
* 选中的平台
@@ -110,8 +110,9 @@ const ChallengeControls: React.FC<ChallengeControlsProps> = ({
110110
// 难度过滤菜单
111111
const difficultyMenu = (
112112
<Menu
113-
selectedKeys={[selectedDifficulty]}
113+
selectedKeys={selectedDifficulty}
114114
onClick={({ key }) => onDifficultyChange(key)}
115+
multiple={false}
115116
>
116117
<Menu.Item key="all">{t('challenges.filters.allDifficulties')}</Menu.Item>
117118
<Menu.Item key="1">

src/components/ChallengeListPage/ChallengeFilters.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ interface ChallengeFiltersProps {
1414
/**
1515
* 选中的难度
1616
*/
17-
selectedDifficulty: string;
17+
selectedDifficulty: string[];
1818

1919
/**
2020
* 选中的平台
@@ -92,7 +92,7 @@ const ChallengeFilters: React.FC<ChallengeFiltersProps> = ({
9292
<Row gutter={[8, 8]} style={{ marginBottom: isMobile ? '8px' : '16px' }}>
9393
<Col span={24}>
9494
<Space wrap size={isMobile ? 4 : 8} style={{ width: '100%' }}>
95-
{selectedDifficulty !== 'all' && (
95+
{selectedDifficulty.length > 0 && (
9696
<Tag
9797
closable
9898
onClose={onRemoveDifficulty}
@@ -105,7 +105,11 @@ const ChallengeFilters: React.FC<ChallengeFiltersProps> = ({
105105
}}
106106
>
107107
{isMobile ? '' : `${t('challenges.sort.difficulty')}: `}
108-
<StarRating difficulty={parseInt(selectedDifficulty)} />
108+
<Space size={2}>
109+
{selectedDifficulty.map(diff => (
110+
<StarRating key={diff} difficulty={parseInt(diff)} />
111+
))}
112+
</Space>
109113
</Tag>
110114
)}
111115

src/components/ChallengeListPage/index.tsx

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const ChallengeListPage = () => {
2323
const { t } = useTranslation();
2424
const isMobile = useMediaQuery({ maxWidth: 768 });
2525
const [filters, setFilters] = useState({
26-
difficulty: 'all',
26+
difficulty: [] as string[],
2727
tags: [] as string[],
2828
platform: 'all'
2929
});
@@ -64,8 +64,10 @@ const ChallengeListPage = () => {
6464
const newSearchParams = new URLSearchParams(searchParams);
6565

6666
// 设置难度
67-
if (parsedFilters.difficulty && parsedFilters.difficulty !== 'all') {
68-
newSearchParams.set('difficulty', parsedFilters.difficulty);
67+
if (parsedFilters.difficulty && parsedFilters.difficulty.length > 0) {
68+
parsedFilters.difficulty.forEach((difficulty: string) => {
69+
newSearchParams.append('difficulty', difficulty);
70+
});
6971
}
7072

7173
// 设置平台
@@ -120,11 +122,33 @@ const ChallengeListPage = () => {
120122
// 处理难度点击
121123
const handleDifficultyClick = (difficulty: string) => {
122124
const newSearchParams = new URLSearchParams(searchParams);
123-
newSearchParams.set('difficulty', difficulty);
125+
const currentDifficulties = filters.difficulty;
126+
127+
// 检查是否已选中该难度
128+
const isSelected = currentDifficulties.includes(difficulty);
129+
130+
if (difficulty === 'all') {
131+
// 如果选择"全部",则清除所有难度筛选
132+
newSearchParams.delete('difficulty');
133+
filters.difficulty = [];
134+
} else if (isSelected) {
135+
// 如果已选中,则取消选中
136+
const newDifficulties = currentDifficulties.filter(d => d !== difficulty);
137+
newSearchParams.delete('difficulty');
138+
newDifficulties.forEach(d => newSearchParams.append('difficulty', d));
139+
filters.difficulty = newDifficulties;
140+
} else {
141+
// 如果未选中,则添加选中
142+
const newDifficulties = [...currentDifficulties, difficulty];
143+
newSearchParams.delete('difficulty');
144+
newDifficulties.forEach(d => newSearchParams.append('difficulty', d));
145+
filters.difficulty = newDifficulties;
146+
}
147+
124148
navigate(`/challenges?${newSearchParams.toString()}`);
125149

126150
// 保存筛选设置到本地存储
127-
saveFilterPreferences({ ...filters, difficulty });
151+
saveFilterPreferences({ ...filters, difficulty: filters.difficulty });
128152
};
129153

130154
// 处理平台筛选
@@ -183,10 +207,22 @@ const ChallengeListPage = () => {
183207
// 从URL同步过滤器状态
184208
useEffect(() => {
185209
const tags = searchParams.getAll('tags');
186-
const difficulty = searchParams.get('difficulty') || 'all';
210+
let difficultyParams = searchParams.getAll('difficulty');
187211
const platform = searchParams.get('platform') || 'all';
188212

189-
const newFilters = { tags, difficulty, platform };
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 };
190226
setFilters(newFilters);
191227

192228
// 当URL发生变化时,同步到本地存储
@@ -218,7 +254,7 @@ const ChallengeListPage = () => {
218254
// 使用搜索服务过滤
219255
const filtered = searchService.filterChallenges(visibleChallenges, {
220256
tags: filters.tags,
221-
difficulty: filters.difficulty,
257+
difficulty: filters.difficulty.join(','),
222258
platform: filters.platform,
223259
query: searchQuery
224260
});
@@ -263,8 +299,17 @@ const ChallengeListPage = () => {
263299
newTags.forEach(t => newSearchParams.append('tags', t));
264300
newFilters = { ...newFilters, tags: newTags };
265301
} else if (type === 'difficulty') {
266-
newSearchParams.delete('difficulty');
267-
newFilters = { ...newFilters, difficulty: 'all' };
302+
if (value) {
303+
// 仅移除单个难度
304+
const newDifficulties = filters.difficulty.filter(d => d !== value);
305+
newSearchParams.delete('difficulty');
306+
newDifficulties.forEach(d => newSearchParams.append('difficulty', d));
307+
newFilters = { ...newFilters, difficulty: newDifficulties };
308+
} else {
309+
// 移除所有难度
310+
newSearchParams.delete('difficulty');
311+
newFilters = { ...newFilters, difficulty: [] };
312+
}
268313
} else if (type === 'platform') {
269314
newSearchParams.delete('platform');
270315
newFilters = { ...newFilters, platform: 'all' };
@@ -278,7 +323,7 @@ const ChallengeListPage = () => {
278323
const handleClearAllFilters = () => {
279324
const newSearchParams = new URLSearchParams();
280325
setSearchParams(newSearchParams);
281-
const newFilters = { tags: [], difficulty: 'all', platform: 'all' };
326+
const newFilters = { tags: [], difficulty: [], platform: 'all' };
282327
setFilters(newFilters);
283328
saveFilterPreferences(newFilters);
284329
};
@@ -295,7 +340,7 @@ const ChallengeListPage = () => {
295340
// 获取应用的过滤器数量
296341
const getAppliedFiltersCount = () => {
297342
let count = 0;
298-
if (filters.difficulty !== 'all') count++;
343+
if (filters.difficulty.length > 0) count++;
299344
if (filters.platform !== 'all') count++;
300345
count += filters.tags.length;
301346
return count;
@@ -325,7 +370,7 @@ const ChallengeListPage = () => {
325370
selectedTags={filters.tags}
326371
selectedDifficulty={filters.difficulty}
327372
selectedPlatform={filters.platform}
328-
hasFilters={filters.tags.length > 0 || filters.difficulty !== 'all' || filters.platform !== 'all'}
373+
hasFilters={filters.tags.length > 0 || filters.difficulty.length > 0 || filters.platform !== 'all'}
329374
onRemoveTag={(tag) => handleFilterRemove('tag', tag)}
330375
onRemoveDifficulty={() => handleFilterRemove('difficulty')}
331376
onRemovePlatform={() => handleFilterRemove('platform')}

src/services/SearchService.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,16 @@ class SearchService {
9696
filters.tags.every(tag => challenge.tags.includes(tag));
9797

9898
// 难度过滤
99-
const matchesDifficulty = !filters.difficulty || filters.difficulty === 'all' ||
100-
challenge.difficulty === parseInt(filters.difficulty);
99+
let matchesDifficulty = true;
100+
if (filters.difficulty && filters.difficulty !== 'all') {
101+
// 处理逗号分隔的多难度筛选
102+
const difficultyArray = filters.difficulty.split(',').filter(Boolean);
103+
if (difficultyArray.length > 0) {
104+
matchesDifficulty = difficultyArray.some(diff =>
105+
challenge.difficulty === parseInt(diff)
106+
);
107+
}
108+
}
101109

102110
// 平台过滤
103111
const matchesPlatform = !filters.platform || filters.platform === 'all' ||

0 commit comments

Comments
 (0)