Initial commit: Telegram Management System
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:
你的用户名
2025-11-04 15:37:50 +08:00
commit 237c7802e5
3674 changed files with 525172 additions and 0 deletions

313
test-export-fix.html Normal file
View File

@@ -0,0 +1,313 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>TG账号导出功能修复测试</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.test-section {
margin: 20px 0;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
}
.status {
margin: 10px 0;
padding: 10px;
border-radius: 3px;
}
.success { background-color: #d4edda; color: #155724; }
.error { background-color: #f8d7da; color: #721c24; }
.info { background-color: #d1ecf1; color: #0c5460; }
button {
padding: 10px 20px;
margin: 5px;
cursor: pointer;
border: none;
border-radius: 3px;
background-color: #007bff;
color: white;
}
button:hover { background-color: #0056b3; }
.log {
background-color: #f8f9fa;
padding: 10px;
margin: 10px 0;
border-radius: 3px;
font-family: monospace;
white-space: pre-wrap;
max-height: 300px;
overflow-y: auto;
}
.modal {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
z-index: 1000;
}
.modal.show { display: block; }
.overlay {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
z-index: 999;
}
.overlay.show { display: block; }
</style>
</head>
<body>
<h1>TG账号导出功能修复测试</h1>
<div id="app">
<div class="test-section">
<h2>1. 环境检查</h2>
<div class="status" :class="envStatus.vue ? 'success' : 'error'">
Vue 3: {{ envStatus.vue ? '✅ 已加载' : '❌ 未加载' }}
</div>
<div class="status" :class="envStatus.xlsx ? 'success' : 'error'">
XLSX: {{ envStatus.xlsx ? '✅ 已加载' : '❌ 未加载' }}
</div>
</div>
<div class="test-section">
<h2>2. 模拟导出功能</h2>
<button @click="showExportModal">导出 (测试按钮点击)</button>
<button @click="testDirectExport">直接导出Excel (测试Excel功能)</button>
<button @click="testCSVExport">导出CSV (备用方案)</button>
<div class="log" v-if="logs.length">
<div v-for="log in logs" :key="log.time">
[{{ formatTime(log.time) }}] {{ log.message }}
</div>
</div>
</div>
<div class="test-section">
<h2>3. API测试</h2>
<button @click="testAPI">测试获取账号数据</button>
<div v-if="apiData.length" class="info">
获取到 {{ apiData.length }} 条账号数据
</div>
</div>
<!-- 模拟导出模态框 -->
<div class="overlay" :class="{ show: exportModalVisible }" @click="exportModalVisible = false"></div>
<div class="modal" :class="{ show: exportModalVisible }">
<h3>导出账号</h3>
<div style="margin: 20px 0;">
<label>
<input type="radio" v-model="exportRange" value="all"> 全部导出
</label>
<label style="margin-left: 20px;">
<input type="radio" v-model="exportRange" value="current"> 当前页
</label>
</div>
<div>
<button @click="confirmExport">确认导出</button>
<button @click="exportModalVisible = false" style="background-color: #6c757d;">取消</button>
</div>
</div>
</div>
<script>
const { createApp, ref, reactive, onMounted } = Vue;
createApp({
setup() {
const envStatus = reactive({
vue: false,
xlsx: false
});
const logs = ref([]);
const apiData = ref([]);
const exportModalVisible = ref(false);
const exportRange = ref('all');
const addLog = (message) => {
logs.value.push({
time: new Date(),
message
});
console.log(`[测试日志] ${message}`);
};
const formatTime = (date) => {
return date.toLocaleTimeString();
};
// 检查环境
onMounted(() => {
envStatus.vue = typeof Vue !== 'undefined';
envStatus.xlsx = typeof XLSX !== 'undefined';
addLog('环境检查完成');
});
// 模拟showExportModal函数
const showExportModal = () => {
addLog('showExportModal被调用');
exportModalVisible.value = true;
addLog('模态框已显示');
};
// 测试API
const testAPI = async () => {
addLog('开始测试API...');
try {
const response = await fetch('http://localhost:3000/tgAccount/test-all', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
const data = await response.json();
if (data.success) {
apiData.value = data.data;
addLog(`成功获取 ${data.data.length} 条账号数据`);
} else {
addLog('API返回失败');
}
} catch (error) {
addLog(`API错误: ${error.message}`);
}
};
// 确认导出
const confirmExport = async () => {
addLog(`确认导出,范围: ${exportRange.value}`);
exportModalVisible.value = false;
let dataToExport = [];
if (exportRange.value === 'all' && apiData.value.length === 0) {
await testAPI();
}
dataToExport = apiData.value;
if (dataToExport.length > 0) {
exportFile(dataToExport);
} else {
addLog('没有数据可导出');
}
};
// 导出文件
const exportFile = (list) => {
addLog(`开始导出 ${list.length} 条数据`);
if (!XLSX) {
addLog('XLSX库未加载使用CSV导出');
exportAsCSV(list);
return;
}
try {
const data = list.map(item => ({
'手机号': item.phone || '',
'密码': item.password || '',
'姓': item.firstname || '',
'名': item.lastname || '',
'用途ID': item.usageId || '',
'Session': item.session ? item.session.substring(0, 50) + '...' : ''
}));
const ws = XLSX.utils.json_to_sheet(data);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "账号列表");
const date = new Date();
const filename = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}-账号列表.xlsx`;
XLSX.writeFile(wb, filename);
addLog(`✅ Excel文件导出成功: ${filename}`);
} catch (error) {
addLog(`❌ Excel导出失败: ${error.message}`);
exportAsCSV(list);
}
};
// CSV导出
const exportAsCSV = (list) => {
addLog('使用CSV导出作为备用方案');
try {
const headers = ['手机号', '密码', '姓', '名', '用途ID', 'Session'];
const headerKeys = ['phone', 'password', 'firstname', 'lastname', 'usageId', 'session'];
const csvContent = [
headers.join(','),
...list.map(row => headerKeys.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 = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}-账号列表.csv`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
addLog(`✅ CSV文件导出成功`);
} catch (error) {
addLog(`❌ CSV导出失败: ${error.message}`);
}
};
// 直接测试Excel导出
const testDirectExport = () => {
const testData = [
{ phone: '12345678901', password: 'test123', firstname: '张', lastname: '三' },
{ phone: '12345678902', password: 'test456', firstname: '李', lastname: '四' }
];
exportFile(testData);
};
// 测试CSV导出
const testCSVExport = () => {
const testData = [
{ phone: '12345678901', password: 'test123', firstname: '张', lastname: '三' },
{ phone: '12345678902', password: 'test456', firstname: '李', lastname: '四' }
];
exportAsCSV(testData);
};
return {
envStatus,
logs,
apiData,
exportModalVisible,
exportRange,
formatTime,
showExportModal,
testAPI,
confirmExport,
testDirectExport,
testCSVExport
};
}
}).mount('#app');
</script>
</body>
</html>