diff --git a/backend/app/api/auth.py b/backend/app/api/auth.py
index 34d2d62..32bfd2c 100644
--- a/backend/app/api/auth.py
+++ b/backend/app/api/auth.py
@@ -11,7 +11,7 @@
from app.models import User
from app.models.password_reset import PasswordResetToken
from app.schemas import (
- LoginRequest, Token, UserCreate, UserOut, UserInfoResponse,
+ LoginRequest, Token, UserCreate, UserUpdate, UserOut, UserInfoResponse,
InitialSetupRequest, PasswordResetRequest,
PasswordResetConfirm, SystemStatusResponse,
)
@@ -245,6 +245,102 @@ def list_all_users(
return users
+@router.patch("/users/{user_id}", response_model=UserOut)
+def update_user(
+ user_id: int,
+ user_update: UserUpdate,
+ current_user: User = Depends(get_current_active_superuser),
+ db: Session = Depends(get_db),
+):
+ """
+ Update a user's information. Only superusers can update users.
+ """
+ target_user = db.query(User).filter(User.id == user_id).first()
+ if not target_user:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="用户不存在",
+ )
+
+ # Prevent demoting yourself
+ if user_update.is_superuser is False and target_user.id == current_user.id:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail="不能取消自己的超级管理员权限",
+ )
+
+ # Prevent demoting the last superuser
+ if user_update.is_superuser is False and target_user.is_superuser:
+ superuser_count = db.query(User).filter(
+ User.is_superuser == True, User.is_default_admin == False # noqa: E712
+ ).count()
+ if superuser_count <= 1:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail="不能取消最后一个超级管理员的权限",
+ )
+
+ # Check email uniqueness if updating email
+ if user_update.email is not None:
+ existing = db.query(User).filter(
+ User.email == user_update.email, User.id != user_id
+ ).first()
+ if existing:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail="该邮箱已被其他用户使用",
+ )
+
+ # Apply updates
+ update_data = user_update.model_dump(exclude_unset=True)
+ if "password" in update_data:
+ target_user.hashed_password = get_password_hash(update_data.pop("password"))
+ for field, value in update_data.items():
+ setattr(target_user, field, value)
+
+ db.commit()
+ db.refresh(target_user)
+ return target_user
+
+
+@router.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
+def delete_user(
+ user_id: int,
+ current_user: User = Depends(get_current_active_superuser),
+ db: Session = Depends(get_db),
+):
+ """
+ Delete a user. Only superusers can delete users.
+ """
+ target_user = db.query(User).filter(User.id == user_id).first()
+ if not target_user:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="用户不存在",
+ )
+
+ # Cannot delete yourself
+ if target_user.id == current_user.id:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail="不能删除自己的账号",
+ )
+
+ # Cannot delete the last superuser
+ if target_user.is_superuser:
+ superuser_count = db.query(User).filter(
+ User.is_superuser == True, User.is_default_admin == False # noqa: E712
+ ).count()
+ if superuser_count <= 1:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail="不能删除最后一个超级管理员",
+ )
+
+ db.delete(target_user)
+ db.commit()
+
+
@router.post("/password-reset/request", status_code=status.HTTP_200_OK)
def request_password_reset(
reset_request: PasswordResetRequest,
diff --git a/backend/app/schemas/user.py b/backend/app/schemas/user.py
index d021db7..08e7dc7 100644
--- a/backend/app/schemas/user.py
+++ b/backend/app/schemas/user.py
@@ -20,6 +20,7 @@ class UserUpdate(BaseModel):
full_name: Optional[str] = None
password: Optional[str] = Field(None, min_length=6, max_length=100)
is_active: Optional[bool] = None
+ is_superuser: Optional[bool] = None
class UserOut(UserBase):
diff --git a/frontend/public/logo.svg b/frontend/public/logo.svg
deleted file mode 100644
index a899ad7..0000000
--- a/frontend/public/logo.svg
+++ /dev/null
@@ -1,45 +0,0 @@
-
diff --git a/frontend/src/api/auth.ts b/frontend/src/api/auth.ts
index e185372..03cf913 100644
--- a/frontend/src/api/auth.ts
+++ b/frontend/src/api/auth.ts
@@ -83,3 +83,17 @@ export async function listAllUsers(): Promise {
const { data } = await apiClient.get('/auth/users')
return data
}
+
+export async function updateUser(userId: number, userData: {
+ email?: string
+ full_name?: string
+ is_superuser?: boolean
+ is_active?: boolean
+}): Promise {
+ const { data } = await apiClient.patch(`/auth/users/${userId}`, userData)
+ return data
+}
+
+export async function deleteUser(userId: number): Promise {
+ await apiClient.delete(`/auth/users/${userId}`)
+}
diff --git a/frontend/src/views/Login.vue b/frontend/src/views/Login.vue
index c72250c..c63dc6e 100644
--- a/frontend/src/views/Login.vue
+++ b/frontend/src/views/Login.vue
@@ -164,6 +164,9 @@ const handleLogin = async () => {
height: auto;
margin: 0 auto 16px;
display: block;
+ background-color: #fff;
+ border-radius: 8px;
+ padding: 8px;
}
h2 {
diff --git a/frontend/src/views/UserManage.vue b/frontend/src/views/UserManage.vue
index fed0d09..af9d029 100644
--- a/frontend/src/views/UserManage.vue
+++ b/frontend/src/views/UserManage.vue
@@ -29,6 +29,17 @@
{{ formatDate(row.created_at) }}
+
+
+ 编辑
+ 删除
+
+
@@ -71,21 +82,64 @@
注册
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 超级管理员
+
+
+
+
+ 取消
+ 保存
+
+