import db from '../../db' import bcrypt from 'bcryptjs' import type { User, Role } from './types' export const SALT_ROUNDS = 10 export function getRoles(): Role[] { const stmt = db.prepare('SELECT * FROM roles ORDER BY is_system DESC, id ASC') const rows = stmt.all() as any[] return rows.map(row => ({ ...row, permissions: JSON.parse(row.permissions || '[]') })) } export function getRoleByName(name: string): Role | undefined { const stmt = db.prepare('SELECT * FROM roles WHERE name = ?') const row = stmt.get(name) as any if (!row) return undefined return { ...row, permissions: JSON.parse(row.permissions || '[]') } } export function createRole(name: string, description: string, permissions: string[], isSystem = false): Role { const stmt = db.prepare( 'INSERT INTO roles (name, description, permissions, is_system) VALUES (?, ?, ?, ?)' ) const result = stmt.run(name, description, JSON.stringify(permissions), isSystem ? 1 : 0) return { id: Number(result.lastInsertRowid), name, description, permissions, is_system: isSystem, created_at: new Date().toISOString() } } export function getUsers(options?: { roleId?: number; status?: string }): User[] { let sql = 'SELECT u.*, r.name as role_name, r.permissions as role_permissions FROM users u LEFT JOIN roles r ON u.role_id = r.id WHERE 1=1' const params: any[] = [] if (options?.roleId) { sql += ' AND u.role_id = ?' params.push(options.roleId) } if (options?.status) { sql += ' AND u.status = ?' params.push(options.status) } sql += ' ORDER BY u.created_at DESC' const stmt = db.prepare(sql) const rows = stmt.all(...params) as any[] return rows.map(row => ({ ...row, permissions: JSON.parse(row.role_permissions || '[]') })) } export function getUserById(id: number): User | undefined { const stmt = db.prepare('SELECT u.*, r.name as role_name, r.permissions as role_permissions FROM users u LEFT JOIN roles r ON u.role_id = r.id WHERE u.id = ?') const row = stmt.get(id) as any if (!row) return undefined return { ...row, permissions: JSON.parse(row.role_permissions || '[]') } } export function getUserByUsername(username: string): User | undefined { const stmt = db.prepare('SELECT u.*, r.name as role_name, r.permissions as role_permissions FROM users u LEFT JOIN roles r ON u.role_id = r.id WHERE u.username = ?') const row = stmt.get(username) as any if (!row) return undefined return { ...row, permissions: JSON.parse(row.role_permissions || '[]') } } export function getUserByEmail(email: string): User | undefined { const stmt = db.prepare('SELECT u.*, r.name as role_name, r.permissions as role_permissions FROM users u LEFT JOIN roles r ON u.role_id = r.id WHERE u.email = ?') const row = stmt.get(email) as any if (!row) return undefined return { ...row, permissions: JSON.parse(row.role_permissions || '[]') } } export async function createUser( username: string, passwordHash: string, email?: string, realName?: string, roleId = 2 ): Promise { const stmt = db.prepare( 'INSERT INTO users (username, password_hash, email, real_name, role_id) VALUES (?, ?, ?, ?, ?)' ) const result = stmt.run(username, passwordHash, email || null, realName || null, roleId) return getUserById(Number(result.lastInsertRowid))! } export async function updateUser( id: number, data: { email?: string realName?: string roleId?: number status?: string avatar?: string } ): Promise { const updates: string[] = [] const params: any[] = [] if (data.email !== undefined) { updates.push('email = ?') params.push(data.email) } if (data.realName !== undefined) { updates.push('real_name = ?') params.push(data.realName) } if (data.roleId !== undefined) { updates.push('role_id = ?') params.push(data.roleId) } if (data.status !== undefined) { updates.push('status = ?') params.push(data.status) } if (data.avatar !== undefined) { updates.push('avatar = ?') params.push(data.avatar) } if (updates.length === 0) return getUserById(id) updates.push('updated_at = CURRENT_TIMESTAMP') params.push(id) const stmt = db.prepare(`UPDATE users SET ${updates.join(', ')} WHERE id = ?`) stmt.run(...params) return getUserById(id) } export async function updatePassword(id: number, newPasswordHash: string): Promise { const stmt = db.prepare('UPDATE users SET password_hash = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?') stmt.run(newPasswordHash, id) } export function deleteUser(id: number): boolean { const stmt = db.prepare('DELETE FROM users WHERE id = ?') const result = stmt.run(id) return result.changes > 0 } export function updateLastLogin(id: number): void { const stmt = db.prepare('UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?') stmt.run(id) } export function incrementLoginAttempts(id: number, lockedUntil?: Date): void { if (lockedUntil) { const stmt = db.prepare('UPDATE users SET login_attempts = login_attempts + 1, locked_until = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?') stmt.run(lockedUntil.toISOString(), id) } else { const stmt = db.prepare('UPDATE users SET login_attempts = login_attempts + 1, updated_at = CURRENT_TIMESTAMP WHERE id = ?') stmt.run(id) } } export function resetLoginAttempts(id: number): void { const stmt = db.prepare('UPDATE users SET login_attempts = 0, locked_until = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?') stmt.run(id) } export function hashPassword(password: string): string { return bcrypt.hashSync(password, SALT_ROUNDS) } export function verifyPassword(password: string, hash: string): boolean { return bcrypt.compareSync(password, hash) } export function validatePassword(password: string): { valid: boolean; message?: string } { if (password.length < 6) { return { valid: false, message: '密码长度至少6位' } } if (/^\d+$/.test(password)) { return { valid: false, message: '密码不能为纯数字' } } return { valid: true } }