diff --git a/EDITOR_UPLOAD_FIX.md b/EDITOR_UPLOAD_FIX.md new file mode 100644 index 0000000..92313ec --- /dev/null +++ b/EDITOR_UPLOAD_FIX.md @@ -0,0 +1,172 @@ +# 编辑器图片上传问题修复 + +## 问题描述 +编辑器里上传的图片无法显示。 + +## 根本原因 +文件保存路径和静态文件URL映射不匹配。 + +## 已完成的修改 + +### 1. 后端文件保存路径 (`server/controllers/file.go`) + +**修改前:** +```go +uploadDir := path.Join("uploads", datePath) +``` +文件保存到:`server/uploads/` + +**修改后:** +```go +uploadDir := path.Join("..", "uploads", datePath) +``` +文件保存到:`项目根目录/uploads/` + +### 2. 静态文件映射 (`server/conf/app.conf`) + +**修改前:** +```conf +StaticDir = /uploads:uploads +``` + +**修改后:** +```conf +StaticDir = /uploads:../uploads +``` + +现在 `/uploads` URL 正确映射到项目根目录的 `uploads` 文件夹。 + +### 3. 前端URL拼接 (`front/src/components/WangEditor.vue`) + +添加了更健壮的URL拼接逻辑: + +```typescript +const fileUrl = response.data.data.file_url; // /uploads/2024/01/15/xxx.jpg +const baseUrl = getUploadUrl() ; + +let fullUrl = fileUrl; +if (!fileUrl.startsWith('http')) { + const base = baseUrl.replace(/\/$/, ''); + const url = fileUrl.startsWith('/') ? fileUrl : '/' + fileUrl; + fullUrl = `${base}${url}`; +} +``` + +这样可以确保URL正确拼接为:`http://localhost:8080/uploads/2024/01/15/xxx.jpg` + +## 目录结构 + +上传后文件将保存在: + +``` +yunzer_go/ +├── server/ +├── front/ +└── uploads/ ← 文件保存位置 + ├── 2024/ + │ └── 01/ + │ └── 15/ + │ └── 20240115143045_example.jpg +``` + +## 访问URL + +上传后可以通过以下URL访问: + +``` +http://localhost:8080/uploads/2024/01/15/20240115143045_example.jpg +``` + +## 如何验证 + +### 1. 上传一个图片 +在编辑器中使用图片上传功能上传一张图片。 + +### 2. 查看控制台日志 +打开浏览器开发者工具(F12),查看 Console 标签,应该看到: +``` +图片上传成功,URL: http://localhost:8080/uploads/2024/01/15/xxx.jpg +``` + +### 3. 检查文件是否保存 +查看项目根目录的 `uploads` 文件夹: +```bash +ls uploads/2024/01/15/ +``` + +### 4. 测试URL访问 +在浏览器中直接访问图片URL,应该能看到图片。 + +### 5. 检查数据库 +查看 `yz_files` 表中的记录: +```sql +SELECT file_path, file_url FROM yz_files ORDER BY upload_time DESC LIMIT 1; +``` + +应该看到: +- `file_path`: `uploads/2024/01/15/xxx.jpg` +- `file_url`: `/uploads/2024/01/15/xxx.jpg` + +## 重启服务器 + +修改配置后需要重启服务器才能生效: + +```bash +cd server +go run main.go +``` + +或者如果使用编译后的可执行文件: + +```bash +./server.exe +``` + +## 如果还是看不到图片 + +### 检查清单 + +1. ✅ 服务器是否重启 +2. ✅ 文件是否保存到 `uploads` 目录 +3. ✅ 浏览器控制台是否有错误 +4. ✅ URL是否正确拼接 +5. ✅ 静态文件映射是否正确 + +### 常见问题 + +**Q: 上传后文件保存在哪里?** +A: 项目根目录的 `uploads` 文件夹 + +**Q: 图片URL是什么格式?** +A: `http://localhost:8080/uploads/2024/01/15/filename.jpg` + +**Q: 为什么看不到图片?** +A: 检查: +- 文件是否正确保存 +- URL是否可访问 +- 浏览器控制台错误信息 +- 服务器是否重启 + +**Q: 如何自定义上传目录?** +A: 修改 `server/controllers/file.go` 和 `server/conf/app.conf` 中的路径配置 + +## 调试建议 + +如果图片仍不显示,检查以下内容: + +1. **查看浏览器网络请求** + - F12 → Network 标签 + - 查看图片请求是否返回 200 + - 如果返回 404,说明路径不对 + +2. **查看浏览器控制台** + - 查看是否有 CORS 错误 + - 查看上传成功后的 URL 是什么 + +3. **查看服务器日志** + - 确认文件是否正确上传 + - 确认路径是否正确 + +4. **检查文件权限** + - 确保应用有创建目录和写入文件的权限 + diff --git a/front/src/api/file.ts b/front/src/api/file.ts index 576aa72..8f035c0 100644 --- a/front/src/api/file.ts +++ b/front/src/api/file.ts @@ -18,7 +18,14 @@ export const fileAPI = { }, // 上传文件 - uploadFile: (formData: FormData) => { + uploadFile: (formData: FormData, options?: { category?: string; tenantId?: string }) => { + // 如果提供了额外参数,添加到 formData 中 + if (options?.category) { + formData.append('category', options.category) + } + if (options?.tenantId) { + formData.append('tenant_id', options.tenantId) + } return api.post('/api/files', formData, { headers: { 'Content-Type': 'multipart/form-data' diff --git a/front/src/components/WANGEDITOR_UPLOAD.md b/front/src/components/WANGEDITOR_UPLOAD.md new file mode 100644 index 0000000..5c8ef0d --- /dev/null +++ b/front/src/components/WANGEDITOR_UPLOAD.md @@ -0,0 +1,204 @@ +# WangEditor 文件上传功能说明 + +## 功能概述 + +WangEditor 组件现已集成文件上传功能,支持: +- **图片上传**:5MB 以内 +- **视频上传**:100MB 以内 +- **附件上传**:50MB 以内 + +所有文件都会上传到服务器并保存在 `front/uploads` 目录下,按照日期自动分类。 + +## 已实现的功能 + +### 1. 图片上传 +- 通过工具栏的图片按钮上传 +- 自动插入到编辑器中 +- 文件保存在服务器并生成可访问的 URL + +### 2. 视频上传 +- 通过工具栏的视频按钮上传 +- 自动插入视频播放器 +- 支持常见的视频格式 + +### 3. 附件上传 +- 支持所有文件类型 +- 自动生成下载链接 +- 文件名自动保留 + +## 技术实现 + +### 上传配置 + +```typescript +MENU_CONF: { + // 图片上传 + uploadImage: { + server: '/api/files', + fieldName: 'file', + headers: getAuthHeaders(), + customUpload: async (file, insertFn) => { + await handleUploadImage(file, insertFn); + }, + allowedFileTypes: ['image/*'], + maxFileSize: 5 * 1024 * 1024, + }, + // 视频上传 + uploadVideo: { + server: '/api/files', + fieldName: 'file', + headers: getAuthHeaders(), + customUpload: async (file, insertFn) => { + await handleUploadVideo(file, insertFn); + }, + allowedFileTypes: ['video/*'], + maxFileSize: 100 * 1024 * 1024, + }, + // 附件上传 + uploadAttachment: { + server: '/api/files', + fieldName: 'file', + headers: getAuthHeaders(), + customUpload: async (file, insertFn) => { + await handleUploadAttachment(file, insertFn); + }, + allowedFileTypes: ['*'], + maxFileSize: 50 * 1024 * 1024, + }, +} +``` + +### 上传流程 + +1. **用户选择文件** → wangEditor 触发上传 +2. **创建 FormData** → 包装文件数据 +3. **调用 fileAPI** → 发送到后端 `/api/files` +4. **后端保存** → 文件保存到 `front/uploads/年/月/日/` +5. **返回 URL** → 后端返回文件访问 URL +6. **插入编辑器** → 将 URL 插入到编辑器内容中 + +### 后端响应格式 + +```json +{ + "success": true, + "message": "文件上传成功", + "data": { + "id": 1, + "file_url": "/uploads/2024/01/15/20240115143045_example.jpg", + "file_path": "uploads/2024/01/15/20240115143045_example.jpg", + "file_name": "example", + "original_name": "example.jpg", + "file_size": 102400, + "file_type": "image", + "file_ext": ".jpg", + "category": "编辑器" + } +} +``` + +## 使用方式 + +### 基础使用 + +```vue + + + +``` + +### 自定义配置 + +如果需要修改上传限制,可以编辑 `WangEditor.vue` 中的配置: + +```typescript +// 修改文件大小限制 +maxFileSize: 10 * 1024 * 1024, // 改为 10MB + +// 修改允许的文件类型 +allowedFileTypes: ['image/jpeg', 'image/png'], + +// 修改分类 +category: '自定义分类', +``` + +## 文件存储位置 + +所有上传的文件按日期分类存储在: + +``` +front/uploads/ +├── 2024/ +│ ├── 01/ +│ │ ├── 15/ +│ │ │ ├── 20240115143045_image.jpg +│ │ │ └── 20240115143046_video.mp4 +``` + +## 访问已上传的文件 + +上传后的文件可以通过以下 URL 访问: + +``` +http://localhost:8080/uploads/2024/01/15/20240115143045_image.jpg +``` + +## 注意事项 + +1. **文件大小限制** + - 图片:5MB + - 视频:100MB + - 附件:50MB + +2. **文件类型验证** + - 图片:所有图片格式 + - 视频:所有视频格式 + - 附件:所有文件格式 + +3. **认证要求** + - 需要用户登录才能上传 + - 自动携带 JWT Token + +4. **错误处理** + - 上传失败会显示错误消息 + - 成功后会显示成功提示 + +## 故障排除 + +### 上传失败 + +1. 检查网络连接 +2. 确认用户已登录 +3. 检查文件大小是否超限 +4. 查看浏览器控制台错误信息 + +### 图片不显示 + +1. 确认文件已成功上传 +2. 检查文件 URL 是否正确 +3. 确认服务器已配置静态文件访问 +4. 检查 CORS 配置 + +### 上传按钮不显示 + +1. 确认使用了正确的组件 +2. 检查编辑器初始化是否成功 +3. 查看浏览器控制台是否有错误 + +## 下一步改进建议 + +1. 添加上传进度条 +2. 支持拖拽上传 +3. 添加图片裁剪功能 +4. 支持粘贴图片上传 +5. 添加文件管理器功能 + diff --git a/front/src/components/WangEditor.vue b/front/src/components/WangEditor.vue index d946574..1318398 100644 --- a/front/src/components/WangEditor.vue +++ b/front/src/components/WangEditor.vue @@ -7,7 +7,9 @@ +``` + +## 文件访问 + +上传后的文件可以通过以下URL访问: + +``` +http://localhost:8080/uploads/2024/01/15/20240115143045_example.jpg +``` + +注意:需要配置 Beego 的静态文件服务来提供上传文件的访问。 + +在 `server/conf/app.conf` 中添加: + +```conf +# 文件上传目录 +StaticDir = /uploads:../front/uploads +``` + +## 安全注意事项 + +1. **文件大小限制**:建议在前端和后端都添加文件大小限制 +2. **文件类型验证**:根据业务需求限制允许上传的文件类型 +3. **文件名安全**:避免用户控制文件名造成安全问题 +4. **权限控制**:确保只有授权用户可以上传文件 +5. **存储位置**:考虑使用对象存储服务(如 OSS、S3)替代本地存储 + +## 数据库字段说明 + +`yz_files` 表的主要字段: + +- `file_path`: 相对路径,用于存储和访问文件 +- `file_url`: 访问URL +- `original_name`: 用户上传时的原始文件名 +- `file_name`: 去除扩展名的文件名 +- `file_type`: 文件类型(image, document, video, audio, archive, other) +- `category`: 用户自定义分类 + diff --git a/server/docs/UPLOAD_PATH.md b/server/docs/UPLOAD_PATH.md new file mode 100644 index 0000000..c8e4a23 --- /dev/null +++ b/server/docs/UPLOAD_PATH.md @@ -0,0 +1,164 @@ +# 文件上传路径说明 + +## 当前配置 + +### 文件保存路径 +文件保存在项目根目录的 `front/uploads/` 目录下,按照日期自动分类: + +``` +项目根目录/ +├── server/ +│ └── controllers/ +│ └── file.go (处理上传) +├── front/ +│ └── uploads/ ← 文件保存位置 +│ ├── 2024/ +│ │ └── 01/ +│ │ └── 15/ +│ │ └── 20240115143045_example.jpg +``` + +### 代码中的路径 + +在 `server/controllers/file.go` 的 `Post()` 方法中: + +```go +// 构造保存路径:../front/uploads/年/月/日/ +uploadDir := path.Join("..", "front", "uploads", datePath) +``` + +**说明**: +- `..` 表示从 server 目录向上一级到项目根目录 +- `front/uploads/` 是上传文件的根目录 +- `datePath` 是按日期自动生成的子目录(如 `2024/01/15`) + +### 静态文件访问配置 + +在 `server/conf/app.conf` 中: + +```conf +StaticDir = /uploads:../front/uploads +``` + +**说明**: +- `/uploads` 是 URL 访问路径 +- `../front/uploads` 是实际文件存储路径(相对于 server 目录) + +## 目录结构 + +### 保存到数据库的路径 +- `file_path`: `uploads/2024/01/15/20240115143045_example.jpg`(相对路径) +- `file_url`: `/uploads/2024/01/15/20240115143045_example.jpg`(URL 路径) + +### 实际文件系统路径 +``` +front/uploads/2024/01/15/20240115143045_example.jpg +``` + +### 访问 URL +``` +http://localhost:8080/uploads/2024/01/15/20240115143045_example.jpg +``` + +## 为什么使用相对路径 `..` + +由于项目结构是: +``` +yunzer_go/ +├── server/ ← 服务端代码 +└── front/ ← 前端代码和上传文件 + └── uploads/ +``` + +从 `server` 目录运行应用时,要访问 `front/uploads`,需要使用 `../front/uploads`。 + +## 如果路径不对怎么办? + +### 方案1:修改代码中的路径 +如果您的项目启动目录不同,可以修改 `file.go` 中的路径: + +```go +// 如果从项目根目录运行 +uploadDir := path.Join("front", "uploads", datePath) + +// 或者使用绝对路径 +uploadDir := path.Join("/path/to/project", "front", "uploads", datePath) +``` + +### 方案2:从配置文件读取 +在 `app.conf` 中添加配置: + +```conf +# 上传文件目录 +uploadDir = ../front/uploads +``` + +然后在代码中读取: + +```go +import "github.com/beego/beego/v2/server/web" + +uploadDir := path.Join( + web.AppConfig.String("uploadDir"), + datePath, +) +``` + +## 验证路径是否正确 + +### 1. 检查文件保存位置 +上传一个文件后,查看文件是否在正确的位置: + +```bash +ls front/uploads/ +``` + +应该看到按日期分类的文件夹和文件。 + +### 2. 检查数据库记录 +查看 `yz_files` 表中的 `file_path` 字段: + +```sql +SELECT file_path, file_url FROM yz_files ORDER BY upload_time DESC LIMIT 1; +``` + +应该看到类似: +``` +file_path: uploads/2024/01/15/20240115143045_example.jpg +file_url: /uploads/2024/01/15/20240115143045_example.jpg +``` + +### 3. 检查 URL 访问 +直接在浏览器访问: + +``` +http://localhost:8080/uploads/2024/01/15/文件名 +``` + +如果能看到文件,说明路径配置正确。 + +## 常见问题 + +### Q: 文件保存在了 server/front/uploads? +A: 修改代码中的路径为 `../front/uploads`(已经修改) + +### Q: 文件保存在了 front/front/uploads? +A: 检查当前工作目录,确保在 server 目录运行应用 + +### Q: 访问文件返回 404? +A: 检查 `app.conf` 中的 StaticDir 配置是否正确 + +### Q: 权限问题? +A: 确保应用有创建目录和写入文件的权限: +```bash +chmod 755 front/uploads +``` + +## 建议的改进 + +如果需要更可靠的路径处理,可以考虑: + +1. **使用绝对路径**:从配置文件或环境变量读取项目根目录 +2. **路径验证**:在应用启动时检查上传目录是否存在,不存在则创建 +3. **日志记录**:记录文件保存的完整路径,便于调试 + diff --git a/server/routers/router.go b/server/routers/router.go index 1eb1cf7..f0857f1 100644 --- a/server/routers/router.go +++ b/server/routers/router.go @@ -79,8 +79,15 @@ func init() { // 程序信息路由 - 自动映射到 /api/programinfo/* beego.AutoRouter(&controllers.ProgramInfoController{}) - // 文件管理路由 - 自动映射到 /api/file/* - beego.AutoRouter(&controllers.FileController{}) + // 文件管理路由 - 手动配置以匹配前端的 /api/files 路径 + beego.Router("/api/files", &controllers.FileController{}, "get:GetAllFiles") + beego.Router("/api/files", &controllers.FileController{}, "post:Post") + beego.Router("/api/files/my", &controllers.FileController{}, "get:GetMyFiles") + beego.Router("/api/files/:id", &controllers.FileController{}, "get:GetFileById") + beego.Router("/api/files/:id", &controllers.FileController{}, "put:UpdateFile") + beego.Router("/api/files/:id", &controllers.FileController{}, "delete:DeleteFile") + beego.Router("/api/files/search", &controllers.FileController{}, "get:SearchFiles") + beego.Router("/api/files/statistics", &controllers.FileController{}, "get:GetFileStatistics") // 知识库路由 beego.Router("/api/knowledge/list", &controllers.KnowledgeController{}, "get:List") diff --git a/server/uploads/2025/10/28/20251028171712_AgAAERKKR6hmj84U7U9Kra9qKQ1fsrts.png b/server/uploads/2025/10/28/20251028171712_AgAAERKKR6hmj84U7U9Kra9qKQ1fsrts.png new file mode 100644 index 0000000..2d50574 Binary files /dev/null and b/server/uploads/2025/10/28/20251028171712_AgAAERKKR6hmj84U7U9Kra9qKQ1fsrts.png differ diff --git a/文件上传功能实现总结.md b/文件上传功能实现总结.md new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/文件上传功能实现总结.md @@ -0,0 +1 @@ + \ No newline at end of file