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:
191
frontend/public/test-export-page.html
Normal file
191
frontend/public/test-export-page.html
Normal file
@@ -0,0 +1,191 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>TG账号导出测试</title>
|
||||
<meta charset="utf-8">
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@3"></script>
|
||||
<script src="https://unpkg.com/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
|
||||
<style>
|
||||
body { font-family: Arial; padding: 20px; }
|
||||
button { padding: 10px 20px; margin: 10px; cursor: pointer; }
|
||||
.success { color: green; }
|
||||
.error { color: red; }
|
||||
#log {
|
||||
background: #f5f5f5;
|
||||
padding: 10px;
|
||||
margin: 20px 0;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h1>TG账号导出功能测试</h1>
|
||||
|
||||
<div>
|
||||
<h2>测试步骤:</h2>
|
||||
<button @click="step1">1. 获取账号数据</button>
|
||||
<button @click="step2" :disabled="!accounts.length">2. 导出为Excel</button>
|
||||
<button @click="step3" :disabled="!accounts.length">3. 导出为CSV</button>
|
||||
<button @click="testAll">一键测试全部</button>
|
||||
<button @click="clearLog">清空日志</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>导出选项:</h2>
|
||||
<label>
|
||||
<input type="radio" v-model="exportRange" value="all"> 导出全部
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" v-model="exportRange" value="first10"> 只导出前10条
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>数据统计:</h2>
|
||||
<p>获取到账号数量:{{ accounts.length }}</p>
|
||||
<p v-if="accounts.length">第一条数据:{{ accounts[0] ? accounts[0].phone : '' }}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>日志输出:</h2>
|
||||
<div id="log" v-html="logContent"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const { createApp } = Vue;
|
||||
|
||||
createApp({
|
||||
data() {
|
||||
return {
|
||||
accounts: [],
|
||||
exportRange: 'first10',
|
||||
logs: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
logContent() {
|
||||
return this.logs.join('<br>');
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
log(msg, type = 'info') {
|
||||
const time = new Date().toLocaleTimeString();
|
||||
const color = type === 'error' ? 'red' : type === 'success' ? 'green' : 'black';
|
||||
this.logs.push(`<span style="color:${color}">[${time}] ${msg}</span>`);
|
||||
console.log(`[${time}] ${msg}`);
|
||||
},
|
||||
|
||||
clearLog() {
|
||||
this.logs = [];
|
||||
},
|
||||
|
||||
async step1() {
|
||||
this.log('步骤1: 获取账号数据...');
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/tgAccount/test-all', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
this.accounts = result.data;
|
||||
this.log(`成功获取 ${this.accounts.length} 条账号数据`, 'success');
|
||||
this.log(`第一条: ${JSON.stringify(this.accounts[0])}`, 'info');
|
||||
} else {
|
||||
throw new Error('API返回失败');
|
||||
}
|
||||
} catch (error) {
|
||||
this.log(`获取数据失败: ${error.message}`, 'error');
|
||||
}
|
||||
},
|
||||
|
||||
step2() {
|
||||
this.log('步骤2: 导出为Excel...');
|
||||
try {
|
||||
const data = this.exportRange === 'all' ? this.accounts : this.accounts.slice(0, 10);
|
||||
|
||||
// 准备数据
|
||||
const exportData = data.map(item => ({
|
||||
'手机号': item.phone || '',
|
||||
'密码': item.password || '',
|
||||
'姓': item.firstname || '',
|
||||
'名': item.lastname || '',
|
||||
'用途ID': item.usageId || '',
|
||||
'Session': item.session || ''
|
||||
}));
|
||||
|
||||
this.log(`准备导出 ${exportData.length} 条数据`);
|
||||
|
||||
// 创建工作簿
|
||||
const ws = XLSX.utils.json_to_sheet(exportData);
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "账号列表");
|
||||
|
||||
// 导出文件
|
||||
const date = new Date();
|
||||
const filename = `TG账号_${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}_${date.getHours()}-${date.getMinutes()}.xlsx`;
|
||||
XLSX.writeFile(wb, filename);
|
||||
|
||||
this.log(`成功导出Excel文件: ${filename}`, 'success');
|
||||
} catch (error) {
|
||||
this.log(`Excel导出失败: ${error.message}`, 'error');
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
|
||||
step3() {
|
||||
this.log('步骤3: 导出为CSV...');
|
||||
try {
|
||||
const data = this.exportRange === 'all' ? this.accounts : this.accounts.slice(0, 10);
|
||||
|
||||
const headers = ['手机号', '密码', '姓', '名', '用途ID', 'Session'];
|
||||
const keys = ['phone', 'password', 'firstname', 'lastname', 'usageId', 'session'];
|
||||
|
||||
const csvContent = [
|
||||
headers.join(','),
|
||||
...data.map(row => keys.map(key => {
|
||||
const value = row[key] || '';
|
||||
// 处理包含逗号或引号的值
|
||||
if (value.toString().includes(',') || value.toString().includes('"')) {
|
||||
return `"${value.toString().replace(/"/g, '""')}"`;
|
||||
}
|
||||
return value;
|
||||
}).join(','))
|
||||
].join('\n');
|
||||
|
||||
// 下载文件
|
||||
const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(blob);
|
||||
const date = new Date();
|
||||
link.download = `TG账号_${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}_${date.getHours()}-${date.getMinutes()}.csv`;
|
||||
link.click();
|
||||
|
||||
this.log(`成功导出CSV文件: ${link.download}`, 'success');
|
||||
} catch (error) {
|
||||
this.log(`CSV导出失败: ${error.message}`, 'error');
|
||||
}
|
||||
},
|
||||
|
||||
async testAll() {
|
||||
this.clearLog();
|
||||
this.log('开始完整测试流程...');
|
||||
await this.step1();
|
||||
if (this.accounts.length > 0) {
|
||||
setTimeout(() => this.step2(), 1000);
|
||||
setTimeout(() => this.step3(), 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).mount('#app');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user