3 Incheckningar cde626fb97 ... 348b735c30

Upphovsman SHA1 Meddelande Datum
  aaww-1216 348b735c30 2 1 vecka sedan
  aaww-1216 3d84d2a992 1 1 vecka sedan
  aaww-1216 3c94b01006 更新代码 2 veckor sedan
5 ändrade filer med 190 tillägg och 80 borttagningar
  1. 0 2
      README.md
  2. 1 1
      ai-interview
  3. 22 17
      recruitment-backend/app.js
  4. 2 0
      recruitment-backend/routes/candidates.js
  5. 165 60
      recruitment-backend/routes/jobs.js

+ 0 - 2
README.md

@@ -62,5 +62,3 @@ npm run dev
 **组长**:
 **组长**:
 **组员**:
 **组员**:
 
 
----
-

+ 1 - 1
ai-interview

@@ -1 +1 @@
-Subproject commit cd422a750939c90aec0ccb76bc5abd6c1511dd88
+Subproject commit 37aa102a27c594de57fb49e4c42db56d63f7970b

+ 22 - 17
recruitment-backend/app.js

@@ -3,25 +3,30 @@ const express = require('express');
 const cors = require('cors');
 const cors = require('cors');
 const helmet = require('helmet');
 const helmet = require('helmet');
 const morgan = require('morgan');
 const morgan = require('morgan');
-const { pool } = require('./config/db'); // 添加这行导入
-const routes = require('./routes');
+const { pool } = require('./config/db');
+const routes = require('./routes'); // 确保这里导入的是整合所有路由的入口文件
 const errorHandler = require('./middlewares/error');
 const errorHandler = require('./middlewares/error');
 
 
 const app = express();
 const app = express();
 
 
-// 中间件
-app.use(cors());
+// CORS 配置
+const corsOptions = {
+  origin: 'http://localhost:5173',
+  credentials: true,
+  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
+  allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
+  optionsSuccessStatus: 200
+};
+
+// 中间件配置
+app.use(cors(corsOptions)); // 只保留这一个 CORS 中间件
+app.options('*', cors(corsOptions)); // 预检请求处理
 app.use(helmet());
 app.use(helmet());
 app.use(morgan('dev'));
 app.use(morgan('dev'));
 app.use(express.json());
 app.use(express.json());
 app.use(express.urlencoded({ extended: true }));
 app.use(express.urlencoded({ extended: true }));
