Files
telegram-management-system/complete-api-server.js
你的用户名 237c7802e5
Some checks failed
Deploy / deploy (push) Has been cancelled
Initial commit: Telegram Management System
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>
2025-11-04 15:37:50 +08:00

779 lines
22 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require('express');
const cors = require('cors');
const mysql = require('mysql2/promise');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const app = express();
// 中间件配置
app.use(cors({
origin: ['http://localhost:5173', 'http://localhost:3000'],
credentials: true
}));
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ extended: true, limit: '50mb' }));
// 数据库连接配置
const dbConfig = {
host: '127.0.0.1',
user: 'root',
password: '',
database: 'tg_manage',
acquireTimeout: 60000,
timeout: 60000,
reconnect: true
};
// JWT配置
const JWT_SECRET = 'tg-management-system-jwt-secret-2025';
// 数据库连接池
let pool;
async function initDB() {
pool = mysql.createPool({
...dbConfig,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
console.log('📊 数据库连接池初始化成功');
}
// JWT中间件
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({
success: false,
code: 401,
msg: '未提供访问令牌'
});
}
jwt.verify(token, JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({
success: false,
code: 403,
msg: '令牌无效或已过期'
});
}
req.user = user;
next();
});
};
// 统一错误处理
const handleError = (error, req, res, next) => {
console.error('API错误:', error);
res.status(500).json({
success: false,
code: 500,
msg: '服务器内部错误: ' + error.message,
data: null
});
};
// ==================== 认证相关接口 ====================
// 登录接口
app.post('/auth/login', async (req, res) => {
try {
const { username, password } = req.body || {};
if (!username || !password) {
return res.status(400).json({
success: false,
code: 400,
msg: '用户名和密码不能为空',
data: null
});
}
// 简单验证 - 生产环境应该从数据库验证
if (username === 'admin' && password === '111111') {
const token = jwt.sign(
{
id: 1,
username: 'admin',
role: 'admin'
},
JWT_SECRET,
{ expiresIn: '24h' }
);
res.json({
success: true,
code: 200,
msg: '登录成功',
data: {
token,
user: {
id: 1,
username: 'admin',
role: 'admin',
nickname: '系统管理员'
}
}
});
} else {
res.status(401).json({
success: false,
code: 401,
msg: '用户名或密码错误',
data: null
});
}
} catch (error) {
handleError(error, req, res);
}
});
// 获取用户信息接口
app.get('/auth/user', authenticateToken, (req, res) => {
res.json({
success: true,
code: 200,
msg: '获取用户信息成功',
data: {
id: req.user.id,
username: req.user.username,
role: req.user.role,
nickname: '系统管理员',
avatar: null,
permissions: ['*']
}
});
});
// ==================== TG账号管理接口 ====================
// TG账号列表接口
app.post('/tgAccount/list', async (req, res) => {
try {
const connection = await pool.getConnection();
const page = (req.body && req.body.page) || 1;
const size = (req.body && req.body.size) || 10;
const phone = (req.body && req.body.phone) || '';
const status = req.body && req.body.status;
const usageId = req.body && req.body.usageId;
let whereConditions = [];
let params = [];
if (phone) {
whereConditions.push('phone LIKE ?');
params.push(`%${phone}%`);
}
if (status !== undefined && status !== null && status !== '') {
whereConditions.push('status = ?');
params.push(status);
}
if (usageId !== undefined && usageId !== null && usageId !== '') {
whereConditions.push('usageId = ?');
params.push(usageId);
}
const whereClause = whereConditions.length > 0 ? 'WHERE ' + whereConditions.join(' AND ') : '';
// 查询总数
const [countResult] = await connection.execute(
`SELECT COUNT(*) as total FROM accounts ${whereClause}`,
params
);
const total = countResult[0].total;
// 查询数据
const offset = (page - 1) * size;
const [rows] = await connection.execute(
`SELECT
id, phone, firstname, lastname, status, usageId,
createdAt, updatedAt, lastOnline, isBan, about
FROM accounts
${whereClause}
ORDER BY id DESC
LIMIT ${size} OFFSET ${offset}`,
params
);
// 统计数据
const [stats] = await connection.execute(
`SELECT
COUNT(*) as total,
SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) as active,
SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) as inactive,
SUM(CASE WHEN isBan = 1 THEN 1 ELSE 0 END) as banned
FROM accounts`
);
connection.release();
res.json({
success: true,
code: 200,
data: {
list: rows,
total: total,
page: page,
size: size,
totalPages: Math.ceil(total / size),
stats: stats[0]
},
msg: '查询成功'
});
} catch (error) {
console.error('TG账号列表API错误:', error);
res.status(500).json({
success: false,
code: 500,
data: null,
msg: '服务器错误: ' + error.message
});
}
});
// TG账号详情接口
app.get('/tgAccount/:id', async (req, res) => {
try {
const connection = await pool.getConnection();
const { id } = req.params;
const [rows] = await connection.execute(
'SELECT * FROM accounts WHERE id = ?',
[id]
);
connection.release();
if (rows.length === 0) {
return res.status(404).json({
success: false,
code: 404,
msg: '账号不存在',
data: null
});
}
res.json({
success: true,
code: 200,
msg: '获取成功',
data: rows[0]
});
} catch (error) {
handleError(error, req, res);
}
});
// 创建TG账号接口
app.post('/tgAccount/add', async (req, res) => {
try {
const connection = await pool.getConnection();
const { phone, firstname, lastname, password, usageId } = req.body;
if (!phone || !usageId) {
return res.status(400).json({
success: false,
code: 400,
msg: '手机号和用途不能为空',
data: null
});
}
const [result] = await connection.execute(
`INSERT INTO accounts
(phone, firstname, lastname, password, usageId, status, createdAt, updatedAt)
VALUES (?, ?, ?, ?, ?, 1, NOW(), NOW())`,
[phone, firstname || '', lastname || '', password || '', usageId]
);
connection.release();
res.json({
success: true,
code: 200,
msg: '添加成功',
data: { id: result.insertId }
});
} catch (error) {
if (error.code === 'ER_DUP_ENTRY') {
res.status(400).json({
success: false,
code: 400,
msg: '手机号已存在',
data: null
});
} else {
handleError(error, req, res);
}
}
});
// 更新TG账号接口
app.put('/tgAccount/:id', async (req, res) => {
try {
const connection = await pool.getConnection();
const { id } = req.params;
const { firstname, lastname, usageId, status, about } = req.body;
await connection.execute(
`UPDATE accounts
SET firstname = ?, lastname = ?, usageId = ?, status = ?, about = ?, updatedAt = NOW()
WHERE id = ?`,
[firstname, lastname, usageId, status, about, id]
);
connection.release();
res.json({
success: true,
code: 200,
msg: '更新成功',
data: null
});
} catch (error) {
handleError(error, req, res);
}
});
// 删除TG账号接口
app.delete('/tgAccount/:id', async (req, res) => {
try {
const connection = await pool.getConnection();
const { id } = req.params;
await connection.execute('DELETE FROM accounts WHERE id = ?', [id]);
connection.release();
res.json({
success: true,
code: 200,
msg: '删除成功',
data: null
});
} catch (error) {
handleError(error, req, res);
}
});
// 批量操作TG账号接口
app.post('/tgAccount/batch', async (req, res) => {
try {
const connection = await pool.getConnection();
const { ids, action } = req.body;
if (!ids || !Array.isArray(ids) || ids.length === 0) {
return res.status(400).json({
success: false,
code: 400,
msg: '请选择要操作的账号',
data: null
});
}
const placeholders = ids.map(() => '?').join(',');
switch (action) {
case 'enable':
await connection.execute(
`UPDATE accounts SET status = 1, updatedAt = NOW() WHERE id IN (${placeholders})`,
ids
);
break;
case 'disable':
await connection.execute(
`UPDATE accounts SET status = 0, updatedAt = NOW() WHERE id IN (${placeholders})`,
ids
);
break;
case 'delete':
await connection.execute(
`DELETE FROM accounts WHERE id IN (${placeholders})`,
ids
);
break;
default:
return res.status(400).json({
success: false,
code: 400,
msg: '不支持的操作类型',
data: null
});
}
connection.release();
res.json({
success: true,
code: 200,
msg: '批量操作成功',
data: null
});
} catch (error) {
handleError(error, req, res);
}
});
// ==================== 账号用途管理接口 ====================
// 账号用途列表接口
app.post('/accountUsage/list', async (req, res) => {
try {
const connection = await pool.getConnection();
const pageIndex = (req.body && req.body.pageIndex) || 1;
const pageSize = (req.body && req.body.pageSize) || 10;
const type = (req.body && req.body.type) || '';
let whereClause = '';
let params = [];
if (type) {
whereClause = 'WHERE type LIKE ?';
params.push(`%${type}%`);
}
// 查询总数
const [countResult] = await connection.execute(
`SELECT COUNT(*) as total FROM accounts_usage ${whereClause}`,
params
);
const total = countResult[0].total;
// 查询数据
const offset = (pageIndex - 1) * pageSize;
const [rows] = await connection.execute(
`SELECT id, type, createdAt, updatedAt
FROM accounts_usage
${whereClause}
ORDER BY id DESC
LIMIT ${pageSize} OFFSET ${offset}`,
params
);
connection.release();
res.json({
success: true,
code: '200',
message: '查询成功',
data: {
list: rows,
totalRow: total,
pageIndex: pageIndex,
pageSize: pageSize
}
});
} catch (error) {
console.error('账号用途API错误:', error);
res.status(500).json({
success: false,
code: '500',
message: '服务器错误: ' + error.message,
data: null
});
}
});
// 添加账号用途接口
app.post('/accountUsage/add', async (req, res) => {
try {
const connection = await pool.getConnection();
const { type } = req.body;
if (!type) {
return res.status(400).json({
success: false,
code: '400',
message: '用途名称不能为空',
data: null
});
}
const [result] = await connection.execute(
'INSERT INTO accounts_usage (type, createdAt, updatedAt) VALUES (?, NOW(), NOW())',
[type]
);
connection.release();
res.json({
success: true,
code: '200',
message: '添加成功',
data: { id: result.insertId }
});
} catch (error) {
console.error('添加账号用途错误:', error);
res.status(500).json({
success: false,
code: '500',
message: '添加失败: ' + error.message,
data: null
});
}
});
// 更新账号用途接口
app.post('/accountUsage/update', async (req, res) => {
try {
const connection = await pool.getConnection();
const { id, type } = req.body;
if (!type) {
return res.status(400).json({
success: false,
code: '400',
message: '用途名称不能为空',
data: null
});
}
await connection.execute(
'UPDATE accounts_usage SET type = ?, updatedAt = NOW() WHERE id = ?',
[type, id]
);
connection.release();
res.json({
success: true,
code: '200',
message: '更新成功',
data: null
});
} catch (error) {
console.error('更新账号用途错误:', error);
res.status(500).json({
success: false,
code: '500',
message: '更新失败: ' + error.message,
data: null
});
}
});
// 删除账号用途接口
app.delete('/accountUsage/:id', async (req, res) => {
try {
const connection = await pool.getConnection();
const { id } = req.params;
await connection.execute('DELETE FROM accounts_usage WHERE id = ?', [id]);
connection.release();
res.json({
success: true,
code: '200',
message: '删除成功',
data: null
});
} catch (error) {
console.error('删除账号用途错误:', error);
res.status(500).json({
success: false,
code: '500',
message: '删除失败: ' + error.message,
data: null
});
}
});
// ==================== 统计分析接口 ====================
// 系统概览数据接口
app.get('/telegram/statistics/overview', async (req, res) => {
try {
const connection = await pool.getConnection();
// 账号统计
const [accountStats] = await connection.execute(
`SELECT
COUNT(*) as totalAccounts,
SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) as activeAccounts,
SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) as inactiveAccounts,
SUM(CASE WHEN isBan = 1 THEN 1 ELSE 0 END) as bannedAccounts
FROM accounts`
);
// 用途统计
const [usageStats] = await connection.execute(
'SELECT COUNT(*) as totalUsages FROM accounts_usage'
);
// 在线统计最近24小时
const [onlineStats] = await connection.execute(
`SELECT COUNT(*) as onlineAccounts
FROM accounts
WHERE lastOnline >= DATE_SUB(NOW(), INTERVAL 24 HOUR)`
);
connection.release();
res.json({
success: true,
code: 200,
msg: '获取成功',
data: {
accounts: accountStats[0],
usages: usageStats[0].totalUsages,
online: onlineStats[0].onlineAccounts,
timestamp: new Date().toISOString()
}
});
} catch (error) {
handleError(error, req, res);
}
});
// 账号统计数据接口
app.get('/telegram/statistics/account', async (req, res) => {
try {
const connection = await pool.getConnection();
// 按用途分组统计
const [usageStats] = await connection.execute(
`SELECT
u.type as usageName,
COUNT(a.id) as count,
SUM(CASE WHEN a.status = 1 THEN 1 ELSE 0 END) as active,
SUM(CASE WHEN a.isBan = 1 THEN 1 ELSE 0 END) as banned
FROM accounts_usage u
LEFT JOIN accounts a ON u.id = a.usageId
GROUP BY u.id, u.type
ORDER BY count DESC`
);
// 日活统计最近7天
const [dailyStats] = await connection.execute(
`SELECT
DATE(lastOnline) as date,
COUNT(*) as count
FROM accounts
WHERE lastOnline >= DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY DATE(lastOnline)
ORDER BY date DESC`
);
connection.release();
res.json({
success: true,
code: 200,
msg: '获取成功',
data: {
usageStats,
dailyStats
}
});
} catch (error) {
handleError(error, req, res);
}
});
// ==================== 菜单权限接口 ====================
// 获取菜单权限接口
app.get('/telegram/permission/menus', authenticateToken, (req, res) => {
const menus = [
{
id: 1,
title: '仪表板',
path: '/dashboard',
icon: 'DashboardOutlined',
children: []
},
{
id: 2,
title: '账号管理',
path: '/account-manage',
icon: 'UserOutlined',
children: [
{
id: 21,
title: 'TG账号列表',
path: '/account-manage/list',
icon: 'UnorderedListOutlined'
},
{
id: 22,
title: 'TG账号用途',
path: '/account-manage/usage',
icon: 'TagsOutlined'
}
]
}
];
res.json({
success: true,
code: 200,
msg: '获取菜单成功',
data: menus
});
});
// ==================== 健康检查接口 ====================
app.get('/health', (req, res) => {
res.json({
success: true,
code: 200,
msg: 'API服务运行正常',
data: {
timestamp: new Date().toISOString(),
uptime: process.uptime()
}
});
});
// 全局错误处理
app.use(handleError);
// 启动服务
const PORT = 3002;
async function startServer() {
try {
await initDB();
app.listen(PORT, () => {
console.log(`🚀 完整版API服务启动成功端口: ${PORT}`);
console.log(`📊 健康检查: GET http://localhost:${PORT}/health`);
console.log(`🔐 登录接口: POST http://localhost:${PORT}/auth/login`);
console.log(`👤 用户信息: GET http://localhost:${PORT}/auth/user`);
console.log(`📱 TG账号列表: POST http://localhost:${PORT}/tgAccount/list`);
console.log(`📋 账号用途管理: POST http://localhost:${PORT}/accountUsage/list`);
console.log(`📈 系统概览: GET http://localhost:${PORT}/telegram/statistics/overview`);
console.log(`📊 账号统计: GET http://localhost:${PORT}/telegram/statistics/account`);
console.log(`🏠 菜单权限: GET http://localhost:${PORT}/telegram/permission/menus`);
console.log('');
console.log('✅ 完整版API服务器已就绪支持全功能');
});
} catch (error) {
console.error('❌ 服务启动失败:', error);
process.exit(1);
}
}
startServer();