const express = require('express'); const router = express.Router(); const { pool } = require('../config/db'); const crypto = require('crypto'); // 安全解析 JSON 或返回原值 const safeParseJSON = (data) => { if (typeof data === 'string') { try { return JSON.parse(data); } catch (e) { return null; } } return data; }; // 获取所有职位 router.get('/', async (req, res) => { try { const [jobs] = await pool.query(` SELECT id, title, department, location, description, status, pending_resumes AS pendingResumes, passed_resumes AS passedResumes, ai_criteria AS aiCriteria, created_at AS createdAt, updated_at AS updatedAt FROM jobs WHERE status != 'deleted' ORDER BY created_at DESC `); // 安全解析 aiCriteria const processedJobs = jobs.map(job => ({ ...job, aiCriteria: safeParseJSON(job.aiCriteria) })); res.json(processedJobs); } catch (error) { console.error('Get jobs error:', error); res.status(500).json({ error: 'Server error' }); } }); // 创建新职位(修正版) router.post('/', async (req, res) => { const connection = await pool.getConnection(); try { await connection.beginTransaction(); const { title, department, location, description = '', // 默认空字符串 status = 'draft', pendingResumes = 0, // 添加默认值 passedResumes = 0, // 添加默认值 aiCriteria = {} // 默认空对象 } = req.body; // 直接插入,使用数据库自增ID const [result] = await connection.query( `INSERT INTO jobs ( title, department, location, description, status, pending_resumes, passed_resumes, ai_criteria, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [ title, department, location, description, status, pendingResumes, passedResumes, JSON.stringify(aiCriteria), new Date(), new Date() ] ); // 获取新创建的记录 const [newJob] = await connection.query( 'SELECT * FROM jobs WHERE id = ?', [result.insertId] ); await connection.commit(); res.status(201).json({ ...newJob[0], id: newJob[0].id, // 保持原始数值ID pendingResumes: newJob[0].pending_resumes, passedResumes: newJob[0].passed_resumes, aiCriteria: safeParseJSON(newJob[0].ai_criteria), createdAt: newJob[0].created_at, updatedAt: newJob[0].updated_at }); } catch (error) { await connection.rollback(); console.error('Create job error:', error); res.status(500).json({ error: 'Failed to create job', details: process.env.NODE_ENV === 'development' ? { message: error.message, stack: error.stack } : undefined }); } finally { connection.release(); } }); // 更新职位 router.put('/:id', async (req, res) => { try { const { id } = req.params; const updates = req.body; const updateFields = []; const queryParams = []; // 动态构建更新语句 for (const [key, value] of Object.entries(updates)) { if (key === 'aiCriteria') { updateFields.push('ai_criteria = ?'); queryParams.push(JSON.stringify(value)); } else { updateFields.push(`${key} = ?`); queryParams.push(value); } } if (updateFields.length === 0) { return res.status(400).json({ error: 'No fields to update' }); } queryParams.push(id); await pool.query( `UPDATE jobs SET ${updateFields.join(', ')}, updated_at = ? WHERE id = ?`, [...queryParams, new Date()] ); const [updatedJob] = await pool.query( 'SELECT * FROM jobs WHERE id = ?', [id] ); if (updatedJob.length === 0) { return res.status(404).json({ error: 'Job not found' }); } res.json({ ...updatedJob[0], pendingResumes: updatedJob[0].pending_resumes, passedResumes: updatedJob[0].passed_resumes, aiCriteria: safeParseJSON(updatedJob[0].ai_criteria), createdAt: updatedJob[0].created_at, updatedAt: updatedJob[0].updated_at }); } catch (error) { console.error('Update job error:', error); res.status(500).json({ error: 'Server error' }); } }); // 删除职位 router.delete('/:id', async (req, res) => { try { const { id } = req.params; // 软删除 await pool.query( `UPDATE jobs SET status = 'deleted', updated_at = ? WHERE id = ?`, [new Date(), id] ); res.status(204).end(); } catch (error) { console.error('Delete job error:', error); res.status(500).json({ error: 'Server error' }); } }); // 触发职位筛选 router.post('/:id/screen', async (req, res) => { try { const { id } = req.params; // 获取职位信息 const [jobs] = await pool.query( 'SELECT * FROM jobs WHERE id = ?', [id] ); if (jobs.length === 0) { return res.status(404).json({ error: 'Job not found' }); } const job = jobs[0]; // 使用安全解析方法 const aiCriteria = safeParseJSON(job.ai_criteria); if (!aiCriteria) { return res.status(400).json({ error: 'Invalid AI criteria format' }); } // 这里应该调用AI筛选逻辑 // 模拟筛选过程 await new Promise(resolve => setTimeout(resolve, 2000)); // 更新筛选结果 const [candidates] = await pool.query( 'SELECT id FROM candidates WHERE job_id = ?', [id] ); const passedCount = Math.floor(candidates.length * 0.6); await pool.query( `UPDATE jobs SET pending_resumes = ?, passed_resumes = ?, updated_at = ? WHERE id = ?`, [candidates.length, passedCount, new Date(), id] ); // 更新候选人状态 await pool.query( `UPDATE candidates SET status = CASE WHEN RAND() < 0.6 THEN 'passed' ELSE 'rejected' END WHERE job_id = ? AND status = 'pending'`, [id] ); const [updatedJob] = await pool.query( 'SELECT * FROM jobs WHERE id = ?', [id] ); res.json({ ...updatedJob[0], pendingResumes: updatedJob[0].pending_resumes, passedResumes: updatedJob[0].passed_resumes, aiCriteria: safeParseJSON(updatedJob[0].ai_criteria), createdAt: updatedJob[0].created_at, updatedAt: updatedJob[0].updated_at }); } catch (error) { console.error('Screen job error:', error); res.status(500).json({ error: 'Server error' }); } }); module.exports = router;