添加了标签排除功能 (#9)

This commit is contained in:
提瓦特钓鱼玳师
2025-04-26 15:09:55 +08:00
committed by GitHub
parent 4f90978a42
commit 4cfe2e4d9a

View File

@@ -40,23 +40,29 @@
<a-space direction="vertical" size="medium" style="width: 100%;"> <a-space direction="vertical" size="medium" style="width: 100%;">
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :span="8"> <a-col :span="6">
<a-input v-model="searchConditions[category.name].name" placeholder="搜索名称" allow-clear <a-input v-model="searchConditions[category.name].name" placeholder="搜索名称" allow-clear
@change="filterData(category.name)" /> @change="filterData(category.name)" />
</a-col> </a-col>
<a-col :span="8"> <a-col :span="6">
<a-select v-model="searchConditions[category.name].author" placeholder="选择作者" style="width: 100%;" <a-select v-model="searchConditions[category.name].author" placeholder="选择作者" style="width: 100%;"
allow-clear @change="filterData(category.name)"> allow-clear @change="filterData(category.name)">
<a-option v-for="author in getUniqueAuthors(category)" :key="author" :value="author">{{ author <a-option v-for="author in getUniqueAuthors(category)" :key="author" :value="author">{{ author
}}</a-option> }}</a-option>
</a-select> </a-select>
</a-col> </a-col>
<a-col :span="8"> <a-col :span="6">
<a-select v-model="searchConditions[category.name].tags" placeholder="选择标签" style="width: 100%;" <a-select v-model="searchConditions[category.name].tags" placeholder="选择标签" style="width: 100%;"
:filter-option="handleTagFilter" allow-clear @change="handleTagSelect(category.name)" multiple> :filter-option="handleTagFilter" allow-clear @change="handleTagSelect(category.name)" multiple>
<a-option v-for="tag in getUniqueTags(category)" :key="tag" :value="tag">{{ tag }}</a-option> <a-option v-for="tag in getUniqueTags(category)" :key="tag" :value="tag">{{ tag }}</a-option>
</a-select> </a-select>
</a-col> </a-col>
<a-col :span="6">
<a-select v-model="searchConditions[category.name].etags" placeholder="排除标签" style="width: 100%;"
:filter-option="handleTagFilter" allow-clear @change="handleTagSelect(category.name)" multiple>
<a-option v-for="tag in getUniqueTags(category)" :key="tag" :value="tag">{{ tag }}</a-option>
</a-select>
</a-col>
</a-row> </a-row>
<!-- 大盒子整体高度 calc(100vh - 200px) --> <!-- 大盒子整体高度 calc(100vh - 200px) -->
<div style="height: calc(100vh - 200px); display: flex; flex-direction: column; flex: 1"> <div style="height: calc(100vh - 200px); display: flex; flex-direction: column; flex: 1">
@@ -79,7 +85,7 @@
<template #tags="{ record }"> <template #tags="{ record }">
<a-space :style="{ flexWrap: 'wrap', rowGap: '8px' }"> <a-space :style="{ flexWrap: 'wrap', rowGap: '8px' }">
<a-tag v-for="tag in record.tags" :key="tag" :color="getTagColor(tag)" <a-tag v-for="tag in record.tags" :key="tag" :color="getTagColor(tag)"
style="cursor: pointer" @click="handleTagClick(tag, category.name)">{{ tag }}</a-tag> style="cursor: pointer" @click="handleTagClick(tag, category.name)" @contextmenu.prevent="handleTagRightClick(tag, category.name)">{{ tag }}</a-tag>
</a-space> </a-space>
</template> </template>
<template #operations="{ record }"> <template #operations="{ record }">
@@ -308,6 +314,7 @@ const fetchRepoData = async () => {
name: '', name: '',
author: '', author: '',
tags: [], tags: [],
etags: [],
path: '' path: ''
}; };
}); });
@@ -428,12 +435,20 @@ const filterData = (categoryName) => {
const filtered = []; const filtered = [];
traverseCategory(category, (item) => { traverseCategory(category, (item) => {
// 名称匹配:如果条件为空或项名称满足拼音匹配则认为匹配
const nameMatch = !condition.name || isPinyinMatch(item.name, condition.name); const nameMatch = !condition.name || isPinyinMatch(item.name, condition.name);
// 作者匹配:如果条件为空或项作者与条件一致则认为匹配
const authorMatch = !condition.author || item.author === condition.author; const authorMatch = !condition.author || item.author === condition.author;
// 修改标签匹配逻辑 // 标签匹配:如果 condition.tags 为空或者 item.tags 包含条件中的所有标签,则认为匹配
const tagMatch = condition.tags.length === 0 || (Array.isArray(item.tags) && condition.tags.every(tag => item.tags.includes(tag))); const tagMatch = condition.tags.length === 0 || (Array.isArray(item.tags) && condition.tags.every(tag => item.tags.includes(tag)));
// 排除标签匹配:如果 condition.etags 有内容,则要求 item.tags 不包含其中任一标签
const etagMatch = condition.etags.length === 0 || (Array.isArray(item.tags) && condition.etags.every(excludeTag => !item.tags.includes(excludeTag)));
// 路径匹配:满足条件时 item.path 存在且以指定条件开头,但不完全等于该条件
const pathMatch = !condition.path || (item.path && item.path.startsWith(condition.path) && item.path !== condition.path); const pathMatch = !condition.path || (item.path && item.path.startsWith(condition.path) && item.path !== condition.path);
if (nameMatch && authorMatch && tagMatch && pathMatch && (item.type === 'file' || (category.name === 'js' && item.type === 'directory'))) {
// 当各条件均满足,且类型为 'file' 或(如果当前分类为 'js' 则允许 'directory')时,将该项加入过滤结果
if (nameMatch && authorMatch && tagMatch && etagMatch && pathMatch &&
(item.type === 'file' || (category.name === 'js' && item.type === 'directory'))) {
filtered.push(item); filtered.push(item);
} }
}); });
@@ -441,12 +456,14 @@ const filterData = (categoryName) => {
filteredData[categoryName] = filtered; filteredData[categoryName] = filtered;
}; };
const initializeSearchConditions = () => { const initializeSearchConditions = () => {
repoDataRaw.value.forEach(category => { repoDataRaw.value.forEach(category => {
searchConditions[category.name] = { searchConditions[category.name] = {
name: '', name: '',
author: '', author: '',
tags: [], tags: [],
etags: [],
path: '' path: ''
}; };
filteredData[category.name] = []; filteredData[category.name] = [];
@@ -615,6 +632,15 @@ const handleTagClick = (tag, categoryName) => {
filterData(categoryName); filterData(categoryName);
} }
const handleTagRightClick = (tag, categoryName) => {
if (!searchConditions[categoryName].etags.includes(tag)) {
searchConditions[categoryName].etags.push(tag);
} else {
searchConditions[categoryName].etags = searchConditions[categoryName].etags.filter(t => t !== tag);
}
filterData(categoryName);
}
const handleTagFilter = (value, option) => { const handleTagFilter = (value, option) => {
return isPinyinMatch(option.value, value); return isPinyinMatch(option.value, value);
}; };