diff --git a/bun.lockb b/bun.lockb index 649d0f4..271c91e 100644 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/database/development.sqlite3-shm b/database/development.sqlite3-shm index 005896d..3827c87 100644 Binary files a/database/development.sqlite3-shm and b/database/development.sqlite3-shm differ diff --git a/database/development.sqlite3-wal b/database/development.sqlite3-wal index e19f5ca..bc8a314 100644 Binary files a/database/development.sqlite3-wal and b/database/development.sqlite3-wal differ diff --git a/package.json b/package.json index cbb4de0..c5fa221 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "consolidate": "^1.0.4", "formidable": "^3.5.4", "get-paths": "^0.0.7", + "image-thumbnail": "^1.0.17", "jsonwebtoken": "^9.0.0", "knex": "^3.1.0", "koa": "^3.0.0", diff --git a/src/controllers/Page/PageController.js b/src/controllers/Page/PageController.js index 793975c..bfffa90 100644 --- a/src/controllers/Page/PageController.js +++ b/src/controllers/Page/PageController.js @@ -10,6 +10,7 @@ import { fileURLToPath } from "url" import CommonError from "@/utils/error/CommonError" import { logger } from "@/logger.js" import { R } from "@/utils/helper" +import imageThumbnail from "image-thumbnail" class PageController { constructor() { @@ -257,13 +258,16 @@ class PageController { { mime: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ext: ".xlsx" }, // .xlsx { mime: "application/vnd.ms-excel", ext: ".xls" }, // .xls { mime: "application/msword", ext: ".doc" }, // .doc - { mime: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ext: ".docx" } // .docx + { mime: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ext: ".docx" }, // .docx ] let typeList = defaultTypeList // 支持通过ctx.query.allowedTypes自定义类型(逗号分隔,自动过滤无效类型) if (ctx.query.allowedTypes) { - const allowed = ctx.query.allowedTypes.split(",").map(t => t.trim()).filter(Boolean) + const allowed = ctx.query.allowedTypes + .split(",") + .map(t => t.trim()) + .filter(Boolean) typeList = defaultTypeList.filter(item => allowed.includes(item.mime)) } @@ -308,7 +312,7 @@ class PageController { ext = path.extname(picked.originalFilename || picked.newFilename || "") || fallbackExt } // 文件名 - const filename = `${ctx.session.user.id}-${Date.now()}-${Math.random().toString(36).slice(2,8)}${ext}` + const filename = `${ctx.session.user.id}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}` const destPath = path.join(uploadsDir, filename) // 如果设置了 uploadDir 且 keepExtensions,文件可能已在该目录,仍统一重命名 if (oldPath && oldPath !== destPath) { @@ -368,18 +372,27 @@ class PageController { // formidable v2 的文件对象 const oldPath = picked.filepath || picked.path + const result = { url: "", thumb: "" } const ext = path.extname(picked.originalFilename || picked.newFilename || "") || path.extname(oldPath || "") || ".jpg" const safeExt = [".jpg", ".jpeg", ".png", ".webp", ".gif"].includes(ext.toLowerCase()) ? ext : ".jpg" - const filename = `${ctx.session.user.id}-${Date.now()}${safeExt}` + const filename = `${ctx.session.user.id}-${Date.now()}/raw${safeExt}` const destPath = path.join(avatarsDir, filename) // 如果设置了 uploadDir 且 keepExtensions,文件可能已在该目录,仍统一重命名 if (oldPath && oldPath !== destPath) { + await fs.mkdir(path.parse(destPath).dir, { recursive: true }) await fs.rename(oldPath, destPath) + try { + const thumbnail = await imageThumbnail(destPath) + fs.writeFile(destPath.replace(/raw\./, "thumb."), thumbnail) + } catch (err) { + console.error(err) + } } const url = `/uploads/avatars/${filename}` - + result.url = url + result.thumb = url.replace(/raw\./, "thumb.") const updatedUser = await this.userService.updateUser(ctx.session.user.id, { avatar: url }) ctx.session.user = { ...ctx.session.user, ...updatedUser } @@ -387,6 +400,7 @@ class PageController { success: true, message: "头像上传成功", url, + thumb: result.thumb, user: updatedUser, } } catch (error) {