feat: 项目结构调整|新增依赖

This commit is contained in:
duanshuwen
2025-11-22 21:17:40 +08:00
parent 38b6a4b4a3
commit 6013c38fe7
40 changed files with 535 additions and 115 deletions

View File

@@ -0,0 +1,247 @@
const { chromium } = require('playwright');
const fs = require('fs');
const path = require('path');
// 录制配置
const recordingConfig = {
outputFile: 'recorded-steps.json',
headless: false, // 显示浏览器窗口
slowMo: 100, // 减慢操作速度,便于观察
viewport: { width: 1280, height: 720 }
};
// 存储录制的步骤
let recordedSteps = [];
let recordingStartTime = Date.now();
let isRecording = true;
// 生成时间戳
function getTimestamp() {
return Date.now() - recordingStartTime;
}
// 记录步骤
function recordStep(step) {
const stepWithTimestamp = {
...step,
timestamp: getTimestamp()
};
recordedSteps.push(stepWithTimestamp);
console.log(`📹 录制步骤: ${step.type} - ${step.description}`);
}
// 保存录制的步骤到文件
function saveRecordedSteps() {
const outputPath = path.join(__dirname, recordingConfig.outputFile);
const data = {
steps: recordedSteps,
metadata: {
totalSteps: recordedSteps.length,
duration: getTimestamp(),
recordedAt: new Date().toISOString()
}
};
fs.writeFileSync(outputPath, JSON.stringify(data, null, 2));
console.log(`\n✅ 录制完成!共录制 ${recordedSteps.length} 个步骤`);
console.log(`📁 录制文件已保存到: ${outputPath}`);
}
// 监听页面事件
async function setupPageListeners(page) {
// 监听点击事件
await page.exposeFunction('__recordClick', (selector, coordinates) => {
if (!isRecording) return;
recordStep({
type: 'click',
description: `点击元素: ${selector || '未知元素'}`,
selector: selector || '',
coordinates: coordinates || {}
});
});
// 监听输入事件
await page.exposeFunction('__recordInput', (selector, text) => {
if (!isRecording) return;
recordStep({
type: 'type',
description: `输入文本: "${text || ''}"`,
selector: selector || '',
text: text || ''
});
});
// 注入脚本监听用户操作
await page.addInitScript(() => {
// 监听点击事件
document.addEventListener('click', (event) => {
const target = event.target;
const selector = generateSelector(target);
const coordinates = { x: event.clientX, y: event.clientY };
if (window.__recordClick) {
window.__recordClick(selector, coordinates);
}
}, true);
// 监听输入事件
document.addEventListener('input', (event) => {
const target = event.target;
const selector = generateSelector(target);
const text = target.value || target.textContent || '';
if (window.__recordInput) {
window.__recordInput(selector, text);
}
}, true);
// 生成元素选择器
function generateSelector(element) {
if (!element) return '';
// 优先使用 ID
if (element.id) {
return `#${element.id}`;
}
// 使用 class 和标签名
const tagName = element.tagName.toLowerCase();
if (element.className) {
const classes = element.className.split(' ').filter(c => c.trim());
if (classes.length > 0) {
return `${tagName}.${classes.join('.')}`;
}
}
// 使用属性
const attributes = ['name', 'placeholder', 'type'];
for (const attr of attributes) {
if (element.getAttribute(attr)) {
return `${tagName}[${attr}="${element.getAttribute(attr)}"]`;
}
}
// 使用路径
return getElementPath(element);
}
function getElementPath(element) {
const path = [];
while (element && element.nodeType === Node.ELEMENT_NODE) {
let selector = element.nodeName.toLowerCase();
if (element.id) {
selector += `#${element.id}`;
path.unshift(selector);
break;
} else {
let sibling = element;
let nth = 1;
while (sibling = sibling.previousElementSibling) {
if (sibling.nodeName.toLowerCase() === selector) nth++;
}
if (nth !== 1) selector += `:nth-of-type(${nth})`;
}
path.unshift(selector);
element = element.parentNode;
}
return path.join(' > ');
}
});
}
// 主录制函数
async function startRecording() {
console.log('🎬 开始自动化录制...');
console.log('请在浏览器中进行操作,系统会自动记录您的操作步骤');
console.log('按 Ctrl+C 停止录制并保存结果\n');
let browser;
let page;
try {
// 启动浏览器
browser = await chromium.launch({
headless: recordingConfig.headless,
slowMo: recordingConfig.slowMo
});
// 创建新页面
page = await browser.newPage({
viewport: recordingConfig.viewport
});
// 设置页面监听器
await setupPageListeners(page);
// 监听页面导航
page.on('framenavigated', async (frame) => {
if (frame === page.mainFrame() && isRecording) {
recordStep({
type: 'navigate',
description: `导航到: ${frame.url()}`,
url: frame.url()
});
// 重新设置监听器
await setupPageListeners(page);
}
});
// 导航到百度首页作为起始页面
console.log('🌐 正在打开百度首页...');
await page.goto('https://www.baidu.com');
recordStep({
type: 'navigate',
description: '打开百度首页',
url: 'https://www.baidu.com'
});
console.log('✅ 录制已启动!请在浏览器中进行操作...');
console.log('💡 您可以:');
console.log(' - 点击页面元素');
console.log(' - 在输入框中输入文本');
console.log(' - 导航到其他页面');
console.log(' - 按回车键或其他键盘操作');
console.log('');
console.log('⚠️ 按 Ctrl+C 停止录制并保存结果');
// 保持浏览器打开,直到用户手动停止
await new Promise((resolve) => {
process.on('SIGINT', () => {
console.log('\n🛑 用户停止录制');
isRecording = false;
resolve();
});
});
} catch (error) {
console.error('❌ 录制过程中发生错误:', error);
} finally {
if (browser) {
// 保存录制的步骤
saveRecordedSteps();
await browser.close();
}
}
}
// 处理程序终止
process.on('SIGINT', () => {
console.log('\n🛑 用户停止录制');
saveRecordedSteps();
process.exit(0);
});
process.on('SIGTERM', () => {
console.log('\n🛑 程序终止');
saveRecordedSteps();
process.exit(0);
});
// 启动录制
(async () => {
await startRecording();
})();