import express, { Request, Response } from 'express'; import db from '../utils/database'; import { authenticateToken, requireAdmin } from '../middleware/auth'; import { PaginationQuery, UpdateCompanyRequest, CompanyDetail, StatsOverview, MonthlyStat, SerialListItem, CompanyListItem } from '../types'; const router = express.Router(); router.get('/', authenticateToken, requireAdmin, async (req: Request<{}, {}, {}, PaginationQuery>, res: Response): Promise => { try { const { page = 1, limit = 20, search = '' } = req.query; const offset = (page - 1) * limit; let query = 'SELECT c.company_name, c.created_at as first_created, c.updated_at as last_created, c.is_active, (SELECT COUNT(*) FROM serials s WHERE s.company_name = c.company_name) as serial_count, (SELECT COUNT(*) FROM serials s WHERE s.company_name = c.company_name AND s.is_active = 1) as active_count FROM companies c'; let countQuery = 'SELECT COUNT(*) as total FROM companies'; let params: any[] = []; if (search) { query += ' WHERE c.company_name LIKE ?'; countQuery += ' WHERE company_name LIKE ?'; params.push(`%${search}%`); } query += ' ORDER BY c.updated_at DESC LIMIT ? OFFSET ?'; params.push(parseInt(limit.toString()), parseInt(offset.toString())); const [companies, countResult] = await Promise.all([ db.all(query, params), db.get<{ total: number }>(countQuery, params.slice(0, -2)) ]); const total = countResult?.total || 0; const totalPages = Math.ceil(total / limit); res.json({ message: '获取企业列表成功', data: companies.map((company: any) => ({ companyName: company.company_name, firstCreated: company.first_created, lastCreated: company.last_created, serialCount: company.serial_count, activeCount: company.active_count, status: company.is_active ? 'active' : 'disabled' })), pagination: { page: parseInt(page.toString()), limit: parseInt(limit.toString()), total, totalPages } }); } catch (error) { console.error('获取企业列表错误:', error); res.status(500).json({ error: '服务器内部错误' }); } }); router.get('/:companyName', authenticateToken, requireAdmin, async (req: Request<{ companyName: string }, {}, {}, PaginationQuery>, res: Response): Promise => { try { const { companyName } = req.params; const decodedCompanyName = decodeURIComponent(companyName); const { page = 1, limit = 20 } = req.query; const offset = (page - 1) * limit; const companyInfo = await db.get('SELECT * FROM companies WHERE company_name = ?', [decodedCompanyName]); if (!companyInfo) { res.status(404).json({ error: '企业不存在' }); return; } const serialStats = await db.get(` SELECT COUNT(*) as serial_count, SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) as active_count, SUM(CASE WHEN is_active = 0 THEN 1 ELSE 0 END) as disabled_count, SUM(CASE WHEN valid_until IS NOT NULL AND valid_until <= datetime('now') THEN 1 ELSE 0 END) as expired_count FROM serials WHERE company_name = ? `, [decodedCompanyName]); const serials = await db.all(` SELECT s.*, u.name as created_by_name FROM serials s LEFT JOIN users u ON s.created_by = u.id WHERE s.company_name = ? ORDER BY s.created_at DESC LIMIT ? OFFSET ? `, [decodedCompanyName, parseInt(limit.toString()), parseInt(offset.toString())]); const stats = await db.all<{ month: string; count: number }>(` SELECT strftime('%Y-%m', created_at) as month, COUNT(*) as count FROM serials WHERE company_name = ? GROUP BY strftime('%Y-%m', created_at) ORDER BY month DESC LIMIT 12 `, [decodedCompanyName]); res.json({ message: '获取企业详情成功', data: { companyName: decodedCompanyName, serialCount: serialStats?.serial_count || 0, activeCount: serialStats?.active_count || 0, disabledCount: serialStats?.disabled_count || 0, expiredCount: serialStats?.expired_count || 0, firstCreated: (companyInfo as any).created_at, lastCreated: (companyInfo as any).updated_at, status: (companyInfo as any).is_active ? 'active' : 'disabled', serials: serials.map((s: any) => ({ serialNumber: s.serial_number, validUntil: s.valid_until, isActive: s.is_active, createdAt: s.created_at, createdBy: s.created_by_name })), monthlyStats: stats.map(stat => ({ month: stat.month, count: stat.count })) } }); } catch (error) { console.error('获取企业详情错误:', error); res.status(500).json({ error: '服务器内部错误' }); } }); router.patch('/:companyName', authenticateToken, requireAdmin, async (req: Request<{ companyName: string }, {}, UpdateCompanyRequest>, res: Response): Promise => { try { const { companyName } = req.params; const decodedCompanyName = decodeURIComponent(companyName); const { newCompanyName } = req.body; if (!newCompanyName || newCompanyName.trim() === '') { res.status(400).json({ error: '新企业名称不能为空' }); return; } const existingCompany = db.get( 'SELECT COUNT(*) as count FROM serials WHERE company_name = ?', [decodedCompanyName] ); if (!existingCompany || existingCompany.count === 0) { res.status(404).json({ error: '企业不存在' }); return; } const duplicateCompany = db.get( 'SELECT COUNT(*) as count FROM serials WHERE company_name = ?', [newCompanyName] ); if (duplicateCompany && duplicateCompany.count > 0) { res.status(400).json({ error: '企业名称已存在' }); return; } db.run( 'UPDATE serials SET company_name = ?, updated_at = CURRENT_TIMESTAMP WHERE company_name = ?', [newCompanyName, decodedCompanyName] ); res.json({ message: '企业名称更新成功', data: { oldCompanyName: decodedCompanyName, newCompanyName } }); } catch (error) { console.error('更新企业信息错误:', error); res.status(500).json({ error: '服务器内部错误' }); } }); router.delete('/:companyName', authenticateToken, requireAdmin, async (req: Request<{ companyName: string }>, res: Response): Promise => { try { const { companyName } = req.params; const decodedCompanyName = decodeURIComponent(companyName); const existingCompany = await db.get( 'SELECT * FROM companies WHERE company_name = ?', [decodedCompanyName] ); if (!existingCompany) { res.status(404).json({ error: '企业不存在' }); return; } db.run('BEGIN TRANSACTION'); try { const serialDeleteResult = db.run( 'DELETE FROM serials WHERE company_name = ?', [decodedCompanyName] ); const companyDeleteResult = db.run( 'DELETE FROM companies WHERE company_name = ?', [decodedCompanyName] ); if (companyDeleteResult.changes === 0) { db.run('ROLLBACK'); res.status(404).json({ error: '企业不存在' }); return; } db.run('COMMIT'); res.json({ message: '企业已完全删除,所有相关序列号已删除', data: { companyName: decodedCompanyName, deletedSerialCount: serialDeleteResult.changes, deletedCompanyCount: companyDeleteResult.changes } }); } catch (error) { console.error('删除企业过程中错误:', error); db.run('ROLLBACK'); throw error; } } catch (error) { console.error('删除企业错误:', error); res.status(500).json({ error: '服务器内部错误' }); } }); router.get('/stats/overview', authenticateToken, requireAdmin, async (req: Request, res: Response): Promise => { try { const companyCount = await db.get<{ count: number }>('SELECT COUNT(*) as count FROM companies'); const serialCount = await db.get<{ count: number }>('SELECT COUNT(*) as count FROM serials'); const activeCount = await db.get<{ count: number }>(` SELECT COUNT(*) as count FROM serials WHERE is_active = 1 AND (valid_until IS NULL OR valid_until > datetime('now')) `); const monthlyStats = await db.all<{ month: string; company_count: number; serial_count: number }>(` SELECT strftime('%Y-%m', created_at) as month, COUNT(DISTINCT company_name) as company_count, COUNT(*) as serial_count FROM serials WHERE created_at >= strftime('%Y-%m-%d', datetime('now', '-12 months')) GROUP BY strftime('%Y-%m', created_at) ORDER BY month ASC `); const recentCompanies = await db.all<{ company_name: string; last_created: string; is_active: number }>(` SELECT c.company_name, c.created_at as last_created, c.is_active FROM companies c ORDER BY c.updated_at DESC LIMIT 10 `); const recentSerials = await db.all<{ serial_number: string; company_name: string; is_active: number; created_at: string }>(` SELECT s.serial_number, s.company_name, s.is_active, s.created_at FROM serials s ORDER BY s.created_at DESC LIMIT 10 `); let finalMonthlyStats = monthlyStats; if (monthlyStats.length === 0) { finalMonthlyStats = []; const now = new Date(); for (let i = 11; i >= 0; i--) { const date = new Date(now.getFullYear(), now.getMonth() - i, 1); const month = date.toISOString().substr(0, 7); finalMonthlyStats.push({ month, company_count: 0, serial_count: 0 }); } } res.json({ message: '获取统计数据成功', data: { overview: { totalCompanies: companyCount?.count || 0, totalSerials: serialCount?.count || 0, activeSerials: activeCount?.count || 0, inactiveSerials: (serialCount?.count || 0) - (activeCount?.count || 0) }, monthlyStats: finalMonthlyStats.map(stat => ({ month: stat.month, company_count: stat.company_count, serial_count: stat.serial_count })), recentCompanies: recentCompanies.map(c => ({ companyName: c.company_name, lastCreated: c.last_created, status: c.is_active ? 'active' : 'disabled' })), recentSerials: recentSerials.map(s => ({ serialNumber: s.serial_number, companyName: s.company_name, isActive: !!s.is_active, createdAt: s.created_at })) } }); } catch (error) { console.error('获取统计数据错误:', error); res.status(500).json({ error: '服务器内部错误' }); } }); router.delete('/:companyName/serials/:serialNumber', authenticateToken, requireAdmin, async (req: Request<{ companyName: string; serialNumber: string }>, res: Response): Promise => { try { const { companyName, serialNumber } = req.params; const serial = await db.get( 'SELECT * FROM serials WHERE serial_number = ? AND company_name = ?', [serialNumber.toUpperCase(), companyName] ); if (!serial) { res.status(404).json({ error: '序列号不存在或不属于该企业' }); return; } await db.run( 'DELETE FROM serials WHERE serial_number = ? AND company_name = ?', [serialNumber.toUpperCase(), companyName] ); res.json({ message: '序列号已成功删除', data: { serialNumber: serialNumber.toUpperCase(), companyName } }); } catch (error) { console.error('删除序列号错误:', error); res.status(500).json({ error: '服务器内部错误' }); } }); router.post('/:companyName/revoke', authenticateToken, requireAdmin, async (req: Request<{ companyName: string }>, res: Response): Promise => { try { const { companyName } = req.params; const decodedCompanyName = decodeURIComponent(companyName); const existingCompany = await db.get( 'SELECT COUNT(*) as count FROM serials WHERE company_name = ?', [decodedCompanyName] ); if (!existingCompany || existingCompany.count === 0) { res.status(404).json({ error: '企业不存在' }); return; } await db.run( 'UPDATE serials SET is_active = 0, updated_at = CURRENT_TIMESTAMP WHERE company_name = ?', [decodedCompanyName] ); res.json({ message: '企业已吊销,所有序列号已失效', data: { companyName: decodedCompanyName } }); } catch (error) { console.error('吊销企业错误:', error); res.status(500).json({ error: '服务器内部错误' }); } }); export default router;