/** * 路径解析工具 * 解决开发环境下路径解析问题 */ import path from 'path'; import fs from 'fs'; import { fileURLToPath } from 'url'; /** * 获取项目根目录 * 通过从当前文件向上查找 package.json 来确定 */ export function getProjectRoot(): string { // 在开发环境使用 tsx 时,使用 process.cwd() // 在构建后的环境,使用 __dirname 的方式 let currentDir: string; try { // ESM 模式下获取当前文件目录 const __filename = fileURLToPath(import.meta.url); currentDir = path.dirname(__filename); } catch { // 回退到 process.cwd() currentDir = process.cwd(); } // Windows 路径处理(去除开头的 /) if (process.platform === 'win32' && currentDir.startsWith('/') && /^[a-zA-Z]:/.test(currentDir.slice(1))) { currentDir = currentDir.substring(1); } // 从当前目录向上查找 package.json let searchDir = currentDir; for (let i = 0; i < 10; i++) { const pkgPath = path.join(searchDir, 'package.json'); if (fs.existsSync(pkgPath)) { return searchDir; } searchDir = path.dirname(searchDir); } // 如果找不到,回退到 process.cwd() return process.cwd(); } /** * 获取上传目录的绝对路径 */ export function getUploadsDir(): string { const projectRoot = getProjectRoot(); return path.join(projectRoot, 'uploads'); } /** * 解析图片路径 * 将数据库中存储的路径 (/uploads/xxx.png) 解析为绝对路径 */ export function resolveImagePath(imagePath: string): string { // 在 Windows 上,path.isAbsolute 会将 /uploads/... 认为是绝对路径 // 但这实际上是 Unix 风格的相对路径,需要特殊处理 const isWindowsAbsPath = process.platform === 'win32' ? /^[a-zA-Z]:\\/.test(imagePath) // Windows 真正的绝对路径如 C:\ : path.isAbsolute(imagePath); if (isWindowsAbsPath) { return imagePath; } // 处理 /uploads/ 开头的相对路径 if (imagePath.startsWith('/uploads/')) { return path.join(getUploadsDir(), imagePath.replace('/uploads/', '')); } // 其他相对路径,使用项目根目录 return path.join(getProjectRoot(), imagePath); } /** * 生成存储到数据库的路径 */ export function generateDbPath(filename: string): string { return `/uploads/${filename}`; }