diff --git a/.gemini-clipboard/clipboard-1766633164025.png b/.gemini-clipboard/clipboard-1766633164025.png deleted file mode 100644 index e7d9c93..0000000 Binary files a/.gemini-clipboard/clipboard-1766633164025.png and /dev/null differ diff --git a/.gemini-clipboard/clipboard-1769082714226.png b/.gemini-clipboard/clipboard-1769082714226.png new file mode 100644 index 0000000..dc39bd2 Binary files /dev/null and b/.gemini-clipboard/clipboard-1769082714226.png differ diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md index 1923651..fced962 100644 --- a/IMPLEMENTATION_PLAN.md +++ b/IMPLEMENTATION_PLAN.md @@ -89,62 +89,6 @@ --- -## 技术决策 - -### 数据库变更 -- 无需修改现有表结构(project_members 和 operation_logs 已存在) - -### 后端API新增 -1. `GET /projects/my` - 获取我创建的项目 -2. `GET /projects/shared` - 获取我参与的项目 -3. `POST /projects/{project_id}/members` - 添加项目成员(已存在,需测试) -4. `DELETE /projects/{project_id}/members/{user_id}` - 删除项目成员(需新增) -5. `POST /search/documents` - 全局文档搜索(需新增) -6. 修改 `POST /files/{project_id}/file` - 增加操作日志记录 - -### 前端路由调整 -- `/projects/my` - 我的项目(原 /projects) -- `/projects/share` - 参与的项目(新增) -- 保持 `/projects` 作为默认,重定向到 `/projects/my` - -### 权限控制策略 -- 项目所有者:完全控制(增删改查、成员管理、删除项目) -- 项目管理员(ADMIN):文档管理、成员管理 -- 项目编辑者(EDITOR):文档编辑 -- 项目查看者(VIEWER):仅查看 - -### 操作日志设计 -```json -{ - "user_id": 1, - "username": "admin", - "operation_type": "update", - "resource_type": "document", - "resource_id": 123, - "detail": { - "project_id": 10, - "file_path": "/docs/readme.md", - "action": "edit", - "changes": "content_modified" - }, - "ip_address": "192.168.1.1", - "status": 1 -} -``` - -### 全局搜索实现方案 -1. **基础版本(当前阶段)**: - - 搜索 document_meta 表的 title 字段 - - 读取磁盘文件内容进行关键词匹配 - - 适用于小规模项目 - -2. **未来优化(可选)**: - - 使用 Elasticsearch 全文检索 - - 添加文档内容索引到数据库 - - 实现增量索引更新 - ---- - ## Stage 7: PDF文档混合模式 **Goal**: 支持项目中上传PDF文件,并在Markdown和浏览模式下查看PDF @@ -271,99 +215,40 @@ --- -## PDF功能技术选型 +## Stage 8: 全文内容检索增强 (Whoosh) +**Goal**: 引入 Whoosh 搜索引擎,实现基于文档内容的全文检索和高亮显示。 -### PDF预览库对比 +### 核心方案 +- **技术**: Whoosh (纯Python搜索引擎) + Jieba (中文分词) +- **存储**: 本地文件系统 `storage/search_index` +- **同步**: 实时文件操作钩子 + 批量重建脚本 -**方案1: react-pdf** (推荐) -- 优点: - - 轻量级,基于pdf.js封装 - - API简单易用 - - 支持分页、缩放、搜索 - - TypeScript支持良好 -- 缺点: - - 需要配置worker - - 大文件可能需要优化 -- 安装:`npm install react-pdf pdfjs-dist` +### 8.1 基础设施搭建 +**Goal**: 引入依赖并创建搜索服务 +**Status**: Not Started +**Implementation**: +1. 添加 `Whoosh`, `jieba` 到 requirements.txt +2. 创建 `backend/app/services/search_service.py` + - 定义 Index Schema (project_id, path, title, content) + - 实现 Add/Remove/Update Document 方法 + - 实现 Search 方法(支持高亮) -**方案2: @react-pdf-viewer** -- 优点: - - 功能更强大(书签、注释、表单) - - 开箱即用的工具栏 - - 插件系统 -- 缺点: - - 包体积较大 - - 可能功能过剩 +### 8.2 索引同步机制 +**Goal**: 确保文件修改实时反映到搜索结果 +**Status**: Not Started +**Implementation**: +1. 修改 `backend/app/api/v1/files.py` + - 在 `save_file` 后调用 `index.add_document` + - 在 `operate_file` (rename/move) 后更新索引 + - 在 `operate_file` (delete) 后删除索引 + - 在 `import_documents` 后批量添加索引 +2. 创建初始化脚本/API:`POST /api/v1/system/rebuild-index` -**方案3: iframe直接嵌入** -- 优点: - - 最简单,无需额外依赖 - - 浏览器原生支持 -- 缺点: - - 功能有限,样式难以自定义 - - 移动端体验差 - -### 推荐方案 -**使用 react-pdf**,理由: -1. 轻量级,适合当前项目规模 -2. 功能足够,易于扩展 -3. 社区活跃,文档完善 - -### 文件存储结构 - -``` -projects/ - {storage_key}/ - _assets/ - images/ # 图片文件(现有) - files/ # PDF等文档文件(新增) - README.md - 其他目录和文件 -``` - -### API设计 - -**1. 上传PDF文件(扩展现有接口)** -``` -POST /api/v1/files/{project_id}/upload-file -``` -请求参数: -- `file`: 文件二进制 -- `subfolder`: "files"(新增,默认"images") - -返回: -```json -{ - "code": 200, - "data": { - "filename": "abc123.pdf", - "original_filename": "产品说明书.pdf", - "path": "_assets/files/abc123.pdf", - "size": 1024000 - } -} -``` - -**2. 访问PDF文件(新接口)** -``` -GET /api/v1/files/{project_id}/asset?path={relative_path} -``` -- 权限校验:检查用户是否有项目访问权限 -- 返回:PDF文件流(Content-Type: application/pdf) - -### Markdown链接格式 - -```markdown -# 项目文档 - -查看详细说明:[产品说明书](/_assets/files/abc123.pdf) -``` - -### 待确认问题 - -1. **文件大小限制**:PDF文件最大允许多少MB?建议:20MB -2. **是否支持PDF注释/标注**:暂不支持,后续可扩展 -3. **PDF缩略图**:是否需要在文件树显示PDF缩略图?建议:暂不支持 -4. **PDF搜索文本内容**:是否需要搜索PDF内部文字?建议:暂不支持 -5. **并发上传限制**:是否限制同时上传的PDF数量? -6. **历史版本**:PDF文件是否需要版本控制?建议:暂不支持 +### 8.3 搜索接口升级 +**Goal**: 升级搜索API支持内容搜索 +**Status**: Not Started +**Implementation**: +1. 修改 `backend/app/api/v1/search.py` +2. 调用 `SearchService.search` +3. 返回包含 `highlight` 摘要的结果结构 +4. 前端展示优化(显示匹配片段) \ No newline at end of file diff --git a/frontend/src/pages/Document/DocumentEditor.css b/frontend/src/pages/Document/DocumentEditor.css index 564673c..977c8ef 100644 --- a/frontend/src/pages/Document/DocumentEditor.css +++ b/frontend/src/pages/Document/DocumentEditor.css @@ -39,17 +39,16 @@ .sider-actions { display: flex; - gap: 8px; align-items: center; } .mode-toggle-btn { - border-radius: 6px !important; font-weight: 500 !important; height: 32px !important; display: flex !important; align-items: center !important; - padding: 0 12px !important; + justify-content: center !important; + padding: 4px 15px !important; border: none !important; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); } @@ -70,9 +69,6 @@ } .sider-actions .ant-btn:not(.mode-toggle-btn) { - background: #f0f0f0; - border: 1px solid #d9d9d9; - border-radius: 6px; display: flex; align-items: center; justify-content: center; diff --git a/frontend/src/pages/Document/DocumentEditor.jsx b/frontend/src/pages/Document/DocumentEditor.jsx index f6b36b1..fc335f3 100644 --- a/frontend/src/pages/Document/DocumentEditor.jsx +++ b/frontend/src/pages/Document/DocumentEditor.jsx @@ -70,7 +70,7 @@ function DocumentEditor() { const [isPdfSelected, setIsPdfSelected] = useState(false) // 是否选中了PDF文件 const [linkModalVisible, setLinkModalVisible] = useState(false) const [linkTarget, setLinkTarget] = useState(null) - const [projectName, setProjectName] = useState('项目文档') // 项目名称 + const [projectName, setProjectName] = useState('') // 项目名称 const editorCtxRef = useRef(null) // 插入内链接 @@ -124,7 +124,7 @@ function DocumentEditor() { const res = await getProjectTree(projectId) const data = res.data || {} const tree = data.tree || data || [] // 兼容新旧格式 - const name = data.project_name || '项目文档' + const name = data.project_name setTreeData(tree) setProjectName(name) } catch (error) { @@ -864,55 +864,55 @@ function DocumentEditor() {