import React, { useState, useEffect } from 'react' import { APP_VERSION } from '../config/version' export default function Admin() { const [users, setUsers] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState('') const [showAddModal, setShowAddModal] = useState(false) const [editingUser, setEditingUser] = useState(null) const [newUser, setNewUser] = useState({ username: '', password: '', email: '', role: 'user' }) const token = localStorage.getItem('token') const userStr = localStorage.getItem('user') let user = null try { user = userStr ? JSON.parse(userStr) : null } catch (e) {} if (!user || user.role !== 'admin') { return (
🚫
无权访问
仅管理员可以访问用户管理界面
) } useEffect(() => { fetchUsers() }, []) const fetchUsers = async () => { try { const res = await fetch('/api/admin/users?page=1&limit=100', { headers: { 'Authorization': `Bearer ${token}` } }) if (!res.ok) throw new Error('获取用户列表失败') const data = await res.json() setUsers(data) } catch (err) { setError(err.message) } finally { setLoading(false) } } const handleDeleteUser = async (userId, username) => { if (!confirm(`确定要删除用户 "${username}" 吗?`)) return try { const res = await fetch(`/api/admin/users/${userId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }) if (!res.ok) throw new Error('删除失败') fetchUsers() } catch (err) { alert(err.message) } } const handleAddUser = async () => { if (!newUser.username || !newUser.password) { alert('用户名和密码为必填项'); return } const payload = { ...newUser } if (!payload.email) delete payload.email try { const res = await fetch('/api/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify(payload) }) if (!res.ok) { const data = await res.json(); throw new Error(data.detail || '添加失败') } alert('添加成功!') setShowAddModal(false) setNewUser({ username: '', password: '', email: '', role: 'user' }) fetchUsers() } catch (err) { alert(err.message) } } const handleEditUser = async () => { if (!editingUser.username) { alert('用户名不能为空'); return } if (editingUser.newPassword || editingUser.confirmPassword) { if (!editingUser.newPassword || !editingUser.confirmPassword) { alert('请填写完整密码信息'); return } if (editingUser.newPassword !== editingUser.confirmPassword) { alert('两次输入的密码不一致'); return } if (editingUser.newPassword.length < 6) { alert('密码至少 6 个字符'); return } } try { const updateData = { username: editingUser.username, email: editingUser.email, phone: editingUser.phone, role: editingUser.role, level: editingUser.level, points: editingUser.points } if (editingUser.newPassword && editingUser.newPassword.trim()) updateData.password = editingUser.newPassword const res = await fetch(`/api/admin/users/${editingUser.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify(updateData) }) if (!res.ok) { const data = await res.json(); throw new Error(data.detail || '更新失败') } alert('更新成功!') setEditingUser(null) fetchUsers() } catch (err) { alert(err.message) } } if (loading) return
加载中...
if (error) return
⚠️ {error}
return (

⚙️ 用户管理

{users.map(u => (
#{u.user_code} {u.username}
{u.role === 'admin' ? '👑 管理员' : u.role === 'editor' ? '📝 信息员' : '👤 用户'}
{u.level && {u.level === '青铜' ? '🥉' : u.level === '白银' ? '🥈' : u.level === '黄金' ? '🥇' : u.level === '钻石' ? '💎' : '👑'} {u.level}}
📧 {u.email || '未设置'} | 📱 {u.phone || '未设置'}
余额
¥{u.balance || 0}
注册时间:{u.created_at ? new Date(u.created_at).toLocaleDateString('zh-CN') : '-'}
{u.role !== 'admin' && }
))}
{users.length === 0 &&
暂无用户数据
} {/* 添加用户弹窗 */} {showAddModal && (

添加用户

setNewUser({ ...newUser, username: e.target.value })} style={{ width: '100%', padding: '10px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff' }} />
setNewUser({ ...newUser, password: e.target.value })} style={{ width: '100%', padding: '10px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff' }} />
setNewUser({ ...newUser, email: e.target.value })} style={{ width: '100%', padding: '10px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff' }} />
)} {/* 编辑用户弹窗 - 完整字段 */} {editingUser && (

编辑用户

{/* 基本信息 */}

📋 基本信息

setEditingUser({ ...editingUser, user_code: e.target.value })} style={{ width: '100%', padding: '8px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '6px', color: '#fbbf24', fontSize: '13px' }} />
setEditingUser({ ...editingUser, username: e.target.value })} style={{ width: '100%', padding: '8px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '6px', color: '#fff', fontSize: '13px' }} />
setEditingUser({ ...editingUser, phone: e.target.value })} style={{ width: '100%', padding: '8px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '6px', color: '#fff', fontSize: '13px' }} />
setEditingUser({ ...editingUser, email: e.target.value })} style={{ width: '100%', padding: '8px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '6px', color: '#fff', fontSize: '13px' }} />
{/* 会员信息 */}

⭐ 会员信息

setEditingUser({ ...editingUser, points: parseInt(e.target.value) || 0 })} style={{ width: '100%', padding: '8px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '6px', color: '#fff', fontSize: '13px' }} />
setEditingUser({ ...editingUser, balance: parseFloat(e.target.value) || 0 })} style={{ width: '100%', padding: '8px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '6px', color: '#fff', fontSize: '13px' }} />
{/* 统计信息(只读) */}

📊 统计数据(仅展示)

藏品
{editingUser.collectionCount || 0}
AI识别
{editingUser.aiCount || 0}
寻号
{editingUser.searchCount || 0}
登录
{editingUser.loginCount || 0}
{/* 修改密码 */}

🔐 修改密码(可选)

setEditingUser({ ...editingUser, newPassword: e.target.value })} placeholder="留空则不修改" style={{ width: '100%', padding: '8px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '6px', color: '#fff', fontSize: '13px' }} />
setEditingUser({ ...editingUser, confirmPassword: e.target.value })} placeholder="再次输入" style={{ width: '100%', padding: '8px', background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '6px', color: '#fff', fontSize: '13px' }} />
)}
) }