user.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. # -*- coding: utf-8 -*-
  2. # @Author : YY
  3. from typing import List, Optional
  4. from flask import request
  5. from flask_login import login_required
  6. from pydantic import BeforeValidator
  7. from typing_extensions import Annotated
  8. from werkzeug.datastructures import FileStorage
  9. from ruoyi_common.base.model import AjaxResponse, TableResponse
  10. from ruoyi_common.base.transformer import ids_to_list
  11. from ruoyi_common.constant import UserConstants
  12. from ruoyi_common.descriptor.serializer import BaseSerializer, JsonSerializer
  13. from ruoyi_common.descriptor.validator import FileDownloadValidator, \
  14. FileUploadValidator, QueryValidator, BodyValidator, PathValidator
  15. from ruoyi_common.domain.entity import SysUser, SysRole
  16. from ruoyi_common.domain.enum import BusinessType
  17. from ruoyi_common.utils import security_util as SecurityUtil
  18. from ruoyi_common.utils.base import ExcelUtil
  19. from ruoyi_framework.descriptor.log import Log
  20. from ruoyi_framework.descriptor.permission import HasPerm, PreAuthorize
  21. from ruoyi_system.domain.entity import SysPost
  22. from ruoyi_system.service import SysUserService
  23. from ruoyi_system.service.sys_post import SysPostService
  24. from ruoyi_system.service.sys_role import SysRoleService
  25. from ... import reg
  26. @reg.api.route("/system/user/list", methods=["GET"])
  27. @QueryValidator(is_page=True)
  28. @PreAuthorize(HasPerm("system:user:list"))
  29. @JsonSerializer()
  30. def system_user_list(dto: SysUser):
  31. '''
  32. 获取用户列表
  33. '''
  34. rows = SysUserService.select_user_list(dto)
  35. table_response = TableResponse(rows=rows)
  36. return table_response
  37. @reg.api.route("/system/user/", methods=["GET"])
  38. @reg.api.route("/system/user/<int:id>", methods=["GET"])
  39. @PathValidator()
  40. @PreAuthorize(HasPerm("system:user:query"))
  41. @JsonSerializer()
  42. def system_get_user(id: Optional[int] = None):
  43. '''
  44. 获取用户详情
  45. '''
  46. SysUserService.check_user_data_scope(id)
  47. ajax_response = AjaxResponse.from_success()
  48. roles: List[SysRole] = SysRoleService.select_role_all()
  49. posts: List[SysPost] = SysPostService.select_post_all()
  50. if not SecurityUtil.is_admin(id):
  51. roles = [role for role in roles if not role.is_admin()]
  52. setattr(ajax_response, "roles", roles)
  53. setattr(ajax_response, "posts", posts)
  54. if id:
  55. user = SysUserService.select_user_by_id(id)
  56. setattr(ajax_response, "data", user)
  57. post_ids = SysPostService.select_post_list_by_user_id(id)
  58. setattr(ajax_response, "postIds", post_ids)
  59. setattr(ajax_response, "role_ids", user.role_ids)
  60. return ajax_response
  61. @reg.api.route("/system/user", methods=["POST"])
  62. @BodyValidator()
  63. @PreAuthorize(HasPerm("system:user:add"))
  64. @Log(title="用户管理", business_type=BusinessType.INSERT)
  65. @JsonSerializer()
  66. def system_create_user(dto: SysUser):
  67. '''
  68. 新增用户
  69. '''
  70. if SysUserService.check_user_name_unique(dto) \
  71. == UserConstants.NOT_UNIQUE:
  72. return AjaxResponse.from_error(
  73. f"新增用户'{dto.user_name}'失败,登录账号已存在"
  74. )
  75. elif dto.phonenumber \
  76. and SysUserService.check_phone_unique(dto) \
  77. == UserConstants.NOT_UNIQUE:
  78. return AjaxResponse.from_error(
  79. f"新增用户'{dto.phonenumber}'失败,手机号码已存在"
  80. )
  81. elif dto.email \
  82. and SysUserService.check_email_unique(dto) \
  83. == UserConstants.NOT_UNIQUE:
  84. return AjaxResponse.from_error(
  85. f"新增用户'{dto.email}'失败,邮箱已存在"
  86. )
  87. dto.create_by_user(SecurityUtil.get_username())
  88. flag = SysUserService.insert_user(dto)
  89. ajax_response = AjaxResponse.from_success() if flag else AjaxResponse.from_error()
  90. return ajax_response
  91. @reg.api.route("/system/user", methods=["PUT"])
  92. @BodyValidator()
  93. @PreAuthorize(HasPerm("system:user:edit"))
  94. @Log(title="用户管理", business_type=BusinessType.UPDATE)
  95. @JsonSerializer()
  96. def system_update_user(dto: SysUser):
  97. '''
  98. 修改用户
  99. '''
  100. SysUserService.check_user_allowed(dto)
  101. SysUserService.check_user_data_scope(dto.user_id)
  102. if dto.phonenumber \
  103. and SysUserService.check_phone_unique(dto) \
  104. == UserConstants.NOT_UNIQUE:
  105. return AjaxResponse.from_error(
  106. f"新增用户'{dto.phonenumber}'失败,手机号码已存在"
  107. )
  108. elif dto.email \
  109. and SysUserService.check_email_unique(dto) \
  110. == UserConstants.NOT_UNIQUE:
  111. return AjaxResponse.from_error(
  112. f"新增用户'{dto.email}'失败,邮箱已存在"
  113. )
  114. dto.update_by_user(SecurityUtil.get_username())
  115. flag = SysUserService.update_user(dto)
  116. ajax_response = AjaxResponse.from_success() if flag else AjaxResponse.from_error()
  117. return ajax_response
  118. @reg.api.route("/system/user/<ids>", methods=["DELETE"])
  119. @PathValidator()
  120. @PreAuthorize(HasPerm("system:user:remove"))
  121. @Log(title="用户管理", business_type=BusinessType.DELETE)
  122. @JsonSerializer()
  123. def system_delete_users(
  124. ids: Annotated[List[int], BeforeValidator(ids_to_list)]
  125. ):
  126. '''
  127. 删除用户
  128. '''
  129. if SecurityUtil.get_user_id() in ids:
  130. return AjaxResponse.from_error("当前用户不能删除")
  131. flag = SysUserService.delete_users_by_ids(ids)
  132. ajax_response = AjaxResponse.from_success() if flag > 0 else AjaxResponse.from_error()
  133. return ajax_response
  134. @reg.api.route("/system/user/export", methods=["POST"])
  135. @FileDownloadValidator()
  136. @PreAuthorize(HasPerm("system:user:export"))
  137. @Log(title="用户管理", business_type=BusinessType.EXPORT)
  138. @BaseSerializer()
  139. def system_user_export(dto: SysUser):
  140. '''
  141. 导出用户数据
  142. '''
  143. rows = SysUserService.select_user_list(dto)
  144. excel_util = ExcelUtil(SysUser)
  145. return excel_util.export_response(rows, "用户数据")
  146. @reg.api.route("/system/user/importData", methods=["POST"])
  147. @FileUploadValidator()
  148. @PreAuthorize(HasPerm("system:user:import"))
  149. @Log(title="用户管理", business_type=BusinessType.IMPORT)
  150. @JsonSerializer()
  151. def system_user_importdata(
  152. file: List[FileStorage],
  153. update_support: Annotated[bool, BeforeValidator(lambda x: x != "0")]
  154. ):
  155. '''
  156. 导入用户模板
  157. '''
  158. file = file[0]
  159. excel_util = ExcelUtil(SysUser)
  160. datas = excel_util.import_file(file, sheetname="用户数据")
  161. msg = SysUserService.import_user(datas, update_support)
  162. return AjaxResponse.from_success(msg=msg)
  163. @reg.api.route("/system/user/importTemplate", methods=["POST"])
  164. @login_required
  165. @BaseSerializer()
  166. def system_user_importtemplate():
  167. '''
  168. 导出模板
  169. '''
  170. excel_util = ExcelUtil(SysUser)
  171. return excel_util.import_template_response(sheetname="用户数据")
  172. @reg.api.route("/system/user/resetPwd", methods=["PUT"])
  173. @BodyValidator()
  174. @PreAuthorize(HasPerm("system:user:resetPwd"))
  175. @Log(title="用户管理", business_type=BusinessType.UPDATE)
  176. @JsonSerializer()
  177. def system_update_user_resetpwd(dto: SysUser):
  178. '''
  179. 重置密码
  180. '''
  181. SysUserService.check_user_allowed(dto)
  182. SysUserService.check_user_data_scope(dto.user_id)
  183. dto.password = SecurityUtil.encrypt_password(dto.password)
  184. dto.update_by_user(SecurityUtil.get_username())
  185. flag = SysUserService.reset_pwd(dto)
  186. ajax_response = AjaxResponse.from_success() if flag else AjaxResponse.from_error()
  187. return ajax_response
  188. @reg.api.route("/system/user/changeStatus", methods=["PUT"])
  189. @BodyValidator()
  190. @PreAuthorize(HasPerm("system:user:edit"))
  191. @Log(title="用户管理", business_type=BusinessType.UPDATE)
  192. @JsonSerializer()
  193. def system_update_user_changestatus(dto: SysUser):
  194. '''
  195. 修改用户状态
  196. '''
  197. SysUserService.check_user_allowed(dto)
  198. SysUserService.check_user_data_scope(dto.user_id)
  199. dto.update_by_user(SecurityUtil.get_username())
  200. flag = SysUserService.update_user_status(dto)
  201. ajax_response = AjaxResponse.from_success() if flag else AjaxResponse.from_error()
  202. return ajax_response
  203. @reg.api.route("/system/user/authRole/<int:id>", methods=["GET"])
  204. @PathValidator()
  205. @PreAuthorize(HasPerm("system:user:query"))
  206. @JsonSerializer()
  207. def system_get_user_authrole(id: int):
  208. '''
  209. 获取用户授权角色
  210. '''
  211. sysuser: SysUser = SysUserService.select_user_by_id(id)
  212. roles: List[SysRole] = SysRoleService.select_role_list_by_user_id(id)
  213. if not sysuser.is_admin():
  214. roles = [role for role in roles if not role.is_admin()]
  215. ajax_response = AjaxResponse.from_success() if sysuser else AjaxResponse.from_error()
  216. setattr(ajax_response, "user", sysuser)
  217. setattr(ajax_response, "roles", roles)
  218. return ajax_response
  219. @reg.api.route("/system/user/authRole", methods=["PUT"])
  220. @PreAuthorize(HasPerm("system:user:edit"))
  221. @Log(title="用户管理", business_type=BusinessType.GRANT)
  222. @JsonSerializer()
  223. def system_update_user_authrole():
  224. '''
  225. 授权用户角色
  226. '''
  227. user_id, role_ids = _extract_auth_role_params()
  228. if user_id is None:
  229. return AjaxResponse.from_error("userId参数不能为空")
  230. if role_ids is None:
  231. return AjaxResponse.from_error("roleIds参数格式错误")
  232. SysUserService.check_user_data_scope(user_id)
  233. SysUserService.update_user_roles(user_id, role_ids)
  234. return AjaxResponse.from_success()
  235. def _extract_auth_role_params() -> tuple[int | None, List[int] | None]:
  236. """
  237. 兼容 query/json/form 三种提交方式
  238. """
  239. payload = request.get_json(silent=True) if request.is_json else None
  240. data = payload if isinstance(payload, dict) else {}
  241. user_id = data.get("user_id") or data.get("userId")
  242. role_ids_raw = data.get("role_ids") or data.get("roleIds")
  243. if user_id is None:
  244. user_id = request.args.get("userId") or request.form.get("userId")
  245. if role_ids_raw is None:
  246. role_ids_list = request.args.getlist("roleIds")
  247. if not role_ids_list and request.form:
  248. role_ids_list = request.form.getlist("roleIds")
  249. if role_ids_list:
  250. role_ids_raw = role_ids_list
  251. else:
  252. role_ids_raw = request.args.get("roleIds") or request.form.get("roleIds")
  253. try:
  254. user_id_int = int(user_id) if user_id is not None else None
  255. except (TypeError, ValueError):
  256. return None, None
  257. try:
  258. role_ids_list = _normalize_role_ids(role_ids_raw)
  259. except ValueError:
  260. return user_id_int, None
  261. return user_id_int, role_ids_list
  262. def _normalize_role_ids(raw_value) -> List[int]:
  263. """
  264. 将不同格式的roleIds转换为整数列表
  265. """
  266. if raw_value is None:
  267. return []
  268. if isinstance(raw_value, list):
  269. normalized: List[int] = []
  270. for item in raw_value:
  271. normalized.extend(_normalize_role_ids(item))
  272. return normalized
  273. if isinstance(raw_value, (int, float)):
  274. return [int(raw_value)]
  275. if isinstance(raw_value, str):
  276. raw_value = raw_value.strip()
  277. if not raw_value:
  278. return []
  279. parts = [part.strip() for part in raw_value.split(",") if part.strip()]
  280. return [int(part) for part in parts]
  281. raise ValueError("unsupported roleIds format")