feat(users): 建号规则收紧与手机号绑定

- 管理端/园区端创建用户:账号系统随机生成不可指定,手机号必填且全局唯一
- 管理端用户管理支持绑定/更换手机号(PATCH /admin/users/{id}/phone)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Pine
2026-08-30 22:29:44 +08:00
parent e44fea96ca
commit 7493383f6a
4 changed files with 80 additions and 18 deletions
+18 -2
View File
@@ -7,7 +7,7 @@ from pydantic import BaseModel, Field
from ..dependencies import get_db
from ..schemas.admin import SetUserRoleRequest, SetUserStatusRequest, UserClassificationRequest
from ..schemas.admin import UserCreateRequest, RolePermissionRequest, UpdateUserRequest
from ..schemas.admin import UserCreateRequest, RolePermissionRequest, UpdateUserRequest, BindPhoneRequest
from ..schemas.admin import OpcCertReviewRequest, ParkAdmissionReviewRequest, ParkTransferReviewRequest
from ...rbac import require_permission, require_roles, write_audit
from ...infrastructure.repositories import Database
@@ -38,7 +38,23 @@ async def create_user(
await _sync_compute(compute_client.create_user(user["username"]))
await _sync_compute(compute_client.issue_pat(user["username"]))
await write_audit(db, action="user.create", resource="user", resource_id=user["id"],
detail=f"role={req.role}", user=actor, request=request)
detail=f"role={req.role} phone={req.phone}", user=actor, request=request)
return await db.users.to_profile(user)
@router.patch("/users/{uid}/phone", summary="为用户绑定/更换手机号")
async def bind_user_phone(
uid: str,
req: BindPhoneRequest,
request: Request,
db: Database = Depends(get_db),
actor: dict = Depends(require_permission("action:user.manage")),
):
from ...services.user_admin_service import UserAdminService
user = await UserAdminService(db).bind_phone(uid, req.phone)
await write_audit(db, action="user.bind_phone", resource="user", resource_id=uid,
detail=f"phone={req.phone}", user=actor, request=request)
return await db.users.to_profile(user)
+7 -1
View File
@@ -27,7 +27,8 @@ class UpdateUserRequest(BaseModel):
region_id: str | None = None
class UserCreateRequest(BaseModel):
username: str # 手机号
"""管理员建号:账号由系统随机生成(不可指定),手机号必填且全局唯一。"""
phone: str # 手机号(必填,11 位大陆手机号)
password: str
nickname: str = ""
role: str = "opc_member"
@@ -36,6 +37,11 @@ class UserCreateRequest(BaseModel):
region_id: str | None = None
class BindPhoneRequest(BaseModel):
"""为已有用户绑定/更换手机号。"""
phone: str
class RolePermissionRequest(BaseModel):
permissions: list[str] = []