Initial commit: Telegram Management System
Some checks failed
Deploy / deploy (push) Has been cancelled
Some checks failed
Deploy / deploy (push) Has been cancelled
Full-stack web application for Telegram management - Frontend: Vue 3 + Vben Admin - Backend: NestJS - Features: User management, group broadcast, statistics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
295
backend/demo_new_features.js
Normal file
295
backend/demo_new_features.js
Normal file
@@ -0,0 +1,295 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* 新姓名管理系统功能演示脚本
|
||||
* 逐个展示所有新开发的功能
|
||||
*/
|
||||
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
async function demoNewFeatures() {
|
||||
console.log('🎭 开始演示新开发的姓名管理系统功能...\n');
|
||||
|
||||
let browser;
|
||||
let page;
|
||||
|
||||
try {
|
||||
browser = await chromium.launch({
|
||||
headless: false,
|
||||
slowMo: 1500, // 慢一点,便于观察
|
||||
devtools: false
|
||||
});
|
||||
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1400, height: 900 }
|
||||
});
|
||||
|
||||
page = await context.newPage();
|
||||
|
||||
// 监听所有姓名相关的API调用
|
||||
page.on('request', request => {
|
||||
const url = request.url();
|
||||
if (url.includes('/nameTemplate/') || url.includes('/firstname/') || url.includes('/lastname/')) {
|
||||
console.log(`🔗 API请求: ${request.method()} ${url}`);
|
||||
}
|
||||
});
|
||||
|
||||
page.on('response', response => {
|
||||
const url = response.url();
|
||||
if (url.includes('/nameTemplate/') || url.includes('/firstname/') || url.includes('/lastname/')) {
|
||||
console.log(`📡 API响应: ${response.status()} ${url}`);
|
||||
if (response.status() !== 200) {
|
||||
console.log(` ⚠️ 状态码: ${response.status()} ${response.statusText()}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ==================== 第1步:登录系统 ====================
|
||||
console.log('🚀 第1步:访问系统并登录...');
|
||||
await page.goto('http://localhost:8891');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// 登录
|
||||
await page.fill('input[type="text"]', 'admin');
|
||||
await page.fill('input[type="password"]', '111111');
|
||||
await page.click('button:has-text("登录")');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
console.log('✅ 登录成功!');
|
||||
await page.screenshot({ path: '01_logged_in.png', fullPage: true });
|
||||
console.log('📸 保存截图: 01_logged_in.png');
|
||||
|
||||
// ==================== 第2步:找到姓名管理菜单 ====================
|
||||
console.log('\n🔍 第2步:找到并点击姓名管理菜单...');
|
||||
|
||||
// 等待菜单加载
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找姓名管理菜单
|
||||
const nameMenu = await page.locator('text=名字管理').first();
|
||||
if (await nameMenu.isVisible()) {
|
||||
console.log('✅ 找到"名字管理"菜单');
|
||||
await nameMenu.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
console.log('🖱️ 点击进入姓名管理');
|
||||
} else {
|
||||
// 尝试其他可能的菜单名称
|
||||
const alternatives = ['text=姓名管理', 'text=姓名', 'text=名字', '[href*="firstname"]'];
|
||||
for (const alt of alternatives) {
|
||||
try {
|
||||
const menu = await page.locator(alt).first();
|
||||
if (await menu.isVisible({ timeout: 1000 })) {
|
||||
console.log(`✅ 找到菜单: ${alt}`);
|
||||
await menu.click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
// 继续尝试
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await page.screenshot({ path: '02_name_management_page.png', fullPage: true });
|
||||
console.log('📸 保存截图: 02_name_management_page.png');
|
||||
|
||||
// ==================== 第3步:演示新API的调用 ====================
|
||||
console.log('\n🔧 第3步:演示新开发的API接口...');
|
||||
|
||||
// 在浏览器控制台中调用新的API
|
||||
console.log('📡 调用新的supportedOptions API...');
|
||||
const supportedOptions = await page.evaluate(async () => {
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/nameTemplate/supportedOptions');
|
||||
const data = await response.json();
|
||||
return { status: response.status, data };
|
||||
} catch (error) {
|
||||
return { error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
console.log('✅ supportedOptions API响应:');
|
||||
console.log(' - 支持的平台:', supportedOptions.data?.data?.platforms?.length || 0, '个');
|
||||
console.log(' - 支持的文化:', supportedOptions.data?.data?.cultures?.length || 0, '个');
|
||||
console.log(' - 数据源类型:', supportedOptions.data?.data?.sources?.length || 0, '个');
|
||||
|
||||
// 调用生成器状态API
|
||||
console.log('\n📡 调用新的generatorStatus API...');
|
||||
const generatorStatus = await page.evaluate(async () => {
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/nameTemplate/generatorStatus');
|
||||
const data = await response.json();
|
||||
return { status: response.status, data };
|
||||
} catch (error) {
|
||||
return { error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
console.log('✅ generatorStatus API响应:');
|
||||
if (generatorStatus.data?.data) {
|
||||
Object.keys(generatorStatus.data.data).forEach(generator => {
|
||||
const info = generatorStatus.data.data[generator];
|
||||
console.log(` - ${generator}: ${info.available ? '✅可用' : '❌不可用'} (优先级: ${info.priority})`);
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 第4步:测试页面功能 ====================
|
||||
console.log('\n🧪 第4步:测试页面功能...');
|
||||
|
||||
// 检查页面元素
|
||||
const hasTable = await page.locator('table').isVisible();
|
||||
const hasAddButton = await page.locator('button:has-text("添加")').isVisible();
|
||||
const hasSearchBox = await page.locator('input[placeholder*="搜索"], input[placeholder*="姓"]').isVisible();
|
||||
|
||||
console.log('📊 页面功能检查:');
|
||||
console.log(` - 数据表格: ${hasTable ? '✅存在' : '❌缺失'}`);
|
||||
console.log(` - 添加按钮: ${hasAddButton ? '✅存在' : '❌缺失'}`);
|
||||
console.log(` - 搜索框: ${hasSearchBox ? '✅存在' : '❌缺失'}`);
|
||||
|
||||
// ==================== 第5步:尝试添加新姓名模板 ====================
|
||||
if (hasAddButton) {
|
||||
console.log('\n➕ 第5步:演示添加新姓名模板功能...');
|
||||
|
||||
try {
|
||||
await page.click('button:has-text("添加")');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 检查是否有弹窗
|
||||
const hasModal = await page.locator('.modal, .dialog, [class*="modal"]').isVisible();
|
||||
console.log(` - 添加弹窗: ${hasModal ? '✅打开' : '❌未找到'}`);
|
||||
|
||||
if (hasModal) {
|
||||
await page.screenshot({ path: '03_add_modal.png', fullPage: true });
|
||||
console.log('📸 保存截图: 03_add_modal.png');
|
||||
|
||||
// 尝试填写测试数据
|
||||
const nameInput = await page.locator('input[placeholder*="姓"], input[v-model*="name"]').first();
|
||||
if (await nameInput.isVisible()) {
|
||||
await nameInput.fill('测试姓氏');
|
||||
console.log('✏️ 填写测试姓氏');
|
||||
|
||||
await page.waitForTimeout(1000);
|
||||
await page.screenshot({ path: '04_filled_form.png', fullPage: true });
|
||||
console.log('📸 保存截图: 04_filled_form.png');
|
||||
|
||||
// 取消或关闭弹窗(不实际提交)
|
||||
const cancelButton = await page.locator('button:has-text("取消"), button:has-text("关闭")').first();
|
||||
if (await cancelButton.isVisible()) {
|
||||
await cancelButton.click();
|
||||
console.log('❌ 取消添加操作(演示完成)');
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(` ⚠️ 添加功能测试失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 第6步:检查数据列表 ====================
|
||||
console.log('\n📋 第6步:检查现有数据列表...');
|
||||
|
||||
if (hasTable) {
|
||||
// 统计表格行数
|
||||
const tableRows = await page.locator('table tbody tr').count();
|
||||
console.log(` - 数据行数: ${tableRows}`);
|
||||
|
||||
if (tableRows > 0) {
|
||||
// 获取表头信息
|
||||
const headers = await page.locator('table thead th').allTextContents();
|
||||
console.log(' - 表格列:', headers.filter(h => h.trim()).join(', '));
|
||||
|
||||
await page.screenshot({ path: '05_data_table.png', fullPage: true });
|
||||
console.log('📸 保存截图: 05_data_table.png');
|
||||
} else {
|
||||
console.log(' ℹ️ 表格为空,可能需要先添加数据');
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 第7步:测试搜索功能 ====================
|
||||
if (hasSearchBox) {
|
||||
console.log('\n🔍 第7步:测试搜索功能...');
|
||||
|
||||
try {
|
||||
const searchInput = await page.locator('input[placeholder*="搜索"], input[placeholder*="姓"]').first();
|
||||
await searchInput.fill('测试');
|
||||
console.log('🔍 输入搜索关键词: 测试');
|
||||
|
||||
// 触发搜索
|
||||
const searchButton = await page.locator('button:has-text("搜索")').first();
|
||||
if (await searchButton.isVisible()) {
|
||||
await searchButton.click();
|
||||
console.log('🔍 点击搜索按钮');
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await page.screenshot({ path: '06_search_result.png', fullPage: true });
|
||||
console.log('📸 保存截图: 06_search_result.png');
|
||||
}
|
||||
|
||||
// 清空搜索
|
||||
await searchInput.clear();
|
||||
console.log('🧹 清空搜索条件');
|
||||
} catch (error) {
|
||||
console.log(` ⚠️ 搜索功能测试失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 第8步:检查控制台错误 ====================
|
||||
console.log('\n🔍 第8步:检查页面控制台错误...');
|
||||
|
||||
// 收集控制台错误
|
||||
const consoleErrors = [];
|
||||
page.on('console', msg => {
|
||||
if (msg.type() === 'error') {
|
||||
consoleErrors.push(msg.text());
|
||||
}
|
||||
});
|
||||
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
if (consoleErrors.length > 0) {
|
||||
console.log('⚠️ 发现控制台错误:');
|
||||
consoleErrors.slice(-3).forEach((error, index) => {
|
||||
console.log(` ${index + 1}. ${error}`);
|
||||
});
|
||||
} else {
|
||||
console.log('✅ 无控制台错误');
|
||||
}
|
||||
|
||||
// ==================== 第9步:最终总结截图 ====================
|
||||
console.log('\n📸 第9步:生成最终演示截图...');
|
||||
await page.screenshot({ path: '07_final_demo.png', fullPage: true });
|
||||
console.log('📸 保存截图: 07_final_demo.png');
|
||||
|
||||
// ==================== 演示完成 ====================
|
||||
console.log('\n🎉 新功能演示完成!');
|
||||
console.log('📁 生成的截图文件:');
|
||||
console.log(' 01_logged_in.png - 登录后页面');
|
||||
console.log(' 02_name_management_page.png - 姓名管理页面');
|
||||
console.log(' 03_add_modal.png - 添加模态窗口');
|
||||
console.log(' 04_filled_form.png - 填写表单');
|
||||
console.log(' 05_data_table.png - 数据表格');
|
||||
console.log(' 06_search_result.png - 搜索结果');
|
||||
console.log(' 07_final_demo.png - 最终演示');
|
||||
|
||||
console.log('\n⏰ 浏览器将保持打开10秒供最后观察...');
|
||||
await page.waitForTimeout(10000);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 演示失败:', error.message);
|
||||
if (page) {
|
||||
await page.screenshot({ path: 'demo_error.png', fullPage: true });
|
||||
console.log('📸 错误截图: demo_error.png');
|
||||
}
|
||||
} finally {
|
||||
if (browser) {
|
||||
await browser.close();
|
||||
}
|
||||
console.log('🏁 演示结束');
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
demoNewFeatures().catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = demoNewFeatures;
|
||||
Reference in New Issue
Block a user