全局搜索与高级检索方案.md 11 KB

全局搜索与高级检索方案

状态:已确认,开始实施 创建日期:2026-08-14 推进顺序:P1 → F1 → F2 → F3 → F4 → 测试

一、需求最终确认

1. 数据模型新增

字段 类型 适用对象 默认值 可改
organization_id 外键 → organizations 主案/子案/附件 创建者当前 organization_id ✅
organization_name 字符串(冗余) 同上 创建者当前 organization_name ✅(联动 id 改名)

与现有的"创建者"字段独立维护。用户调岗不影响历史文档归属。

2. 检索条件矩阵

条件 控件 匹配字段 默认值 行为
简单关键词 顶部全局文本框 标题(主案/子案/附件) 空=不过滤 模糊匹配
正文关键词 高级检索文本框 contentText/searchText 空=不过滤 模糊匹配
密级 高级检索多选框 securityLevel 不勾=不过滤 勾选项内 OR
所属部门 高级检索文本框 organization_name 空=不过滤 模糊匹配

叠加:四条件全部 AND。

3. 列表行为

主案列表(顶部表格):

  • 简单关键词命中标题 → 入列表
  • 简单关键词未命中主案标题,但命中其下可见子案/附件标题 → 主案入列表,显示徽章
    • 📄 子案 N / 📎 附件 N(同时命中同时显示)
  • 高级检索条件(正文/密级/部门)只过滤主案本身——主案不满足则不入列表(即便其下子案/附件满足)
  • 主案标题中的简单关键词 → 高亮

子案/附件 Tab(选中主案后):

  • 应用全部四条件到该主案下的子案/附件
    • 简单关键词匹配标题
    • 正文关键词匹配正文
    • 密级匹配密级
    • 所属部门匹配所属部门
  • 仅显示满足全部条件的子案/附件
  • 无满足项 → 完全空白
  • 标题中的简单关键词 → 高亮
  • 正文关键词命中 → 行下方延展 contentSnippet 片段并高亮(沿用现有样式)

4. UI 结构

┌──────────────────────────────────────────────────────────┐
│ 🔍 [ 全局关键词(匹配标题)                    ] [🔍] [⚙高级检索] │
│ ┌─高级检索(折叠态默认隐藏)────────────────────────────┐ │
│ │ 正文: [             ]  密级: ☐公开 ☐内部 ☐秘密 ☐机密 ☐绝密 │ │
│ │ 部门: [             ]                                  │ │
│ └─────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────┤
│ 主案列表(含命中徽章)                                    │
│ ┌────┬──────────────┬──────┬────┬────┬───────┐         │
│ │序号│ 名称         │ 类型 │密级│部门│更新   │         │
│ │ 1  │ 2026**作战** │ 秘密 │秘密│作战│07-12  │         │
│ │ 2  │ 训练方案  📄📎│ 内部 │内部│训练│06-30  │         │
│ └────┴──────────────┴──────┴────┴────┴───────┘         │
├──────────────────────────────────────────────────────────┤
│ [子案(N)] [附件(N)]                                       │
│ ┌────┬──────────────┬──────┬─────────────┐              │
│ │序号│ 名称         │ 密级 │ 部门        │              │
│ │ 1  │ 南路**作战** │ 秘密 │ 作战部      │              │
│ │    │ └ 📝 "...**作战**分队由..."      │ ← 正文片段    │
│ └────┴──────────────┴──────┴─────────────┘              │
└──────────────────────────────────────────────────────────┘

二、实施计划

P1. 后端数据模型与迁移(约 3h)

步骤 文件 说明
P1.1 backend/dms/models/document.py Document 模型新增 organization_id 外键 + organization_name 冗余字段(参照现有 category_id/category_name 模式)
P1.2 backend/migrations/versions/0006_document_organization.py down_revision=0005_category_flat_mode;添加列;按 creator_id → users.organization_id 回填历史;回填 organization_name
P1.3 backend/dms/services/document_query_service.py document_summary 响应 DTO 新增 organizationId/organizationName;document_mutation_service.py 创建/更新分支接收 organizationId(缺省取 AuthContext.organization_id)
P1.4 backend/dms/services/organization_service.py update_organization 在第 381-395 行附近追加 Document 的 organization_name 批量刷新(与 User 刷新一致)

P2. 后端接口扩展(约 4h)

步骤 文件 说明
P2.1 backend/dms/api/v1/documents.py list 接口新增查询参数:content_keyword、security_levels(多选)、organization_keyword
P2.2 同上 新增 list_aggregated 端点或扩展现有 list:返回主案时附带 subHitCount、attachmentHitCount、titleHit(主案本身是否命中)
P2.3 backend/dms/api/v1/documents.py sub-plans/{main_id} 与 attachments 接口同步扩展四条件参数
P2.4 backend/dms/api/v1/documents.py 文档创建:organization_id 缺省取 current_user.organization_id;更新:管理员可改