-app.use(cors({
-  origin: process.env.FRONTEND_URL || 'http://localhost:5173', // 假设 Vue 运行在 5173
-  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
-  allowedHeaders: ['Content-Type', 'Authorization']
-}));
 
 
-// 测试数据库连接的路由
+// 测试路由
 app.get('/test-db', async (req, res) => {
 app.get('/test-db', async (req, res) => {
   try {
   try {
     const [rows] = await pool.query('SELECT 1 + 1 AS result');
     const [rows] = await pool.query('SELECT 1 + 1 AS result');
@@ -34,17 +39,17 @@ app.get('/test-db', async (req, res) => {
     console.error('数据库连接测试失败:', error);
     console.error('数据库连接测试失败:', error);
     res.status(500).json({
     res.status(500).json({
       success: false,
       success: false,
-      error: error.message,
-      code: error.code, // 添加数据库错误代码
-      stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
+      error: error.message
     });
     });
   }
   }
 });
 });
 
 
-// 注册路由
-app.use('/api', routes);
+// 路由注册 (关键修正点)
+// 注意:这里只需要使用 routes,不需要单独再挂载 jobsRouter
+// 因为 routes/index.js 应该已经整合了所有子路由
+app.use('/api', routes); 
 
 
-// 错误处理中间件(必须放在所有路由之后)
+// 错误处理
 app.use(errorHandler);
 app.use(errorHandler);
 
 
 // 404 处理
 // 404 处理
@@ -59,7 +64,7 @@ app.use((req, res) => {
 const PORT = process.env.PORT || 3000;
 const PORT = process.env.PORT || 3000;
 app.listen(PORT, () => {
 app.listen(PORT, () => {
   console.log(`Server running on port ${PORT}`);
   console.log(`Server running on port ${PORT}`);
-  console.log(`测试数据库连接: http://localhost:${PORT}/test-db`);
+  console.log(`测试地址: http://localhost:${PORT}/test-db`);
 });
 });
 
 
 module.exports = app;
 module.exports = app;

+ 2 - 0
recruitment-backend/routes/candidates.js

@@ -73,6 +73,8 @@ function formatCandidate(candidate) {
     reviewedAt: candidate.reviewed_at || candidate.reviewedAt || null
     reviewedAt: candidate.reviewed_at || candidate.reviewedAt || null
   };
   };
 }
 }
+// 删除职位 (软删除)
+// 删除职位 (软删除)
 
 
 // 获取所有候选人
 // 获取所有候选人
 router.get('/', async (req, res) => {
 router.get('/', async (req, res) => {

+ 165 - 60
recruitment-backend/routes/jobs.js

@@ -14,6 +14,47 @@ const safeParseJSON = (data) => {
   }
   }
   return data;
   return data;
 };
 };
+router.put('/jobs/:id', async (req, res) => {
+  const { id } = req.params;
+  const updates = req.body;
+
+  try {
+    // 构建动态更新语句
+    const updateFields = [];
+    const values = [];
+    
+    for (const [key, value] of Object.entries(updates)) {
+      updateFields.push(`${key} = ?`);
+      values.push(value);
+    }
+    
+    if (updateFields.length === 0) {
+      return res.status(400).json({ error: 'No fields to update' });
+    }
+    
+    values.push(id);
+    
+    const query = `
+      UPDATE jobs 
+      SET ${updateFields.join(', ')}, updated_at = NOW()
+      WHERE id = ?
+    `;
+    
+    const [result] = await pool.query(query, values);
+    
+    if (result.affectedRows === 0) {
+      return res.status(404).json({ error: 'Job not found' });
+    }
+    
+    // 返回更新后的职位信息
+    const [updatedJob] = await pool.query('SELECT * FROM jobs WHERE id = ?', [id]);
+    res.json(updatedJob[0]);
+    
+  } catch (error) {
+    console.error('Update job error:', error);
+    res.status(500).json({ error: 'Database error' });
+  }
+});
 
 
 // 获取所有职位
 // 获取所有职位
 router.get('/', async (req, res) => {
 router.get('/', async (req, res) => {
@@ -43,6 +84,79 @@ router.get('/', async (req, res) => {
   }
   }
 });
 });
 
 
+// 更新职位信息
+router.put('/:id', async (req, res) => {
+  const { id } = req.params;
+  const updates = req.body;
+
+  // 验证必要字段
+  if (!updates || Object.keys(updates).length === 0) {
+    return res.status(400).json({ 
+      error: '请求体不能为空',
+      example: {
+        title: "新职位标题",
+        description: "职位描述"
+      }
+    });
+  }
+
+  try {
+    // 只允许更新特定字段
+    const allowedFields = ['title', 'description', 'department', 'location', 'status'];
+    const updateFields = [];
+    const values = [];
+    
+    for (const [key, value] of Object.entries(updates)) {
+      if (allowedFields.includes(key)) {
+        updateFields.push(`${key} = ?`);
+        values.push(value);
+      }
+    }
+    
+    if (updateFields.length === 0) {
+      return res.status(400).json({ 
+        error: '没有有效的字段可更新',
+        allowedFields
+      });
+    }
+    
+    values.push(id);
+    
+    const query = `
+      UPDATE jobs 
+      SET ${updateFields.join(', ')}, updated_at = NOW()
+      WHERE id = ?
+    `;
+    
+    const [result] = await pool.query(query, values);
+    
+    if (result.affectedRows === 0) {
+      return res.status(404).json({ 
+        error: '职位不存在或未更改',
+        jobId: id
+      });
+    }
+    
+    // 返回更新后的数据
+    const [updatedJob] = await pool.query(
+      'SELECT * FROM jobs WHERE id = ?',
+      [id]
+    );
+    
+    res.json({
+      success: true,
+      data: updatedJob[0]
+    });
+    
+  } catch (error) {
+    console.error('数据库更新错误:', error);
+    res.status(500).json({ 
+      error: '更新职位信息失败',
+      details: process.env.NODE_ENV === 'development' ? error.message : null
+    });
+  }
+});
+
 // 创建新职位(修正版)
 // 创建新职位(修正版)
 router.post('/', async (req, res) => {
 router.post('/', async (req, res) => {
   const connection = await pool.getConnection();
   const connection = await pool.getConnection();
@@ -113,83 +227,74 @@ router.post('/', async (req, res) => {
     connection.release();
     connection.release();
   }
   }
 });
 });
-
-// 更新职位
-router.put('/:id', async (req, res) => {
+router.delete('/:id', async (req, res) => {
+  const { id } = req.params;
+  
   try {
   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 = ?',
+    // 使用软删除,将状态标记为deleted
+    const [result] = await pool.query(
+      `UPDATE jobs SET status = 'deleted', updated_at = NOW() WHERE id = ? AND status != 'deleted'`,
       [id]
       [id]
     );
     );
     
     
-    if (updatedJob.length === 0) {
-      return res.status(404).json({ error: 'Job not found' });
+    if (result.affectedRows === 0) {
+      return res.status(404).json({
+        success: false,
+        error: '职位不存在或已被删除'
+      });
     }
     }
     
     
-    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
-    });
+    // 成功删除返回204 No Content
+    res.status(204).end();
     
     
   } catch (error) {
   } catch (error) {
-    console.error('Update job error:', error);
-    res.status(500).json({ error: 'Server error' });
+    console.error('删除职位失败:', error);
+    res.status(500).json({
+      success: false,
+      error: '删除职位失败',
+      details: process.env.NODE_ENV === 'development' ? error.message : undefined
+    });
   }
   }
 });
 });
