const express = require('express'); const router = express.Router(); const bcrypt = require('bcryptjs'); const db = require('../db'); const { verifyToken, isSuperAdmin, isSystemAdmin } = require('../middleware/auth'); // 搜索用户 (所有登录用户可用,用于成果录入选择作者) router.get('/search', verifyToken, async (req, res) => { const { keyword, leaderOnly } = req.query; if (!keyword) return res.json([]); try { let query = ` SELECT id, username as phone, real_name, department FROM users WHERE (username ILIKE $1 OR real_name ILIKE $1) `; const params = [`%${keyword}%`]; if (leaderOnly === 'true') { // 获取所有领导层部门 const leaderDeptsRes = await db.query('SELECT name FROM dict_leader_departments'); const leaderDepts = leaderDeptsRes.rows.map(r => r.name); if (leaderDepts.length > 0) { query += ` AND department = ANY($${params.length + 1})`; params.push(leaderDepts); } else { // 如果没有配置领导层部门,则返回空 return res.json([]); } } query += ` LIMIT 20`; const result = await db.query(query, params); res.json(result.rows); } catch (err) { console.error(err); res.status(500).json({ message: '服务器错误' }); } }); // 获取所有待定状态用户的手机号列表 (用于前端标红显示) router.get('/pending-list', verifyToken, async (req, res) => { try { const result = await db.query('SELECT username FROM users WHERE dept_status = \'pending\''); const phones = result.rows.map(row => row.username); res.json(phones); } catch (err) { res.status(500).json({ message: '服务器错误' }); } }); // 获取所有用户列表 (系统管理员:超管或维护员) router.get('/', verifyToken, isSystemAdmin, async (req, res) => { const { keyword } = req.query; try { let query = 'SELECT id, username, role, real_name, department, dept_status, created_at FROM users WHERE 1=1'; const params = []; if (keyword) { query += ` AND (username ILIKE $1 OR real_name ILIKE $1 OR department ILIKE $1)`; params.push(`%${keyword}%`); } query += ' ORDER BY created_at DESC'; const result = await db.query(query, params); res.json(result.rows); } catch (err) { res.status(500).json({ message: '服务器错误' }); } }); // 创建新用户 (仅超管) router.post('/', verifyToken, isSuperAdmin, async (req, res) => { const { username, password, role, real_name, department: inputDepartment } = req.body; let department = inputDepartment; if (!username || !password || !role) { return res.status(400).json({ message: '缺少必填字段 (username, password, role)' }); } try { // 手机号格式校验 if (!/^1[3-9]\d{9}$/.test(username)) { return res.status(400).json({ message: '手机号格式不正确' }); } const userExists = await db.query('SELECT * FROM users WHERE username = $1', [username]); if (userExists.rows.length > 0) { return res.status(400).json({ message: '该手机号已注册' }); } // 校验部门 let deptStatus = 'verified'; if (['admin', 'user'].includes(role)) { if (!department) { return res.status(400).json({ message: '该角色必须指定部门' }); } const deptCheck = await db.query('SELECT * FROM departments WHERE name = $1', [department]); deptStatus = deptCheck.rows.length > 0 ? 'verified' : 'pending'; } else { // super_admin 或 maintainer 可以没有部门 if (!department) department = null; } const salt = await bcrypt.genSalt(10); const passwordHash = await bcrypt.hash(password, salt); const result = await db.query( 'INSERT INTO users (username, password_hash, role, real_name, department, dept_status) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id, username, role, real_name, department, dept_status', [username, passwordHash, role, real_name, department, deptStatus] ); res.status(201).json(result.rows[0]); } catch (err) { res.status(500).json({ message: '服务器错误' }); } }); // 修改用户信息 (系统管理员:超管或维护员) router.put('/:id', verifyToken, isSystemAdmin, async (req, res) => { const { id } = req.params; let { username, role, real_name, department, password } = req.body; // 如果是维护员,只能修改密码,忽略其他字段 if (req.user.role === 'maintainer') { if (!password) { return res.json({ message: '未提供新密码,无任何修改' }); } try { const salt = await bcrypt.genSalt(10); const passwordHash = await bcrypt.hash(password, salt); await db.query( 'UPDATE users SET password_hash=$1, token_version = CASE WHEN token_version >= 2000000000 THEN 1 ELSE token_version + 1 END WHERE id=$2', [passwordHash, id] ); return res.json({ message: '密码重置成功' }); } catch (err) { return res.status(500).json({ message: '服务器错误' }); } } // 以下逻辑仅适用于超级管理员 (super_admin) try { // 手机号格式校验 if (!/^1[3-9]\d{9}$/.test(username)) { return res.status(400).json({ message: '手机号格式不正确' }); } // 校验部门 let deptStatus = 'verified'; if (['admin', 'user'].includes(role)) { if (!department) { return res.status(400).json({ message: '该角色必须指定部门' }); } const deptCheck = await db.query('SELECT * FROM departments WHERE name = $1', [department]); deptStatus = deptCheck.rows.length > 0 ? 'verified' : 'pending'; } else { // super_admin 或 maintainer 可以没有部门 if (!department) department = null; } let query = 'UPDATE users SET username=$1, role=$2, real_name=$3, department=$4, dept_status=$5'; let params = [username, role, real_name, department, deptStatus, id]; if (password) { const salt = await bcrypt.genSalt(10); const passwordHash = await bcrypt.hash(password, salt); query += ', password_hash=$6, token_version = CASE WHEN token_version >= 2000000000 THEN 1 ELSE token_version + 1 END WHERE id=$7'; params = [username, role, real_name, department, deptStatus, passwordHash, id]; } else { query += ' WHERE id=$6'; } await db.query(query, params); res.json({ message: '修改成功' }); } catch (err) { res.status(500).json({ message: '服务器错误' }); } }); // 删除用户 (仅超管) router.delete('/:id', verifyToken, isSuperAdmin, async (req, res) => { const { id } = req.params; try { // 防止删除自己 if (parseInt(id) === req.user.id) { return res.status(400).json({ message: '不能删除当前登录账号' }); } // 检查是否有关联的成果 const achievementCheck = await db.query('SELECT id FROM achievements WHERE user_id = $1 LIMIT 1', [id]); if (achievementCheck.rows.length > 0) { return res.status(400).json({ message: '该用户有关联的成果数据,无法直接删除。请先处理关联数据。' }); } await db.query('DELETE FROM users WHERE id = $1', [id]); res.json({ message: '删除成功' }); } catch (err) { console.error(err); res.status(500).json({ message: '服务器错误' }); } }); module.exports = router;