114 lines
4.4 KiB
JavaScript
114 lines
4.4 KiB
JavaScript
const express = require('express');
|
|
const cors = require('cors');
|
|
const path = require('path');
|
|
const { initDB } = require('./db');
|
|
const { authenticateToken } = require('./middleware/auth');
|
|
|
|
const app = express();
|
|
const PORT = process.env.PORT || 3000;
|
|
|
|
// Middleware
|
|
app.use(cors());
|
|
app.use(express.json({ limit: '50mb' }));
|
|
app.use(express.urlencoded({ limit: '50mb', extended: true }));
|
|
|
|
// Static files (for serving built frontend)
|
|
app.use(express.static(path.join(__dirname, 'public')));
|
|
|
|
async function startServer() {
|
|
// Initialize database
|
|
const db = await initDB();
|
|
|
|
// Make db available to routes
|
|
app.locals.db = db;
|
|
|
|
// Auth routes (login is public)
|
|
const jwt = require('jsonwebtoken');
|
|
const bcrypt = require('bcryptjs');
|
|
const { JWT_SECRET } = require('./middleware/auth');
|
|
|
|
app.post('/api/auth/login', (req, res) => {
|
|
const { username, password } = req.body;
|
|
if (!username || !password) return res.status(400).json({ code: 400, message: '用户名和密码不能为空' });
|
|
const user = db.get('SELECT * FROM users WHERE username = ?', [username]);
|
|
if (!user) return res.status(401).json({ code: 401, message: '用户名或密码错误' });
|
|
if (user.status !== 1) return res.status(403).json({ code: 403, message: '账号已被禁用' });
|
|
if (user.role === 'sales') return res.status(403).json({ code: 403, message: '销售人员无需登录系统' });
|
|
if (!bcrypt.compareSync(password, user.password)) return res.status(401).json({ code: 401, message: '用户名或密码错误' });
|
|
const token = jwt.sign({ id: user.id, username: user.username, role: user.role, realname: user.realname }, JWT_SECRET, { expiresIn: '24h' });
|
|
res.json({ code: 200, message: '登录成功', data: { token, user: { id: user.id, username: user.username, realname: user.realname, role: user.role } } });
|
|
});
|
|
|
|
app.get('/api/auth/me', authenticateToken, (req, res) => {
|
|
const user = db.get('SELECT id, username, realname, role, status FROM users WHERE id = ?', [req.user.id]);
|
|
if (!user) return res.status(404).json({ code: 404, message: '用户不存在' });
|
|
res.json({ code: 200, data: user });
|
|
});
|
|
|
|
// Module routes
|
|
const adminRoutes = require('./routes/admin');
|
|
const rdRoutes = require('./routes/rd');
|
|
|
|
app.use('/api/admin', authenticateToken, adminRoutes);
|
|
app.use('/api/rd', authenticateToken, rdRoutes);
|
|
|
|
// Health check
|
|
app.get('/api/health', (req, res) => {
|
|
res.json({ code: 200, message: 'OK', time: new Date().toISOString() });
|
|
});
|
|
|
|
// Fallback: serve index.html for SPA
|
|
app.get('*', (req, res) => {
|
|
const indexPath = path.join(__dirname, 'public', 'index.html');
|
|
const fs = require('fs');
|
|
if (fs.existsSync(indexPath)) {
|
|
res.sendFile(indexPath);
|
|
} else {
|
|
res.status(404).json({ code: 404, message: 'Not found' });
|
|
}
|
|
});
|
|
|
|
app.listen(PORT, () => {
|
|
console.log(`🚀 WorkTime Server running at http://localhost:${PORT}`);
|
|
});
|
|
|
|
// ===== Auto-backup cron: daily at 03:00 =====
|
|
const cron = require('node-cron');
|
|
const fsBackup = require('fs');
|
|
const { buildBackupJson, BACKUP_DIR, ensureBackupDir } = adminRoutes;
|
|
|
|
function runAutoBackup() {
|
|
try {
|
|
ensureBackupDir();
|
|
const json = buildBackupJson(db);
|
|
const date = new Date().toISOString().slice(0, 10);
|
|
const filePath = `${BACKUP_DIR}/backup-${date}.json`;
|
|
fsBackup.writeFileSync(filePath, json, 'utf8');
|
|
console.log(`[AutoBackup] Saved: ${filePath}`);
|
|
|
|
// Purge backups older than 30 days
|
|
const cutoff = Date.now() - 30 * 24 * 60 * 60 * 1000;
|
|
fsBackup.readdirSync(BACKUP_DIR).forEach(f => {
|
|
if (!f.endsWith('.json')) return;
|
|
const fp = `${BACKUP_DIR}/${f}`;
|
|
if (fsBackup.statSync(fp).mtimeMs < cutoff) {
|
|
fsBackup.unlinkSync(fp);
|
|
console.log(`[AutoBackup] Purged old backup: ${f}`);
|
|
}
|
|
});
|
|
} catch (e) {
|
|
console.error('[AutoBackup] Error:', e.message);
|
|
}
|
|
}
|
|
|
|
cron.schedule('0 3 * * *', runAutoBackup);
|
|
console.log('[AutoBackup] Scheduled daily at 03:00');
|
|
}
|
|
|
|
startServer().catch(err => {
|
|
console.error('Failed to start server:', err);
|
|
process.exit(1);
|
|
});
|
|
|
|
module.exports = app;
|