// routes/employees.js —— 员工管理 CRUD(纯数据库操作,权限由中间件层控制) const { pool } = require('../db') const bcrypt = require('bcryptjs') // 格式化日期为 YYYY-MM-DD function formatDate(dateStr) { if (!dateStr) return null if (typeof dateStr === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(dateStr)) { return dateStr // 已经是正确格式 } try { const date = new Date(dateStr) if (isNaN(date.getTime())) return null const year = date.getFullYear() const month = String(date.getMonth() + 1).padStart(2, '0') const day = String(date.getDate()).padStart(2, '0') return `${year}-${month}-${day}` } catch { return null } } function pagination(query) { const page = Math.max(Number(query.page) || 1, 1) const pageSize = Math.min(Math.max(Number(query.pageSize) || 10, 1), 100) const offset = (page - 1) * pageSize return { page, pageSize, offset } } // GET /api/employees —— 列表 async function list(req, res) { try { const { page, pageSize, offset } = pagination(req.query) const { id, name, status, department } = req.query let where = 'WHERE 1=1' const params = [] // 数据范围过滤(由中间件注入 req.scope) if (req.scope && req.scope.sql) { where += ' ' + req.scope.sql params.push(...req.scope.params) } if (id) { where += ' AND id = ?' params.push(Number(id)) } if (name) { where += ' AND name LIKE ?' params.push(`%${name}%`) } if (status !== undefined && status !== '') { where += ' AND status = ?' params.push(Number(status)) } if (department) { where += ' AND department LIKE ?' params.push(`%${department}%`) } const [[{ total }]] = await pool.query( `SELECT COUNT(*) AS total FROM employees ${where}`, params ) const [rows] = await pool.query( `SELECT * FROM employees ${where} ORDER BY id ASC LIMIT ? OFFSET ?`, [...params, pageSize, offset] ) res.json({ code: 0, message: 'ok', data: { list: rows, total, page, pageSize, totalPages: Math.ceil(total / pageSize), }, }) } catch (e) { console.error('[employees list] error:', e) res.status(500).json({ code: 500, message: e.message }) } } // GET /api/employees/:id —— 详情 async function detail(req, res) { try { let sql = 'SELECT * FROM employees WHERE id = ?' const params = [req.params.id] // 数据范围过滤(由中间件注入 req.scope) if (req.scope && req.scope.sql) { sql += ' ' + req.scope.sql params.push(...req.scope.params) } const [rows] = await pool.query(sql, params) if (rows.length === 0) { return res.status(404).json({ code: 404, message: '员工不存在' }) } res.json({ code: 0, message: 'ok', data: rows[0] }) } catch (e) { console.error('[employees detail] error:', e) res.status(500).json({ code: 500, message: e.message }) } } // POST /api/employees —— 新增 async function create(req, res) { const { name, gender, age, education, department, entry_date, position, salary, phone, email, status, remark, } = req.body || {} if (!name) { return res.status(400).json({ code: 400, message: '员工姓名必填' }) } try { const [result] = await pool.query( `INSERT INTO employees (name, gender, age, education, department, entry_date, position, salary, phone, email, status, remark) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [name, gender || null, age !== undefined ? age : null, education || null, department || null, formatDate(entry_date), position || null, salary !== undefined ? salary : null, phone || null, email || null, status !== undefined ? status : 1, remark || null] ) const [rows] = await pool.query('SELECT * FROM employees WHERE id = ?', [result.insertId]) // 如果中间件 allowUserCreation 要求同步创建用户账号 if (req._createUser) { const { username, password, department_id } = req._createUser const hash = await bcrypt.hash(password, 10) await pool.query( 'INSERT INTO users (username, password, is_active, department_id, employee_id) VALUES (?, ?, 1, ?, ?)', [username, hash, department_id, result.insertId] ) delete req._createUser // 清理,避免影响后续中间件 } res.json({ code: 0, message: 'ok', data: rows[0] }) } catch (e) { console.error('[employees create] error:', e) res.status(500).json({ code: 500, message: e.message }) } } // PUT /api/employees/:id —— 更新 async function update(req, res) { const { id } = req.params const fields = [ 'name', 'gender', 'age', 'education', 'department', 'entry_date', 'position', 'salary', 'phone', 'email', 'status', 'remark', ] try { // 确认记录存在且在数据范围内 let checkSql = 'SELECT id FROM employees WHERE id = ?' let checkParams = [id] if (req.scope && req.scope.sql) { checkSql += ' ' + req.scope.sql checkParams.push(...req.scope.params) } const [existing] = await pool.query(checkSql, checkParams) if (existing.length === 0) { return res.status(404).json({ code: 404, message: '员工不存在或无权操作' }) } const sets = [] const params = [] for (const f of fields) { if (req.body[f] !== undefined) { sets.push(`${f} = ?`) // 日期字段需要格式化 if (f === 'entry_date') { params.push(formatDate(req.body[f])) } else { params.push(req.body[f]) } } } if (sets.length === 0) { return res.status(400).json({ code: 400, message: '没有需要更新的字段' }) } params.push(id) await pool.query(`UPDATE employees SET ${sets.join(', ')} WHERE id = ?`, params) // 部门联动:员工部门变更时同步更新关联用户的部门 if (req.body.department !== undefined) { const [[dept]] = await pool.query('SELECT id FROM departments WHERE description = ?', [req.body.department]) if (dept) { await pool.query('UPDATE users SET department_id = ? WHERE employee_id = ?', [dept.id, id]) } } // 状态联动:员工离职时同步禁用关联用户,复职时同步启用 if (req.body.status !== undefined) { const isActive = req.body.status === 1 ? 1 : 0 await pool.query('UPDATE users SET is_active = ? WHERE employee_id = ?', [isActive, id]) } const [rows] = await pool.query('SELECT * FROM employees WHERE id = ?', [id]) res.json({ code: 0, message: 'ok', data: rows[0] }) } catch (e) { console.error('[employees update] error:', e) res.status(500).json({ code: 500, message: e.message }) } } // DELETE /api/employees/:id —— 删除 async function remove(req, res) { const { id } = req.params try { let checkSql = 'SELECT id FROM employees WHERE id = ?' let checkParams = [id] if (req.scope && req.scope.sql) { checkSql += ' ' + req.scope.sql checkParams.push(...req.scope.params) } const [existing] = await pool.query(checkSql, checkParams) if (existing.length === 0) { return res.status(404).json({ code: 404, message: '员工不存在或无权操作' }) } // 禁止删除自己关联的员工 const [selfCheck] = await pool.query('SELECT id FROM users WHERE employee_id = ? AND id = ?', [id, req.user.id]) if (selfCheck.length > 0) { return res.status(400).json({ code: 400, message: '不能删除自己的员工账号' }) } // 同步删除关联的用户账号 await pool.query('DELETE FROM users WHERE employee_id = ?', [id]) await pool.query('DELETE FROM employees WHERE id = ?', [id]) res.json({ code: 0, message: 'ok' }) } catch (e) { console.error('[employees delete] error:', e) if (e.code === 'ER_ROW_IS_REFERENCED_2') { return res.status(400).json({ code: 400, message: '该员工被合同或售后记录引用,无法删除' }) } res.status(500).json({ code: 500, message: e.message }) } } // GET /api/employees/simple —— 简易员工列表(无数据范围限制,用于下拉选择) async function simpleList(req, res) { try { const { department } = req.query let sql = 'SELECT id, name, department, position FROM employees WHERE status = 1' const params = [] if (department) { sql += ' AND department = ?' params.push(department) } sql += ' ORDER BY id' const [rows] = await pool.query(sql, params) res.json({ code: 0, message: 'ok', data: rows }) } catch (e) { console.error('[employees simpleList] error:', e) res.status(500).json({ code: 500, message: e.message }) } } module.exports = { list, detail, create, update, remove, simpleList }