fix: 第二轮PubMed搜索合规审计 — 8项修复 + 6项新测试
F1: search_engine.py `_pubmed_conditions` 顶层 [MH:noexp] 丢失 _noexp 标志
按 _noexp 分组 mesh_terms,分别调用 _expand_mesh_tag_ids(noexp=True/False)
F2: search_engine.py 组内 NOT 违反 De Morgan 律
全组 is_not=True 时单 NOT 包裹组合条件而非 per-term not_()
F3: pubmed_query_parser.py `_parse_not_expr` 不支持重复 NOT
改为递归调用,NOT NOT toggle is_not(三重 NOT 正确)
F4: SearchView.vue Custom Range datePreset 不发送日期参数
增加 datePreset === 'custom' 分支发送 year_from/year_to
F5: HomeView.vue restoreFromUrl 恢复不全
补全 sort/field/retracted/negative_result
F6: AdvancedSearchPanel.vue precision_mode 死控件移除(UI+emit+reset)
types/index.ts precision_mode 死类型字段移除
F7: types/index.ts is_oa 标记为 unused, reserved
F8: search_engine.py `_expand_mesh_tag_ids` N+1 → 2 批量查询
所有 entry_terms 和 name_en 分别合并为 OR 查询
测试: 新增 NOT NOT/triple NOT/NOT group/DM:noexp 顶层 共 7 项
This commit is contained in:
@@ -12,7 +12,7 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
search: [params: { query: string; field: string; date_from: string | null; date_to: string | null; journal_tiers: string[]; tag_ids: string[]; retracted: string; negative_result: string; precision_mode: string; sort: string }]
|
||||
search: [params: { query: string; field: string; date_from: string | null; date_to: string | null; journal_tiers: string[]; tag_ids: string[]; retracted: string; negative_result: string; sort: string }]
|
||||
}>()
|
||||
|
||||
const toast = useToast()
|
||||
@@ -23,7 +23,6 @@ const selectedTiers = ref<string[]>([])
|
||||
const selectedTags = ref<string[]>([])
|
||||
const retracted = ref('')
|
||||
const negativeResult = ref('')
|
||||
const precisionMode = ref('majr')
|
||||
const sort = ref('date')
|
||||
const field = ref('all')
|
||||
const fieldOptions = [
|
||||
@@ -71,7 +70,6 @@ function handleSearch() {
|
||||
tag_ids: selectedTags.value,
|
||||
retracted: retracted.value,
|
||||
negative_result: negativeResult.value,
|
||||
precision_mode: precisionMode.value,
|
||||
sort: sort.value,
|
||||
})
|
||||
}
|
||||
@@ -85,7 +83,6 @@ function resetFilters() {
|
||||
selectedTags.value = []
|
||||
retracted.value = ''
|
||||
negativeResult.value = ''
|
||||
precisionMode.value = 'majr'
|
||||
sort.value = 'date'
|
||||
}
|
||||
|
||||
@@ -143,14 +140,6 @@ function resetFilters() {
|
||||
<NRadio value="only" size="small">阴性结果</NRadio>
|
||||
</NRadioGroup>
|
||||
</div>
|
||||
<div>
|
||||
<label class="filter-label">🎯 精度模式</label>
|
||||
<NRadioGroup v-model:value="precisionMode" name="precision">
|
||||
<NRadio value="" size="small">全部</NRadio>
|
||||
<NRadio value="majr" size="small">🎯 高精度 (Major Topic)</NRadio>
|
||||
<NRadio value="mesh" size="small">📚 高召回 (MeSH)</NRadio>
|
||||
</NRadioGroup>
|
||||
</div>
|
||||
<div>
|
||||
<label class="filter-label">📊 排序</label>
|
||||
<NSelect v-model:value="sort" :options="[
|
||||
|
||||
@@ -339,13 +339,12 @@ export interface SearchRequestBody {
|
||||
journal_tiers?: string[]
|
||||
tag_ids?: string[]
|
||||
pub_types?: string[]
|
||||
is_oa?: boolean | null
|
||||
is_oa?: boolean | null // unused, reserved for future OA filter UI
|
||||
language?: string | null
|
||||
languages?: string[]
|
||||
nlm_subsets?: string[]
|
||||
retracted?: string
|
||||
negative_result?: string
|
||||
precision_mode?: string
|
||||
// PubMed 筛选器
|
||||
has_abstract?: boolean
|
||||
is_free_full_text?: boolean
|
||||
|
||||
@@ -296,8 +296,13 @@ const { page, total, goToPage } = usePagination({
|
||||
// 年份 / 日期(datePreset 与 year_* 互斥)
|
||||
const yf = Number(yearFromStr.value)
|
||||
const yt = Number(yearToStr.value)
|
||||
if (!datePreset.value && yearFromStr.value && !isNaN(yf) && yf >= 1900 && yf <= 2100) body.year_from = yf
|
||||
if (!datePreset.value && yearToStr.value && !isNaN(yt) && yt >= 1900 && yt <= 2100) body.year_to = yt
|
||||
if (datePreset.value === 'custom') {
|
||||
if (yearFromStr.value && !isNaN(yf) && yf >= 1900 && yf <= 2100) body.year_from = yf
|
||||
if (yearToStr.value && !isNaN(yt) && yt >= 1900 && yt <= 2100) body.year_to = yt
|
||||
} else {
|
||||
if (!datePreset.value && yearFromStr.value && !isNaN(yf) && yf >= 1900 && yf <= 2100) body.year_from = yf
|
||||
if (!datePreset.value && yearToStr.value && !isNaN(yt) && yt >= 1900 && yt <= 2100) body.year_to = yt
|
||||
}
|
||||
if (datePreset.value && datePreset.value !== 'custom') {
|
||||
const now = new Date()
|
||||
body.date_to = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())).toISOString().slice(0, 10)
|
||||
|
||||
@@ -361,6 +361,10 @@ function restoreFromUrl() {
|
||||
searchParams.value.query = q
|
||||
localQuery.value = q
|
||||
}
|
||||
if (route.query.sort) searchParams.value.sort = route.query.sort as string
|
||||
if (route.query.field) searchParams.value.field = route.query.field as string
|
||||
if (route.query.retracted) searchParams.value.retracted = route.query.retracted as string
|
||||
if (route.query.negative) searchParams.value.negative_result = route.query.negative as string
|
||||
}
|
||||
|
||||
// ── 同步状态到 URL ──
|
||||
|
||||
Reference in New Issue
Block a user