Files
DjangoAdmin_FastAPI_EleVue/apps/services/user.py
T
ClaudeandClaude dbcce79536 chore: 基线提交(重构前快照)
重构前保存现有 apps/ 结构基线,供后续各阶段回滚。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-07 09:43:18 +08:00

382 lines
12 KiB
Python

from datetime import datetime, timezone
import asyncio
from fastapi.logger import logger
from sqlalchemy import and_
from apps.constants.constants import GENDER_LIST
from apps.constants.message import PAGE_SIZE, DEFAULT_PASSWORD
from apps.forms.user import UserForm, UserStatusForm, UpdatePwdForm, UserInfoForm, ResetPwdForm
from apps.models.dept import Dept
from apps.models.level import Level
from apps.models.position import Position
from apps.models.user import User
from apps.models.user_role import UserRole
from apps.services import user_role
from extensions import get_db_session
from utils import R
from utils import password
from utils.rich_text import get_file_url, save_file
from utils.request import like_contains
from utils.security import get_user_id
from utils.perm_cache import invalidate_user_perms
# 查询用户分页数据
def get_user_page(request):
db = get_db_session()
# 页码
page = int(request.query_params.get("pageNo", 1))
# 每页数
limit = int(request.query_params.get("pageSize", PAGE_SIZE))
# 实例化查询对象
query = db.query(User).filter(User.is_delete == 0)
# 用户账号
username = request.query_params.get('username')
if username:
query = query.filter(User.username.like(like_contains(username), escape='\\'))
# 性别
gender = request.query_params.get('gender')
if gender:
query = query.filter(User.gender == gender)
# 用户状态
status = request.query_params.get('status')
if status:
query = query.filter(User.status == status)
# 排序
query = query.order_by(User.id.asc())
# 记录总数
count = query.count()
# 分页查询
user_list = query.limit(limit).offset((page - 1) * limit).all()
# 若当前页超出末页(数据被并发删除),自动回退到第一页
if page > 1 and not user_list:
page = 1
count = query.count()
user_list = query.limit(limit).offset(0).all()
# 实例化结果
result = []
# 遍历数据源
if len(user_list) > 0:
# 仅查询当前页用到的部门ID
dept_ids = {item.dept_id for item in user_list if item.dept_id}
deptList = {}
if dept_ids:
for dept in db.query(Dept).filter(Dept.id.in_(dept_ids), Dept.is_delete == 0).all():
deptList[dept.id] = dept.name
# 仅查询当前页用到的职级ID
level_ids = {item.level_id for item in user_list if item.level_id}
levelList = {}
if level_ids:
for level in db.query(Level).filter(Level.id.in_(level_ids), Level.is_delete == 0).all():
levelList[level.id] = level.name
# 仅查询当前页用到的岗位ID
position_ids = {item.position_id for item in user_list if item.position_id}
positionList = {}
if position_ids:
for position in db.query(Position).filter(Position.id.in_(position_ids), Position.is_delete == 0).all():
positionList[position.id] = position.name
# 批量查询用户角色
user_ids = [item.id for item in user_list]
roleMap = user_role.get_user_role_map(user_ids)
for item in user_list:
# 城市
city_list = []
# 省份编码
city_list.append(item.province_code)
# 城市编码
city_list.append(item.city_code)
# 县区编码
city_list.append(item.district_code)
# 对象转字典
data = item.to_dict()
# 性别
data['gender_name'] = GENDER_LIST.get(item.gender)
# 头像
data['avatar'] = get_file_url(item.avatar) if item.avatar else ""
# 部门名称
data['dept_name'] = deptList.get(item.dept_id) if deptList else None
# 职级名称
data['level_name'] = levelList.get(item.level_id) if levelList else None
# 岗位名称
data['position_name'] = positionList.get(item.position_id) if positionList else None
# 角色列表
data['roleList'] = roleMap.get(item.id, [])
# 行政区划
data['city'] = city_list
# 加入列表
result.append(data)
# 返回结果
return R.ok(data=result, count=count)
# 根据ID查询用户详情
def get_user_detail(user_id):
db = get_db_session()
# 根据ID查询用户
user = db.query(User).filter(and_(User.id == user_id, User.is_delete == 0)).first()
# 查询结果判空
if not user:
return None
# 获取用户角色数据
roleList = db.query(UserRole).filter(UserRole.user_id == user.id).all()
roles = []
for role in roleList:
roles.append(role.role_id)
# 城市编码
cityList = []
# 省份编号
cityList.append(user.province_code)
# 城市编码
cityList.append(user.city_code)
# 县区编码
cityList.append(user.district_code)
# 对象转字典
data = user.to_dict()
# 头像
data['avatar'] = get_file_url(user.avatar) if user.avatar else ""
# 角色
data['roles'] = roles
# 行政区划
data['city'] = cityList
# 返回结果
return data
# 添加用户
async def add_user(request, data: UserForm):
def _add():
db = get_db_session()
# 唯一性校验
if db.query(User).filter(and_(User.username == data.username, User.is_delete == 0)).first():
return R.failed("登录账号不能重复"), None
# 获取表单数据(排除非数据列)
formData = data.model_dump(exclude={'city', 'roles'})
# 图片处理
avatar = data.avatar
if avatar:
formData['avatar'] = save_file(avatar, "user")
# 密码加密:未传密码时使用默认密码
pwd = data.password or DEFAULT_PASSWORD
salt = password.generate_salt()
formData['password'] = password.encrypt_password(pwd, salt)
formData['salt'] = salt
# 行政区划处理
citys = data.city
if citys and len(citys) == 3:
formData['province_code'] = citys[0]
formData['city_code'] = citys[1]
formData['district_code'] = citys[2]
# 表单数据赋值给对象
user = User(**formData)
user.create_user = get_user_id(request)
# 插入数据
user.save()
return None, user.id
# 同步DB/文件操作放入线程池,避免阻塞事件循环
err, user_id = await asyncio.to_thread(_add)
if err:
return err
# 创建用户角色数据 + 清理权限缓存
await add_user_role(user_id, data.roles)
# 返回结果
return R.ok(msg="添加成功")
# 更新用户
async def update_user(request, data: UserForm):
def _update():
db = get_db_session()
# 记录ID判空
user_id = data.id
if not user_id or int(user_id) <= 0:
return R.failed("记录ID不能为空"), None
# 唯一性校验(排除自身)
if db.query(User).filter(and_(User.username == data.username, User.id != data.id, User.is_delete == 0)).first():
return R.failed("登录账号不能重复"), None
# 根据ID查询记录
user = db.query(User).filter(and_(User.id == user_id, User.is_delete == 0)).first()
# 查询结果判空
if not user:
return R.failed("记录不存在"), None
# 获取表单数据(排除敏感字段和非数据列)
formData = data.model_dump(exclude={'id', 'password', 'city', 'roles'})
# 图片处理
avatar = data.avatar
if avatar:
formData['avatar'] = save_file(avatar, "user")
# 密码加密:仅传入新密码时才更新,否则保留原值
pwd = data.password
if pwd:
salt = password.generate_salt()
formData['password'] = password.encrypt_password(pwd, salt)
formData['salt'] = salt
# 行政区划处理
citys = data.city
if citys and len(citys) == 3:
formData['province_code'] = citys[0]
formData['city_code'] = citys[1]
formData['district_code'] = citys[2]
updData = formData
updData['update_user'] = get_user_id(request)
updData['update_time'] = datetime.now(tz=timezone.utc)
# 更新数据
result = db.query(User).filter_by(id=user_id).update(updData)
if not result:
return R.failed("更新失败"), None
return None, user_id
# 同步DB/文件操作放入线程池,避免阻塞事件循环
err, user_id = await asyncio.to_thread(_update)
if err:
return err
# 创建用户角色数据 + 清理权限缓存
await add_user_role(user_id, data.roles)
# 返回结果
return R.ok(msg="更新成功")
# 创建用户角色信息
async def add_user_role(user_id, roleIdList):
def _save():
db = get_db_session()
# 删除用户角色关系数据
db.query(UserRole).filter(UserRole.user_id == user_id).delete()
# 创建新的用户角色关系
if roleIdList:
new_roles = []
for roleId in roleIdList:
if not roleId:
continue
new_roles.append(UserRole(user_id=user_id, role_id=roleId))
db.add_all(new_roles)
# 同步DB操作放入线程池,避免阻塞事件循环
await asyncio.to_thread(_save)
# 清理该用户权限缓存
await invalidate_user_perms(user_id)
# 删除用户
def delete_user(user_id):
return User.batch_delete_r(user_id)
# 设置状态
def update_user_status(request, data: UserStatusForm):
db = get_db_session()
# 记录ID
id = data.id
# 状态值
status = data.status
# 根据ID查询记录
user = db.query(User).filter(and_(User.id == id, User.is_delete == 0)).first()
# 查询结果判空
if not user:
return R.failed("记录不存在")
# 更新记录
result = db.query(User).filter_by(id=id).update({
"status": status,
"update_user": get_user_id(request),
"update_time": datetime.now(tz=timezone.utc)
})
# 提交数据
if not result:
return R.failed("设置失败")
# 返回结果
return R.ok(msg="设置成功")
# 更新用户信息
def update_user_info(request, data: UserInfoForm):
db = get_db_session()
# 用户ID
user_id = get_user_id(request)
# 根据ID查询记录
user = db.query(User).filter(and_(User.id == user_id, User.is_delete == 0)).first()
# 查询结果判空
if not user:
return R.failed("记录不存在")
# 更新记录
updData = data.model_dump()
result = db.query(User).filter_by(id=user_id).update(updData)
# 提交数据
if not result:
return R.failed("更新失败")
# 返回结果
return R.ok(msg="更新成功")
# 更新密码
def update_pwd(request, data: UpdatePwdForm):
db = get_db_session()
# 用户ID
user_id = get_user_id(request)
# 根据ID查询用户
user = db.query(User).filter(and_(User.is_delete == 0, User.id == user_id)).first()
if not user:
return R.failed("用户不存在")
# 验证原始密码
if not password.verify_password(data.oldPassword, user.salt or '', user.password or ''):
return R.failed("原始密码不正确")
# 加密新密码
salt = password.generate_salt()
new_hash = password.encrypt_password(data.newPassword, salt)
result = db.query(User).filter_by(id=user_id).update({
"password": new_hash,
"salt": salt
})
# 提交数据
if not result:
return R.failed("更新失败")
# 返回结果
return R.ok(msg="更新成功")
# 重置密码
def reset_user_pwd(request, data: ResetPwdForm):
db = get_db_session()
# 用户ID
user_id = data.id
# 根据ID查询用户
user = db.query(User).filter(and_(User.is_delete == 0, User.id == user_id)).first()
if not user:
return R.failed("用户不存在")
# 加密新密码
salt = password.generate_salt()
new_hash = password.encrypt_password(DEFAULT_PASSWORD, salt)
result = db.query(User).filter_by(id=user_id).update({
"password": new_hash,
"salt": salt
})
# 提交数据
if not result:
return R.failed("重置密码失败")
# 返回结果
return R.ok(msg="重置密码成功")