File size: 4,132 Bytes
f9e1174
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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;
}