| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- import { Hono } from 'hono'
- import { authMiddleware, requireRole } from '../middleware/auth'
- import { hashPassword } from '../utils/password'
- import { generateId } from '../utils/jwt'
- import type { Env, ApiResponse, PageResponse, User, UserPermission } from '../types'
- const user = new Hono<{ Bindings: Env }>()
- /**
- * 创建成功响应
- */
- function success<T>(data: T, msg = 'success'): ApiResponse<T> {
- return { code: 200, msg, data }
- }
- /**
- * 创建错误响应
- */
- function error(msg: string, code = 500): ApiResponse<null> {
- return { code, msg, data: null }
- }
- // 所有用户管理接口都需要认证和 admin 角色
- user.use('*', authMiddleware())
- user.use('*', requireRole('admin'))
- // ==================== 用户管理 ====================
- /**
- * 获取用户列表
- * GET /api/users
- */
- user.get('/', async (c) => {
- try {
- const { role, status, search, pageSize = '20', page = '1' } = c.req.query()
- const limit = Math.min(parseInt(pageSize), 100)
- const offset = (parseInt(page) - 1) * limit
- let sql = 'SELECT id, username, email, role, status, last_login, created_at, updated_at FROM users WHERE is_deleted = 0'
- const params: (string | number)[] = []
- if (role) {
- sql += ' AND role = ?'
- params.push(role)
- }
- if (status) {
- sql += ' AND status = ?'
- params.push(status)
- }
- if (search) {
- sql += ' AND (username LIKE ? OR email LIKE ?)'
- params.push(`%${search}%`, `%${search}%`)
- }
- // 获取总数
- const countResult = await c.env.DB
- .prepare(sql.replace('SELECT id, username, email, role, status, last_login, created_at, updated_at', 'SELECT COUNT(*) as count'))
- .bind(...params)
- .first<{ count: number }>()
- // 获取分页数据
- sql += ' ORDER BY created_at DESC LIMIT ? OFFSET ?'
- params.push(limit, offset)
- const users = await c.env.DB
- .prepare(sql)
- .bind(...params)
- .all<User>()
- const data: PageResponse<User> = {
- rows: users.results || [],
- total: countResult?.count || 0,
- }
- return c.json(success(data))
- } catch (err) {
- console.error('List users error:', err)
- return c.json(error(err instanceof Error ? err.message : '获取用户列表失败'))
- }
- })
- /**
- * 获取用户详情
- * GET /api/users/:id
- */
- user.get('/:id', async (c) => {
- try {
- const userId = c.req.param('id')
- const userData = await c.env.DB
- .prepare('SELECT id, username, email, role, status, last_login, created_at, updated_at FROM users WHERE id = ? AND is_deleted = 0')
- .bind(userId)
- .first<User>()
- if (!userData) {
- return c.json(error('用户不存在', 404), 404)
- }
- return c.json(success(userData))
- } catch (err) {
- console.error('Get user error:', err)
- return c.json(error(err instanceof Error ? err.message : '获取用户详情失败'))
- }
- })
- /**
- * 创建用户
- * POST /api/users
- */
- user.post('/', async (c) => {
- try {
- const body = await c.req.json<{
- username: string
- password: string
- email?: string
- role?: 'admin' | 'operator' | 'viewer'
- }>()
- if (!body.username || !body.password) {
- return c.json(error('用户名和密码不能为空', 400), 400)
- }
- // 检查用户名是否已存在
- const existing = await c.env.DB
- .prepare('SELECT id FROM users WHERE username = ?')
- .bind(body.username)
- .first()
- if (existing) {
- return c.json(error('用户名已存在', 400), 400)
- }
- const userId = generateId()
- const passwordHash = await hashPassword(body.password)
- const now = Math.floor(Date.now() / 1000)
- await c.env.DB
- .prepare(`
- INSERT INTO users (id, username, email, password_hash, role, status, created_at, updated_at)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
- `)
- .bind(
- userId,
- body.username,
- body.email || null,
- passwordHash,
- body.role || 'viewer',
- 'active',
- now,
- now
- )
- .run()
- // 记录操作日志
- const adminUser = c.get('user')
- await c.env.DB
- .prepare(`
- INSERT INTO audit_logs (id, user_id, action, resource, resource_id, details, created_at)
- VALUES (?, ?, ?, ?, ?, ?, ?)
- `)
- .bind(generateId(), adminUser.sub, 'create', 'user', userId, JSON.stringify({ username: body.username }), now)
- .run()
- const newUser = await c.env.DB
- .prepare('SELECT id, username, email, role, status, created_at, updated_at FROM users WHERE id = ?')
- .bind(userId)
- .first<User>()
- return c.json(success(newUser, '用户创建成功'))
- } catch (err) {
- console.error('Create user error:', err)
- return c.json(error(err instanceof Error ? err.message : '创建用户失败'))
- }
- })
- /**
- * 更新用户
- * PUT /api/users/:id
- */
- user.put('/:id', async (c) => {
- try {
- const userId = c.req.param('id')
- const body = await c.req.json<{
- email?: string
- role?: 'admin' | 'operator' | 'viewer'
- status?: 'active' | 'disabled'
- password?: string
- }>()
- const existing = await c.env.DB
- .prepare('SELECT id FROM users WHERE id = ? AND is_deleted = 0')
- .bind(userId)
- .first()
- if (!existing) {
- return c.json(error('用户不存在', 404), 404)
- }
- const updates: string[] = []
- const params: (string | number)[] = []
- if (body.email !== undefined) {
- updates.push('email = ?')
- params.push(body.email)
- }
- if (body.role) {
- updates.push('role = ?')
- params.push(body.role)
- }
- if (body.status) {
- updates.push('status = ?')
- params.push(body.status)
- }
- if (body.password) {
- const passwordHash = await hashPassword(body.password)
- updates.push('password_hash = ?')
- params.push(passwordHash)
- }
- if (updates.length === 0) {
- return c.json(error('没有要更新的字段', 400), 400)
- }
- const now = Math.floor(Date.now() / 1000)
- updates.push('updated_at = ?')
- params.push(now)
- params.push(userId)
- await c.env.DB
- .prepare(`UPDATE users SET ${updates.join(', ')} WHERE id = ?`)
- .bind(...params)
- .run()
- // 记录操作日志
- const adminUser = c.get('user')
- await c.env.DB
- .prepare(`
- INSERT INTO audit_logs (id, user_id, action, resource, resource_id, details, created_at)
- VALUES (?, ?, ?, ?, ?, ?, ?)
- `)
- .bind(generateId(), adminUser.sub, 'update', 'user', userId, JSON.stringify(body), now)
- .run()
- const updatedUser = await c.env.DB
- .prepare('SELECT id, username, email, role, status, created_at, updated_at FROM users WHERE id = ?')
- .bind(userId)
- .first<User>()
- return c.json(success(updatedUser, '用户更新成功'))
- } catch (err) {
- console.error('Update user error:', err)
- return c.json(error(err instanceof Error ? err.message : '更新用户失败'))
- }
- })
- /**
- * 删除用户
- * DELETE /api/users/:id
- */
- user.delete('/:id', async (c) => {
- try {
- const userId = c.req.param('id')
- const adminUser = c.get('user')
- // 不能删除自己
- if (userId === adminUser.sub) {
- return c.json(error('不能删除自己', 400), 400)
- }
- const existing = await c.env.DB
- .prepare('SELECT id, username FROM users WHERE id = ? AND is_deleted = 0')
- .bind(userId)
- .first<User>()
- if (!existing) {
- return c.json(error('用户不存在', 404), 404)
- }
- const now = Math.floor(Date.now() / 1000)
- // 软删除时清空 email,避免 UNIQUE 约束冲突
- await c.env.DB
- .prepare('UPDATE users SET is_deleted = 1, email = NULL, updated_at = ? WHERE id = ?')
- .bind(now, userId)
- .run()
- // 记录操作日志
- await c.env.DB
- .prepare(`
- INSERT INTO audit_logs (id, user_id, action, resource, resource_id, details, created_at)
- VALUES (?, ?, ?, ?, ?, ?, ?)
- `)
- .bind(generateId(), adminUser.sub, 'delete', 'user', userId, JSON.stringify({ username: existing.username }), now)
- .run()
- return c.json(success(null, '用户删除成功'))
- } catch (err) {
- console.error('Delete user error:', err)
- return c.json(error(err instanceof Error ? err.message : '删除用户失败'))
- }
- })
- // ==================== 权限管理 ====================
- /**
- * 获取用户权限列表
- * GET /api/users/:id/permissions
- */
- user.get('/:id/permissions', async (c) => {
- try {
- const userId = c.req.param('id')
- const permissions = await c.env.DB
- .prepare(`
- SELECT up.*, c.name as camera_name
- FROM user_permissions up
- LEFT JOIN cameras c ON up.camera_id = c.id
- WHERE up.user_id = ? AND up.is_deleted = 0
- ORDER BY up.granted_at DESC
- `)
- .bind(userId)
- .all<UserPermission & { camera_name: string }>()
- return c.json(success(permissions.results || []))
- } catch (err) {
- console.error('List permissions error:', err)
- return c.json(error(err instanceof Error ? err.message : '获取权限列表失败'))
- }
- })
- /**
- * 添加用户权限
- * POST /api/users/:id/permissions
- */
- user.post('/:id/permissions', async (c) => {
- try {
- const userId = c.req.param('id')
- const adminUser = c.get('user')
- const body = await c.req.json<{
- camera_id: string
- permission: 'view' | 'control' | 'manage'
- }>()
- if (!body.camera_id || !body.permission) {
- return c.json(error('camera_id 和 permission 不能为空', 400), 400)
- }
- // 检查用户是否存在
- const userExists = await c.env.DB
- .prepare('SELECT id FROM users WHERE id = ? AND is_deleted = 0')
- .bind(userId)
- .first()
- if (!userExists) {
- return c.json(error('用户不存在', 404), 404)
- }
- // 检查摄像头是否存在
- const cameraExists = await c.env.DB
- .prepare('SELECT id FROM cameras WHERE id = ? AND is_deleted = 0')
- .bind(body.camera_id)
- .first()
- if (!cameraExists) {
- return c.json(error('摄像头不存在', 404), 404)
- }
- // 检查是否已存在权限
- const existing = await c.env.DB
- .prepare('SELECT id FROM user_permissions WHERE user_id = ? AND camera_id = ? AND is_deleted = 0')
- .bind(userId, body.camera_id)
- .first()
- const now = Math.floor(Date.now() / 1000)
- if (existing) {
- // 更新现有权限
- await c.env.DB
- .prepare('UPDATE user_permissions SET permission = ?, granted_at = ?, granted_by = ? WHERE user_id = ? AND camera_id = ?')
- .bind(body.permission, now, adminUser.sub, userId, body.camera_id)
- .run()
- } else {
- // 创建新权限
- await c.env.DB
- .prepare(`
- INSERT INTO user_permissions (id, user_id, camera_id, permission, granted_at, granted_by)
- VALUES (?, ?, ?, ?, ?, ?)
- `)
- .bind(generateId(), userId, body.camera_id, body.permission, now, adminUser.sub)
- .run()
- }
- return c.json(success(null, '权限设置成功'))
- } catch (err) {
- console.error('Add permission error:', err)
- return c.json(error(err instanceof Error ? err.message : '设置权限失败'))
- }
- })
- /**
- * 删除用户权限
- * DELETE /api/users/:id/permissions/:permissionId
- */
- user.delete('/:id/permissions/:permissionId', async (c) => {
- try {
- const userId = c.req.param('id')
- const permissionId = c.req.param('permissionId')
- const existing = await c.env.DB
- .prepare('SELECT id FROM user_permissions WHERE id = ? AND user_id = ? AND is_deleted = 0')
- .bind(permissionId, userId)
- .first()
- if (!existing) {
- return c.json(error('权限不存在', 404), 404)
- }
- await c.env.DB
- .prepare('UPDATE user_permissions SET is_deleted = 1 WHERE id = ?')
- .bind(permissionId)
- .run()
- return c.json(success(null, '权限删除成功'))
- } catch (err) {
- console.error('Delete permission error:', err)
- return c.json(error(err instanceof Error ? err.message : '删除权限失败'))
- }
- })
- export default user
|