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:
375
check-vben-menus.js
Normal file
375
check-vben-menus.js
Normal file
@@ -0,0 +1,375 @@
|
||||
const { chromium } = require('playwright');
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
|
||||
// 菜单项配置
|
||||
const MENU_CONFIG = [
|
||||
// 仪表板
|
||||
{ name: '仪表板', path: '/dashboard/home', selector: 'text=仪表板' },
|
||||
|
||||
// 账号管理
|
||||
{ name: 'TG账号列表', path: '/account-manage/list', selector: 'text=TG账号列表' },
|
||||
{ name: 'TG账号用途', path: '/account-manage/usage', selector: 'text=TG账号用途' },
|
||||
{ name: 'Telegram用户列表', path: '/account-manage/telegram-users', selector: 'text=Telegram用户列表' },
|
||||
{ name: '统一注册系统', path: '/account-manage/unified-register', selector: 'text=统一注册系统' },
|
||||
{ name: 'Telegram指南', path: '/account-manage/guide', selector: 'text=Telegram指南' },
|
||||
{ name: 'Telegram快速访问', path: '/account-manage/quick-access', selector: 'text=Telegram快速访问' },
|
||||
{ name: 'Telegram聊天', path: '/account-manage/telegram-chat', selector: 'text=Telegram聊天' },
|
||||
{ name: 'Telegram网页版', path: '/account-manage/telegram-web', selector: 'text=Telegram网页版' },
|
||||
{ name: 'Telegram网页版(全屏)', path: '/account-manage/telegram-full', selector: 'text=Telegram网页版(全屏)' },
|
||||
|
||||
// 名称管理
|
||||
{ name: '名字列表', path: '/name-management/firstname', selector: 'text=名字列表' },
|
||||
{ name: '姓氏列表', path: '/name-management/lastname', selector: 'text=姓氏列表' },
|
||||
{ name: '统一名称管理', path: '/name-management/unified', selector: 'text=统一名称管理' },
|
||||
|
||||
// 群组管理
|
||||
{ name: '群组列表', path: '/group-config/list', selector: 'text=群组列表' },
|
||||
{ name: '群组成员', path: '/group-config/members', selector: 'text=群组成员' },
|
||||
{ name: '群组设置', path: '/group-config/sets', selector: 'text=群组设置' },
|
||||
|
||||
// 消息管理
|
||||
{ name: '消息列表', path: '/message-management/list', selector: 'text=消息列表' },
|
||||
|
||||
// 营销中心
|
||||
{ name: '营销控制台', path: '/marketing-center/dashboard', selector: 'text=营销控制台' },
|
||||
{ name: '智能群发', path: '/marketing-center/smart-campaign', selector: 'text=智能群发' },
|
||||
{ name: '统一账号管理', path: '/marketing-center/integrated-account', selector: 'text=统一账号管理' },
|
||||
{ name: '账号池管理', path: '/marketing-center/account-pool', selector: 'text=账号池管理' },
|
||||
{ name: '风控中心', path: '/marketing-center/risk-control', selector: 'text=风控中心' },
|
||||
{ name: '监控中心', path: '/marketing-center/monitoring', selector: 'text=监控中心' },
|
||||
|
||||
// 私信群发
|
||||
{ name: '任务列表', path: '/direct-message/task-list', selector: 'text=任务列表' },
|
||||
{ name: '创建任务', path: '/direct-message/create-task', selector: 'text=创建任务' },
|
||||
{ name: '模板列表', path: '/direct-message/template-list', selector: 'text=模板列表' },
|
||||
{ name: '创建模板', path: '/direct-message/create-template', selector: 'text=创建模板' },
|
||||
{ name: '引擎控制', path: '/direct-message/engine-control', selector: 'text=引擎控制' },
|
||||
{ name: '统计分析', path: '/direct-message/statistics', selector: 'text=统计分析' },
|
||||
|
||||
// 群发广播
|
||||
{ name: '广播任务', path: '/group-broadcast/task', selector: 'text=广播任务' },
|
||||
{ name: '广播日志', path: '/group-broadcast/log', selector: 'text=广播日志' },
|
||||
|
||||
// 炒群营销
|
||||
{ name: '剧本列表', path: '/group-marketing/script', selector: 'text=剧本列表' },
|
||||
{ name: '营销项目', path: '/group-marketing/project', selector: 'text=营销项目' },
|
||||
|
||||
// 短信平台
|
||||
{ name: '短信仪表板', path: '/sms-platform/dashboard', selector: 'text=短信仪表板' },
|
||||
{ name: '平台管理', path: '/sms-platform/platform-list', selector: 'text=平台管理' },
|
||||
{ name: '发送记录', path: '/sms-platform/records', selector: 'text=发送记录' },
|
||||
{ name: '统计分析', path: '/sms-platform/statistics', selector: 'text=统计分析' },
|
||||
{ name: '价格对比', path: '/sms-platform/price-compare', selector: 'text=价格对比' },
|
||||
{ name: '快速操作', path: '/sms-platform/quick-actions', selector: 'text=快速操作' },
|
||||
{ name: '余额报警', path: '/sms-platform/balance-alert', selector: 'text=余额报警' },
|
||||
|
||||
// 日志管理
|
||||
{ name: '注册日志', path: '/log-manage/register', selector: 'text=注册日志' },
|
||||
{ name: '用户登录', path: '/log-manage/user-login', selector: 'text=用户登录' },
|
||||
{ name: '用户注册', path: '/log-manage/user-register', selector: 'text=用户注册' },
|
||||
{ name: '群发日志', path: '/log-manage/group-send', selector: 'text=群发日志' },
|
||||
{ name: '群组加入', path: '/log-manage/group-join', selector: 'text=群组加入' },
|
||||
{ name: 'TG登录验证码', path: '/log-manage/login-code', selector: 'text=TG登录验证码' },
|
||||
{ name: '拉群成员', path: '/log-manage/pull-member', selector: 'text=拉群成员' },
|
||||
{ name: '拉群统计', path: '/log-manage/pull-member-statistic', selector: 'text=拉群统计' },
|
||||
{ name: '拉群项目统计', path: '/log-manage/pull-member-project-statistic', selector: 'text=拉群项目统计' },
|
||||
|
||||
// 系统配置
|
||||
{ name: '系统参数', path: '/system-config/params', selector: 'text=系统参数' },
|
||||
{ name: '通用设置', path: '/system-config/base-config', selector: 'text=通用设置' },
|
||||
{ name: '数据中心', path: '/system-config/dc-list', selector: 'text=数据中心' }
|
||||
];
|
||||
|
||||
class VbenMenuChecker {
|
||||
constructor() {
|
||||
this.baseUrl = 'http://localhost:5173';
|
||||
this.results = [];
|
||||
this.screenshots = [];
|
||||
this.browser = null;
|
||||
this.context = null;
|
||||
this.page = null;
|
||||
}
|
||||
|
||||
async init() {
|
||||
console.log('🚀 启动浏览器...');
|
||||
this.browser = await chromium.launch({
|
||||
headless: false,
|
||||
slowMo: 500
|
||||
});
|
||||
this.context = await this.browser.newContext({
|
||||
viewport: { width: 1920, height: 1080 }
|
||||
});
|
||||
this.page = await this.context.newPage();
|
||||
|
||||
// 监听网络请求
|
||||
this.page.on('response', (response) => {
|
||||
const url = response.url();
|
||||
if (url.includes('/api/') && !response.ok()) {
|
||||
console.log(`⚠️ API 请求失败: ${url} - ${response.status()}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async login() {
|
||||
console.log('🔑 开始登录...');
|
||||
try {
|
||||
await this.page.goto(this.baseUrl);
|
||||
await this.page.waitForLoadState('networkidle');
|
||||
|
||||
// 检查是否已经登录
|
||||
try {
|
||||
if (await this.page.locator('text=仪表板').first().isVisible({ timeout: 2000 })) {
|
||||
console.log('✅ 已经登录');
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
// 继续登录流程
|
||||
}
|
||||
|
||||
// 填写登录信息
|
||||
await this.page.fill('input[placeholder*="用户名"]', 'admin');
|
||||
await this.page.fill('input[placeholder*="密码"]', '111111');
|
||||
|
||||
// 点击登录按钮
|
||||
await this.page.click('button:has-text("登录")');
|
||||
await this.page.waitForLoadState('networkidle');
|
||||
|
||||
// 等待登录成功 - 等待页面跳转
|
||||
await this.page.waitForTimeout(3000);
|
||||
|
||||
// 检查是否登录成功(URL改变或出现菜单)
|
||||
const currentUrl = this.page.url();
|
||||
const hasMenu = await this.page.locator('.ant-menu, .vben-menu, [role="menu"]').count() > 0;
|
||||
const hasDashboard = await this.page.locator('text=仪表板').count() > 0;
|
||||
|
||||
if (!currentUrl.includes('/login') || hasMenu || hasDashboard) {
|
||||
console.log('✅ 登录成功,当前页面包含菜单组件');
|
||||
} else {
|
||||
throw new Error('登录后未找到预期的页面元素');
|
||||
}
|
||||
console.log('✅ 登录成功');
|
||||
|
||||
// 截图保存登录后状态
|
||||
await this.page.screenshot({
|
||||
path: `/Users/hahaha/telegram-management-system/test-screenshots/vben-after-login.png`,
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('❌ 登录失败:', error.message);
|
||||
await this.page.screenshot({
|
||||
path: `/Users/hahaha/telegram-management-system/test-screenshots/vben-login-error.png`,
|
||||
fullPage: true
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async checkMenu(menuItem) {
|
||||
console.log(`\n📋 检查菜单: ${menuItem.name}`);
|
||||
const result = {
|
||||
name: menuItem.name,
|
||||
path: menuItem.path,
|
||||
success: false,
|
||||
loadTime: 0,
|
||||
hasData: false,
|
||||
error: null,
|
||||
dataElements: 0,
|
||||
apiCalls: 0,
|
||||
screenshot: null
|
||||
};
|
||||
|
||||
try {
|
||||
const startTime = Date.now();
|
||||
|
||||
// 监听 API 调用
|
||||
let apiCallCount = 0;
|
||||
const apiListener = (response) => {
|
||||
if (response.url().includes('/api/')) {
|
||||
apiCallCount++;
|
||||
console.log(`🔄 API 调用: ${response.url()} - ${response.status()}`);
|
||||
}
|
||||
};
|
||||
this.page.on('response', apiListener);
|
||||
|
||||
// 导航到菜单页面
|
||||
await this.page.goto(`${this.baseUrl}${menuItem.path}`);
|
||||
await this.page.waitForLoadState('networkidle');
|
||||
|
||||
// 等待页面内容加载
|
||||
await this.page.waitForTimeout(2000);
|
||||
|
||||
const loadTime = Date.now() - startTime;
|
||||
result.loadTime = loadTime;
|
||||
result.apiCalls = apiCallCount;
|
||||
|
||||
// 检查页面是否有错误
|
||||
const hasError = await this.page.locator('.ant-result-error, .error, .ant-empty').count() > 0;
|
||||
|
||||
// 检查是否有数据表格或列表
|
||||
const tableCount = await this.page.locator('table, .ant-table, .ant-list, .card-list').count();
|
||||
const dataElements = await this.page.locator('td, li, .card-item').count();
|
||||
|
||||
result.dataElements = dataElements;
|
||||
result.hasData = dataElements > 0;
|
||||
result.success = !hasError && loadTime < 10000;
|
||||
|
||||
// 截图
|
||||
const screenshotPath = `/Users/hahaha/telegram-management-system/test-screenshots/vben-${menuItem.name.replace(/[\/\\]/g, '-')}.png`;
|
||||
await this.page.screenshot({
|
||||
path: screenshotPath,
|
||||
fullPage: true
|
||||
});
|
||||
result.screenshot = screenshotPath;
|
||||
|
||||
console.log(` ✅ 加载时间: ${loadTime}ms`);
|
||||
console.log(` 📊 数据元素: ${dataElements}个`);
|
||||
console.log(` 🌐 API调用: ${apiCallCount}次`);
|
||||
console.log(` 📷 截图: ${screenshotPath}`);
|
||||
|
||||
// 移除事件监听器
|
||||
this.page.off('response', apiListener);
|
||||
|
||||
} catch (error) {
|
||||
result.error = error.message;
|
||||
console.error(` ❌ 错误: ${error.message}`);
|
||||
|
||||
// 错误截图
|
||||
const errorScreenshotPath = `/Users/hahaha/telegram-management-system/test-screenshots/vben-error-${menuItem.name.replace(/[\/\\]/g, '-')}.png`;
|
||||
await this.page.screenshot({
|
||||
path: errorScreenshotPath,
|
||||
fullPage: true
|
||||
});
|
||||
result.screenshot = errorScreenshotPath;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async checkAllMenus() {
|
||||
console.log(`\n🎯 开始检查 ${MENU_CONFIG.length} 个菜单...\n`);
|
||||
|
||||
for (let i = 0; i < MENU_CONFIG.length; i++) {
|
||||
const menuItem = MENU_CONFIG[i];
|
||||
console.log(`[${i + 1}/${MENU_CONFIG.length}] 检查菜单: ${menuItem.name}`);
|
||||
|
||||
const result = await this.checkMenu(menuItem);
|
||||
this.results.push(result);
|
||||
|
||||
// 每检查5个菜单暂停一下
|
||||
if ((i + 1) % 5 === 0) {
|
||||
console.log(`⏸️ 已检查 ${i + 1} 个菜单,暂停2秒...`);
|
||||
await this.page.waitForTimeout(2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async generateReport() {
|
||||
console.log('\n📊 生成测试报告...');
|
||||
|
||||
const successCount = this.results.filter(r => r.success).length;
|
||||
const errorCount = this.results.filter(r => r.error).length;
|
||||
const dataCount = this.results.filter(r => r.hasData).length;
|
||||
const avgLoadTime = this.results.reduce((sum, r) => sum + r.loadTime, 0) / this.results.length;
|
||||
const totalApiCalls = this.results.reduce((sum, r) => sum + r.apiCalls, 0);
|
||||
|
||||
const report = {
|
||||
timestamp: new Date().toISOString(),
|
||||
summary: {
|
||||
total: this.results.length,
|
||||
success: successCount,
|
||||
errors: errorCount,
|
||||
hasData: dataCount,
|
||||
successRate: `${((successCount / this.results.length) * 100).toFixed(1)}%`,
|
||||
avgLoadTime: `${avgLoadTime.toFixed(0)}ms`,
|
||||
totalApiCalls
|
||||
},
|
||||
details: this.results.map(r => ({
|
||||
name: r.name,
|
||||
path: r.path,
|
||||
success: r.success,
|
||||
loadTime: `${r.loadTime}ms`,
|
||||
hasData: r.hasData,
|
||||
dataElements: r.dataElements,
|
||||
apiCalls: r.apiCalls,
|
||||
error: r.error,
|
||||
screenshot: r.screenshot
|
||||
}))
|
||||
};
|
||||
|
||||
// 保存报告
|
||||
await fs.writeFile(
|
||||
'/Users/hahaha/telegram-management-system/vben-menu-test-report.json',
|
||||
JSON.stringify(report, null, 2)
|
||||
);
|
||||
|
||||
// 打印摘要
|
||||
console.log('\n📈 测试摘要:');
|
||||
console.log(` 总菜单数: ${report.summary.total}`);
|
||||
console.log(` 成功加载: ${report.summary.success} (${report.summary.successRate})`);
|
||||
console.log(` 加载错误: ${report.summary.errors}`);
|
||||
console.log(` 有数据显示: ${report.summary.hasData}`);
|
||||
console.log(` 平均加载时间: ${report.summary.avgLoadTime}`);
|
||||
console.log(` API调用总数: ${report.summary.totalApiCalls}`);
|
||||
|
||||
// 打印有问题的菜单
|
||||
const problemMenus = this.results.filter(r => !r.success || r.error);
|
||||
if (problemMenus.length > 0) {
|
||||
console.log('\n⚠️ 有问题的菜单:');
|
||||
problemMenus.forEach(menu => {
|
||||
console.log(` - ${menu.name}: ${menu.error || '加载失败'}`);
|
||||
});
|
||||
}
|
||||
|
||||
// 打印无数据的菜单
|
||||
const noDataMenus = this.results.filter(r => r.success && !r.hasData);
|
||||
if (noDataMenus.length > 0) {
|
||||
console.log('\n📭 无数据显示的菜单:');
|
||||
noDataMenus.forEach(menu => {
|
||||
console.log(` - ${menu.name} (${menu.loadTime}ms)`);
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`\n📁 完整报告已保存到: vben-menu-test-report.json`);
|
||||
return report;
|
||||
}
|
||||
|
||||
async close() {
|
||||
if (this.browser) {
|
||||
await this.browser.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const checker = new VbenMenuChecker();
|
||||
|
||||
try {
|
||||
await checker.init();
|
||||
|
||||
const loginSuccess = await checker.login();
|
||||
if (!loginSuccess) {
|
||||
console.error('❌ 登录失败,无法继续测试');
|
||||
return;
|
||||
}
|
||||
|
||||
await checker.checkAllMenus();
|
||||
await checker.generateReport();
|
||||
|
||||
console.log('\n🎉 菜单检查完成!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 测试过程中发生错误:', error);
|
||||
} finally {
|
||||
await checker.close();
|
||||
}
|
||||
}
|
||||
|
||||
// 运行测试
|
||||
if (require.main === module) {
|
||||
main().catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = { VbenMenuChecker, MENU_CONFIG };
|
||||
Reference in New Issue
Block a user