P3. 后端服务层(约 3h)

步骤 文件 说明
P3.1 backend/dms/services/document_service.py list_documents 增加高级检索过滤分支(与现有 keyword 标题匹配并存)
P3.2 同上 新增 list_main_documents_aggregated:处理"主案或其下子案/附件命中"的并集逻辑,返回主案列表 + 命中计数
P3.3 同上 命中计数来源:按主案 ID 批量查询可见子案/附件的标题命中数

F1. 前端类型与 API 客户端(约 2h)

步骤 文件 说明
F1.1 frontend/src/features/documents/documentTypes.ts DocumentSummary 新增 organizationId、organizationName、subHitCount?、attachmentHitCount?、titleHit?
F1.2 frontend/src/features/documents/documentApi.ts 查询参数类型扩展;新增 searchAggregated 方法(或扩展现有 list)
F1.3 frontend/src/features/attachments/attachmentApi.ts 同步扩展查询参数

F2. 前端检索栏(约 3h)

步骤 文件 说明
F2.1 frontend/src/features/documents/GlobalSearchBar.tsx(新) 顶部全局检索栏:含简单关键词输入 + 高级检索折叠行
F2.2 frontend/src/app/App.tsx 删除 RealMainPage / RealAdminPage 中三处 DocumentSearchToolbar 调用
F2.3 同 F2.1 高级检索折叠行:正文关键词 + 密级多选 + 所属部门;密级选项来自 shared/api/enums.ts 的 SecurityLevel

F3. 前端列表渲染(约 3h)

步骤 文件 说明
F3.1 frontend/src/app/App.tsx F4DocumentTable 名称列高亮渲染(接收 highlightKeyword);命中徽章列(subHitCount/attachmentHitCount);新增"所属部门"列
F3.2 同上 选中主案后,子案/附件 Tab 调用扩展接口传入四条件
F3.3 同上 行下方延展沿用现有 contentSnippet 样式

F4. 前端状态管理(约 2h)

步骤 文件 说明
F4.1 frontend/src/features/documents/documentState.ts 新增全局检索状态:simpleKeyword、advancedFilters(contentKeyword、securityLevels、organizationKeyword)
F4.2 frontend/src/app/App.tsx 主案查询使用全局状态;选中主案后子案/附件查询复用全局状态
F4.3 同上 关键词防抖沿用 300ms

测试(约 4h)

步骤 文件 说明
T1.1 backend/tests/dms/test_global_search.py 后端:覆盖 6 种命中组合(主案命中、子案命中、附件命中、混合、空、高级检索过滤)
T1.2 backend/tests/dms/test_document_organization.py 后端:默认值取创建者组织、可修改、不联动调岗
T2.1 frontend/src/features/documents/__tests__/GlobalSearchBar.test.tsx 前端:折叠/展开、条件生效、密级多选
T2.2 frontend/src/app/__tests__/F4DocumentTable.test.tsx 前端:徽章显示、高亮渲染、所属部门列

三、风险与缓解

编号 风险 缓解
R1 聚合查询在大数据量下慢 在 title、organization_name、security_level 上加索引;必要时切全文索引
R2 历史数据密级为空 迁移中给默认值(最低密级)
R3 组织改名时冗余字段不同步 沿用 move organization 级联策略:移动组织时同步刷新所有文档的 organization_name
R4 简单关键词匹配标题但子案不可见 聚合时按 ACL 校验子案/附件可见性,不可见的命中不计入计数
R5 索引膨胀 仅在 title、organization_name 上加 BTREE 索引;contentText 不加索引(按需切全文)

四、工作量估算

阶段 工作量
P1 后端模型+迁移 ~3h
P2 后端接口扩展 ~4h
P3 后端服务层 ~3h
F1 前端类型与API ~2h
F2 前端检索栏 ~3h
F3 前端列表渲染 ~3h
F4 前端状态管理 ~2h
测试 ~4h
联调与回归 ~2h
合计 ~26h

五、推进顺序

按用户要求:P1 → F1 → F2 → F3 → F4 → 测试

  • P1 完成后即可推进 F1(前端类型可基于后端 DTO 设计提前确定)
  • P2/P3 在 F 阶段并行推进(前端先用 mock 数据,后端接口 ready 后切换)
  • 测试阶段:后端测试在 P3 完成后立即写;前端测试在 F4 完成后立即写
  • 联调与回归:所有阶段完成后做一次完整联调