+// 更新职位
+router.put('/:id/status', async (req, res) => {
+  const { id } = req.params;
+  const { status } = req.body;
+
+  // 验证状态值
+  if (!['active', 'paused'].includes(status)) {
+    return res.status(400).json({ 
+      success: false,
+      error: '无效的状态值',
+      allowed: ['active', 'paused']
+    });
+  }
 
 
-// 删除职位
-router.delete('/:id', async (req, res) => {
   try {
   try {
-    const { id } = req.params;
-    
-    // 软删除
-    await pool.query(
-      `UPDATE jobs SET status = 'deleted', updated_at = ? 
-       WHERE id = ?`,
-      [new Date(), id]
+    const [result] = await pool.query(
+      `UPDATE jobs SET status = ?, updated_at = NOW() WHERE id = ?`,
+      [status, id]
     );
     );
     
     
-    res.status(204).end();
+    if (result.affectedRows === 0) {
+      return res.status(404).json({ 
+        success: false,
+        error: '职位不存在'
+      });
+    }
+    
+    res.json({ 
+      success: true,
+      message: '状态更新成功'
+    });
   } catch (error) {
   } catch (error) {
-    console.error('Delete job error:', error);
-    res.status(500).json({ error: 'Server error' });
+    console.error('状态更新失败:', error);
+    res.status(500).json({ 
+      success: false,
+      error: '服务器错误'
+    });
   }
   }
 });
 });
-
 // 触发职位筛选
 // 触发职位筛选
 router.post('/:id/screen', async (req, res) => {
 router.post('/:id/screen', async (req, res) => {
   try {
   try {