const http = require('http'); const fs = require('fs'); const path = require('path'); const PORT = process.env.PORT || 3000; const DATA_FILE = path.join(__dirname, 'data.json'); function load() { try { return JSON.parse(fs.readFileSync(DATA_FILE, 'utf8')); } catch { return { items: [], log: [] }; } } function save(data) { fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2)); } const server = http.createServer((req, res) => { const url = req.url.split('?')[0]; const method = req.method; res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); if (method === 'OPTIONS') { res.writeHead(204); res.end(); return; } if (url === '/api/requests' && method === 'GET') { const data = load(); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data.items)); return; } if (url === '/api/requests' && method === 'POST') { let body = ''; req.on('data', chunk => { body += chunk; }); req.on('end', () => { const data = load(); const newRequest = JSON.parse(body); newRequest.id = Date.now(); newRequest.createdAt = new Date().toISOString(); newRequest.updatedAt = new Date().toISOString(); data.items.push(newRequest); data.log.push({ when: new Date().toISOString(), what: `Создана заявка #${newRequest.id}`, who: newRequest.operator || 'Система' }); save(data); res.writeHead(201, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(newRequest)); }); return; } if (url === '/api/requests' && method === 'PUT') { let body = ''; req.on('data', chunk => { body += chunk; }); req.on('end', () => { const data = load(); const updated = JSON.parse(body); const index = data.items.findIndex(r => r.id === updated.id); if (index !== -1) { const old = data.items[index]; updated.updatedAt = new Date().toISOString(); data.items[index] = { ...old, ...updated }; data.log.push({ when: new Date().toISOString(), what: `Обновлена заявка #${updated.id}: статус ${old.status} → ${updated.status}`, who: updated.operator || 'Система' }); save(data); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(updated)); } else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Заявка не найдена' })); } }); return; } if (url.startsWith('/api/requests/') && method === 'DELETE') { const id = parseInt(url.split('/').pop()); const data = load(); const index = data.items.findIndex(r => r.id === id); if (index !== -1) { const removed = data.items.splice(index, 1)[0]; data.log.push({ when: new Date().toISOString(), what: `Удалена заявка #${id}`, who: 'Оператор' }); save(data); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(removed)); } else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Заявка не найдена' })); } return; } if (url === '/api/log' && method === 'GET') { const data = load(); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data.log.slice(-50))); return; } if (url === '/' || url === '/index.html') { const filePath = path.join(__dirname, 'index.html'); fs.readFile(filePath, 'utf8', (err, content) => { if (err) { res.writeHead(500); res.end('Ошибка загрузки страницы'); return; } res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(content); }); return; } const filePath = path.join(__dirname, url); fs.readFile(filePath, (err, content) => { if (err) { res.writeHead(404); res.end('Не найдено'); return; } const ext = path.extname(url); const mime = { '.css': 'text/css', '.js': 'application/javascript', '.png': 'image/png', '.svg': 'image/svg+xml' }; res.writeHead(200, { 'Content-Type': mime[ext] || 'text/plain' }); res.end(content); }); }); server.listen(PORT, () => { console.log(`Сервер заявок запущен на порту ${PORT}`); });