Spaces:
Running
Running
import fs from 'fs'; | |
import path from 'path'; | |
// 日志文件路径 | |
const LOG_FILE = './logs/app.log'; | |
const LOG_DIR = './logs'; | |
/** | |
* 确保日志目录存在 | |
*/ | |
function ensureLogDirectory() { | |
if (!fs.existsSync(LOG_DIR)) { | |
fs.mkdirSync(LOG_DIR, { recursive: true }); | |
} | |
} | |
/** | |
* 写入日志到文件 | |
* @param {string} level - 日志级别 (INFO, ERROR, WARN) | |
* @param {string} message - 日志消息 | |
*/ | |
export function writeLog(level, message) { | |
ensureLogDirectory(); | |
const timestamp = new Date().toISOString(); | |
const logEntry = `[${timestamp}] [${level}] ${message}\n`; | |
try { | |
fs.appendFileSync(LOG_FILE, logEntry); | |
} catch (error) { | |
console.error('写入日志文件失败:', error); | |
} | |
} | |
/** | |
* 增强的 console.log,同时输出到控制台和文件 | |
* @param {...any} args - 要记录的参数 | |
*/ | |
export function log(...args) { | |
const message = args.map(arg => | |
typeof arg === 'object' ? JSON.stringify(arg) : String(arg) | |
).join(' '); | |
console.log(...args); | |
writeLog('INFO', message); | |
} | |
/** | |
* 增强的 console.error,同时输出到控制台和文件 | |
* @param {...any} args - 要记录的参数 | |
*/ | |
export function logError(...args) { | |
const message = args.map(arg => | |
typeof arg === 'object' ? JSON.stringify(arg) : String(arg) | |
).join(' '); | |
console.error(...args); | |
writeLog('ERROR', message); | |
} | |
/** | |
* 读取最近的日志 | |
* @param {number} lines - 要读取的行数,默认100行 | |
* @returns {Array} 日志行数组 | |
*/ | |
export function getRecentLogs(lines = 100) { | |
try { | |
if (!fs.existsSync(LOG_FILE)) { | |
return []; | |
} | |
const content = fs.readFileSync(LOG_FILE, 'utf8'); | |
const logLines = content.trim().split('\n').filter(line => line.length > 0); | |
// 返回最后 N 行 | |
return logLines.slice(-lines); | |
} catch (error) { | |
console.error('读取日志文件失败:', error); | |
return []; | |
} | |
} | |
/** | |
* 创建人类可读的时间戳 | |
* @returns {string} 格式化的时间戳 YYYY-MM-DD_HH-MM-SS | |
*/ | |
export function getHumanReadableTimestamp() { | |
const now = new Date(); | |
const year = now.getFullYear(); | |
const month = String(now.getMonth() + 1).padStart(2, '0'); | |
const day = String(now.getDate()).padStart(2, '0'); | |
const hours = String(now.getHours()).padStart(2, '0'); | |
const minutes = String(now.getMinutes()).padStart(2, '0'); | |
const seconds = String(now.getSeconds()).padStart(2, '0'); | |
return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`; | |
} | |
/** | |
* 确保截图目录存在 | |
* @param {string} dir - 目录路径 | |
*/ | |
export function ensureScreenshotDirectory(dir) { | |
if (!fs.existsSync(dir)) { | |
fs.mkdirSync(dir, { recursive: true }); | |
console.log(`创建截图目录: ${dir}`); | |
} | |
} | |
/** | |
* 检查 Cookie 文件是否存在 | |
* @param {string} cookieFile - Cookie 文件路径 | |
* @returns {boolean} 文件是否存在 | |
*/ | |
export function checkCookieFile(cookieFile) { | |
if (!fs.existsSync(cookieFile)) { | |
console.error(`Cookie文件不存在: ${cookieFile}`); | |
console.log('请先运行 npm run login 进行登录'); | |
return false; | |
} | |
return true; | |
} | |
/** | |
* 读取并解析 Cookie 文件 | |
* @param {string} cookieFile - Cookie 文件路径 | |
* @returns {Array} Cookie 数组 | |
*/ | |
export function loadCookies(cookieFile) { | |
try { | |
const cookies = JSON.parse(fs.readFileSync(cookieFile, 'utf8')); | |
console.log(`已加载 ${cookies.length} 个cookies`); | |
return cookies; | |
} catch (error) { | |
console.error('读取 Cookie 文件失败:', error); | |
throw error; | |
} | |
} | |
/** | |
* 保存截图 | |
* @param {Object} page - Playwright 页面对象 | |
* @param {string} screenshotDir - 截图目录 | |
* @param {string} prefix - 文件名前缀 | |
* @returns {string} 截图文件路径 | |
*/ | |
export async function saveScreenshot(page, screenshotDir, prefix = 'screenshot') { | |
ensureScreenshotDirectory(screenshotDir); | |
const timestamp = getHumanReadableTimestamp(); | |
const screenshotPath = path.join(screenshotDir, `${prefix}-${timestamp}.png`); | |
await page.screenshot({ path: screenshotPath }); | |
console.log(`截图已保存: ${screenshotPath}`); | |
return screenshotPath; | |
} | |