/** * server.js - AI 接单系统主服务 * 支持 Docker 部署、垃圾过滤、环境变量配置 */ import http from 'http'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import { CONFIG, validateConfig } from './config.js'; import { createOrder, getActiveOrders, getArchivedOrders, getAllOrders, findOrder, getOrder, updateStatus, addSubTask, updateSubStatus, updateProgress, setExpectedDays, deliverOrder, archiveOrder, addComment, getRecentOrders, getPendingCount, deleteOrder, flagOrder } from './order-manager.js'; import { analyzeRequirement, generateConfirmation } from './ai-intake.js'; import { filterOrder, getRateStatus } from './spam-filter.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); // 启动检查 const configWarnings = validateConfig(); if (configWarnings.length) configWarnings.forEach(w => console.log(w)); // 路由表 const routes = { '/' : serveStatic('submit.html', 'text/html'), '/submit' : serveStatic('submit.html', 'text/html'), '/admin' : serveStatic('admin.html', 'text/html'), '/track' : serveStatic('track.html', 'text/html'), '/style.css' : serveStatic('style.css', 'text/css'), '/api/orders' : apiOrders, '/api/orders/active': apiActiveOrders, '/api/orders/archived': apiArchivedOrders, '/api/orders/search': apiSearchOrders, '/api/orders/pending': apiPendingCount, '/api/orders/recent': apiRecentOrders, '/api/orders/analyze': apiAnalyze, '/api/health' : apiHealth, }; function serveStatic(file, mime) { return (req, res) => { const p = path.join(__dirname, 'public', file); try { let data = fs.readFileSync(p, 'utf-8'); // 注入站点名称 data = data.replace(/__SITE_NAME__/g, CONFIG.siteName); data = data.replace(/__ADMIN_TOKEN__/g, CONFIG.adminToken); res.writeHead(200, { 'Content-Type': mime }); res.end(data); } catch { res.writeHead(404); res.end('Not found'); } }; } function json(res, data, code = 200) { res.writeHead(code, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }); res.end(JSON.stringify(data)); } function readBody(req) { return new Promise(resolve => { let d = ''; req.on('data', c => d += c); req.on('end', () => { try { resolve(JSON.parse(d)); } catch { resolve({}); } }); }); } function parseUrl(req) { return new URL(req.url, `http://localhost:${CONFIG.port}`); } function getClientIp(req) { return req.headers['x-forwarded-for']?.split(',')[0]?.trim() || req.socket?.remoteAddress || '0.0.0.0'; } // --- API Handlers --- async function apiOrders(req, res) { const url = parseUrl(req); const parts = url.pathname.split('/'); const id = parts.length >= 4 ? parts[3] : null; const ip = getClientIp(req); // Special sub-paths - redirect to specific handlers if (id === 'active') return apiActiveOrders(req, res); if (id === 'archived') return apiArchivedOrders(req, res); if (id === 'search') return apiSearchOrders(req, res); if (id === 'pending') return apiPendingCount(req, res); if (id === 'recent') return apiRecentOrders(req, res); if (id === 'analyze') return apiAnalyze(req, res); // GET if (req.method === 'GET') { if (id) { const order = getOrder(id); if (!order) return json(res, { error: '订单不存在' }, 404); return json(res, order); } return json(res, getAllOrders()); } // POST — 创建订单(含垃圾过滤) if (req.method === 'POST') { const body = await readBody(req); if (!body.requirements || !body.contact) { return json(res, { error: '需求和联系方式不能为空' }, 400); } // 垃圾过滤三道关 const security = filterOrder(body, ip); if (!security.allowed) { return json(res, { error: '提交被拒绝', issues: security.issues, flagged: true, }, 429); } const order = createOrder({ name: body.name, contact: body.contact, contactType: body.contactType || '微信', requirements: body.requirements, budget: body.budget || '', expectedDays: parseInt(body.expectedDays) || 0, source: body.source || 'web', }); // 如果被标记为可疑,自动标记 if (security.flagged) { flagOrder(order.id, true, security.flagReasons?.join('; ') || '系统自动标记'); addComment(order.id, { author: '系统', content: `⚠️ 此订单被自动标记为可疑: ${security.flagReasons?.join('、') || '内容异常'}。请审核。`, side: 'dev' }); } // AI 确认(异步) try { const msg = await generateConfirmation(order); addComment(order.id, { author: '系统', content: msg, side: 'dev' }); } catch {} return json(res, { success: true, order, flagged: security.flagged, flagReasons: security.flagged ? security.flagReasons : undefined, }, 201); } // PUT if (req.method === 'PUT') { const body = await readBody(req); let result; if (body.action === 'status') result = updateStatus(id, body.status); else if (body.action === 'subtask') result = addSubTask(id, body); else if (body.action === 'sub-status') result = updateSubStatus(id, body.subId, body.status); else if (body.action === 'comment') result = addComment(id, body); else if (body.action === 'flag') result = flagOrder(id, body.flagged, body.reason); else if (body.action === 'progress') result = updateProgress(id, body.progress, body.note); else if (body.action === 'set-expected') result = setExpectedDays(id, body.days); else if (body.action === 'deliver') result = deliverOrder(id); else if (body.action === 'archive') result = archiveOrder(id); if (!result) return json(res, { error: '操作失败' }, 400); return json(res, { success: true, data: result }); } // DELETE if (req.method === 'DELETE') { const ok = deleteOrder(id); return json(res, { success: ok }); } } async function apiSearchOrders(req, res) { const q = parseUrl(req).searchParams.get('q') || ''; json(res, findOrder(q)); } function apiPendingCount(req, res) { json(res, { count: getPendingCount() }); } function apiActiveOrders(req, res) { json(res, getActiveOrders()); } function apiArchivedOrders(req, res) { json(res, getArchivedOrders()); } function apiRecentOrders(req, res) { json(res, getRecentOrders(120)); } async function apiAnalyze(req, res) { const body = await readBody(req); if (!body.text) return json(res, { error: '缺少需求文本' }, 400); try { const analysis = await analyzeRequirement(body.text); json(res, analysis || { error: '分析失败' }); } catch (e) { json(res, { error: e.message }, 500); } } function apiHealth(req, res) { json(res, { status: 'ok', site: CONFIG.siteName, version: '1.0.0', aiEnabled: !!CONFIG.deepseekKey && CONFIG.deepseekKey !== 'your-api-key-here', docker: !!process.env.DOCKER, }); } // Server const server = http.createServer((req, res) => { const pathname = parseUrl(req).pathname; if (pathname.startsWith('/api/orders')) return apiOrders(req, res); const handler = routes[pathname]; if (handler) handler(req, res); else { res.writeHead(404); res.end('Not found'); } }); server.listen(CONFIG.port, '0.0.0.0', () => { console.log(`🧰 zhiqiu-order-system v1.0`); console.log(` 📋 客户提交: http://0.0.0.0:${CONFIG.port}/submit`); console.log(` 🔧 管理面板: http://0.0.0.0:${CONFIG.port}/admin`); console.log(` 🔍 订单追踪: http://0.0.0.0:${CONFIG.port}/track`); console.log(` 🤖 AI 辅助: ${CONFIG.deepseekKey && CONFIG.deepseekKey !== 'your-api-key-here' ? '已启用' : '未配置'}`); });