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:
313
test-export-fix.html
Normal file
313
test-export-fix.html
Normal 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>
|
||||
Reference in New Issue
Block a user