system.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. import json
  2. import re
  3. from typing import Optional, List
  4. from fastapi import APIRouter, Depends, Query, Request
  5. from pydantic import BaseModel, ConfigDict
  6. from pydantic.alias_generators import to_camel
  7. from sqlalchemy.orm import Session
  8. from sqlalchemy import text
  9. from app.database import get_db
  10. from app.models.system import SysUser, SysDept, SysDictData, SysOss
  11. from app.schemas import R, TableDataInfo, PageQuery
  12. from app.middleware import get_current_user
  13. from app.utils.redis_client import get_redis
  14. router = APIRouter()
  15. def _is_http(s: str) -> bool:
  16. return s.startswith("http://") or s.startswith("https://")
  17. def _capitalize(s: str) -> str:
  18. return s[0].upper() + s[1:] if s else ""
  19. def _build_router_tree(menus: list, parent_id: int) -> list:
  20. children_menus = [m for m in menus if m["parent_id"] == parent_id]
  21. result = []
  22. for menu in children_menus:
  23. menu_type = menu["menu_type"]
  24. path = menu["path"] or ""
  25. component = menu["component"] or ""
  26. is_frame = str(menu.get("is_frame", 1))
  27. is_cache = str(menu.get("is_cache", 0))
  28. visible = str(menu.get("visible", "0"))
  29. menu_id = menu["menu_id"]
  30. pid = menu["parent_id"]
  31. is_menu_frame = pid == 0 and menu_type == "C" and is_frame == "1"
  32. is_inner_link = is_frame == "1" and _is_http(path)
  33. is_parent_view = pid != 0 and menu_type == "M"
  34. route_name = ""
  35. if not is_menu_frame:
  36. route_name = _capitalize(path)
  37. router_path = path
  38. if pid != 0 and is_inner_link:
  39. router_path = re.sub(r'^https?://|www\.|[.:]', '', path)
  40. elif pid == 0 and menu_type == "M" and is_frame == "1":
  41. router_path = path if path.startswith("/") else "/" + path
  42. elif is_menu_frame:
  43. router_path = path if path.startswith("/") else "/" + path
  44. component_info = "Layout"
  45. if component and not is_menu_frame:
  46. component_info = component
  47. elif not component and pid != 0 and is_inner_link:
  48. component_info = "InnerLink"
  49. elif not component and is_parent_view:
  50. component_info = "ParentView"
  51. router = {
  52. "name": route_name + str(menu_id),
  53. "path": router_path,
  54. "hidden": visible == "1",
  55. "component": component_info,
  56. "query": menu.get("query_param", ""),
  57. "menuType": menu_type,
  58. "isFrame": is_frame,
  59. "meta": {
  60. "title": menu["menu_name"],
  61. "icon": menu.get("icon", ""),
  62. "noCache": is_cache == "1",
  63. "link": path if is_inner_link else None,
  64. },
  65. }
  66. sub_children = _build_router_tree(menus, menu_id)
  67. if sub_children and menu_type == "M":
  68. router["alwaysShow"] = True
  69. router["redirect"] = "noRedirect"
  70. router["children"] = sub_children
  71. elif is_menu_frame:
  72. frame_name = _capitalize(path) + str(menu_id)
  73. router["children"] = [{
  74. "path": path,
  75. "component": component,
  76. "name": frame_name,
  77. "meta": {
  78. "title": menu["menu_name"],
  79. "icon": menu.get("icon", ""),
  80. "noCache": is_cache == "1",
  81. "link": None,
  82. },
  83. "query": menu.get("query_param", ""),
  84. }]
  85. elif pid == 0 and is_inner_link:
  86. inner_path = re.sub(r'^https?://|www\.|[.:]', '', path)
  87. inner_name = _capitalize(inner_path) + str(menu_id)
  88. router["path"] = "/"
  89. router["children"] = [{
  90. "path": inner_path,
  91. "component": "InnerLink",
  92. "name": inner_name,
  93. "meta": {
  94. "title": menu["menu_name"],
  95. "icon": menu.get("icon", ""),
  96. "link": path,
  97. },
  98. }]
  99. router["meta"] = {
  100. "title": menu["menu_name"],
  101. "icon": menu.get("icon", ""),
  102. }
  103. result.append(router)
  104. return result
  105. @router.get("/user/getInfo")
  106. def get_user_info(current_user: dict = Depends(get_current_user), db: Session = Depends(get_db)):
  107. user_id = current_user.get("user_id")
  108. tenant_id = current_user.get("tenant_id", "000000")
  109. redis = get_redis()
  110. session_key = f"login:session:{user_id}:{tenant_id}"
  111. session_data = redis.get(session_key)
  112. permissions = []
  113. roles = []
  114. if session_data:
  115. import json
  116. data = json.loads(session_data)
  117. permissions = data.get("permissions", [])
  118. roles = data.get("roles", [])
  119. user = db.query(SysUser).filter(SysUser.user_id == user_id, SysUser.del_flag == "0").first()
  120. if not user:
  121. return R.fail("用户不存在")
  122. user_data = {
  123. "userId": user.user_id,
  124. "userName": user.user_name,
  125. "nickName": user.nick_name,
  126. "deptId": user.dept_id,
  127. "email": user.email or "",
  128. "phonenumber": user.phonenumber or "",
  129. "sex": user.sex,
  130. "avatar": user.avatar or "",
  131. "status": user.status,
  132. "accountType": getattr(user, "account_type", "1"),
  133. }
  134. return R.ok(data={
  135. "user": user_data,
  136. "permissions": permissions,
  137. "roles": roles,
  138. })
  139. class UserQuery(PageQuery):
  140. model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
  141. user_name: Optional[str] = None
  142. status: Optional[str] = None
  143. dept_id: Optional[int] = None
  144. @router.get("/user/list")
  145. def list_users(query: UserQuery = Depends(), db: Session = Depends(get_db)):
  146. q = db.query(SysUser).filter(SysUser.del_flag == "0")
  147. if query.user_name:
  148. q = q.filter(SysUser.user_name.like(f"%{query.user_name}%"))
  149. if query.status:
  150. q = q.filter(SysUser.status == query.status)
  151. if query.dept_id:
  152. q = q.filter(SysUser.dept_id == query.dept_id)
  153. total = q.count()
  154. users = q.order_by(SysUser.create_time.desc()).offset(query.offset).limit(query.limit).all()
  155. rows = [
  156. {
  157. "userId": u.user_id,
  158. "userName": u.user_name,
  159. "nickName": u.nick_name,
  160. "deptId": u.dept_id,
  161. "email": u.email or "",
  162. "phonenumber": u.phonenumber or "",
  163. "sex": u.sex,
  164. "avatar": u.avatar or "",
  165. "status": u.status,
  166. "accountType": getattr(u, "account_type", "1"),
  167. "createTime": u.create_time.strftime("%Y-%m-%d %H:%M:%S") if u.create_time else None,
  168. }
  169. for u in users
  170. ]
  171. return TableDataInfo.build(rows, total)
  172. @router.get("/user/deptTree")
  173. def dept_tree(db: Session = Depends(get_db)):
  174. depts = db.query(SysDept).filter(SysDept.del_flag == "0", SysDept.status == "0").all()
  175. dept_map = {d.dept_id: d for d in depts}
  176. def build_tree(parent_id=0):
  177. children = []
  178. for d in depts:
  179. if d.parent_id == parent_id:
  180. node = {
  181. "id": d.dept_id,
  182. "label": d.dept_name,
  183. "parentId": d.parent_id,
  184. "children": build_tree(d.dept_id),
  185. }
  186. children.append(node)
  187. return children
  188. return R.ok(data=build_tree(0))
  189. @router.get("/user/list-by-permission")
  190. def list_users_by_permission(
  191. permission: str = Query(...),
  192. db: Session = Depends(get_db),
  193. ):
  194. return list_users(UserQuery(), db)
  195. @router.get("/dict/data/type/{dict_type}")
  196. def dict_data_by_type(dict_type: str, db: Session = Depends(get_db)):
  197. redis = get_redis()
  198. cache_key = f"dict:data:{dict_type}"
  199. cached = redis.get(cache_key)
  200. if cached:
  201. return R.ok(data=json.loads(cached))
  202. items = (
  203. db.query(SysDictData)
  204. .filter(SysDictData.dict_type == dict_type)
  205. .order_by(SysDictData.dict_sort)
  206. .all()
  207. )
  208. data = [
  209. {
  210. "dictCode": d.dict_code,
  211. "dictSort": d.dict_sort,
  212. "dictLabel": d.dict_label,
  213. "dictValue": d.dict_value,
  214. "dictType": d.dict_type,
  215. "cssClass": d.css_class or "",
  216. "listClass": d.list_class or "",
  217. "isDefault": d.is_default,
  218. "remark": d.remark or "",
  219. }
  220. for d in items
  221. ]
  222. redis.setex(cache_key, 3600, json.dumps(data, ensure_ascii=False))
  223. return R.ok(data=data)
  224. @router.get("/dept/list")
  225. def dept_list(
  226. parent_id: Optional[int] = Query(None),
  227. status: Optional[str] = Query(None),
  228. db: Session = Depends(get_db),
  229. ):
  230. q = db.query(SysDept).filter(SysDept.del_flag == "0")
  231. if status:
  232. q = q.filter(SysDept.status == status)
  233. depts = q.order_by(SysDept.order_num).all()
  234. return R.ok(data=[
  235. {
  236. "deptId": d.dept_id,
  237. "parentId": d.parent_id,
  238. "ancestors": d.ancestors,
  239. "deptName": d.dept_name,
  240. "deptCategory": d.dept_category or "",
  241. "orderNum": d.order_num,
  242. "leader": d.leader,
  243. "phone": d.phone or "",
  244. "email": d.email or "",
  245. "status": d.status,
  246. }
  247. for d in depts
  248. ])
  249. @router.get("/dept/treeselect")
  250. def dept_treeselect(db: Session = Depends(get_db)):
  251. return dept_tree(db)
  252. @router.post("/oss/upload")
  253. def upload_file(request: Request, db: Session = Depends(get_db)):
  254. return R.fail("OSS upload not yet implemented - use existing Java backend for file uploads")
  255. @router.get("/oss/{oss_id}")
  256. def get_oss(oss_id: int, db: Session = Depends(get_db)):
  257. oss = db.query(SysOss).filter(SysOss.oss_id == oss_id).first()
  258. if not oss:
  259. return R.fail("文件不存在")
  260. return R.ok(data={
  261. "ossId": oss.oss_id,
  262. "fileName": oss.file_name,
  263. "originalName": oss.original_name,
  264. "fileSuffix": oss.file_suffix,
  265. "url": oss.url,
  266. })
  267. @router.get("/menu/getRouters")
  268. def get_routers(current_user: dict = Depends(get_current_user), db: Session = Depends(get_db)):
  269. user_id = current_user.get("user_id")
  270. rows = db.execute(text("""
  271. SELECT m.menu_id, m.menu_name, m.parent_id, m.order_num, m.path, m.component,
  272. m.query_param, m.is_frame, m.is_cache, m.menu_type, m.visible, m.status, m.icon, m.perms
  273. FROM sys_menu m
  274. WHERE m.menu_type IN ('M', 'C') AND m.status = '0'
  275. ORDER BY m.parent_id, m.order_num
  276. """)).fetchall()
  277. menus = []
  278. for r in rows:
  279. menus.append({
  280. "menu_id": r[0],
  281. "menu_name": r[1],
  282. "parent_id": r[2],
  283. "order_num": r[3],
  284. "path": r[4] or "",
  285. "component": r[5] or "",
  286. "query_param": r[6] or "",
  287. "is_frame": r[7],
  288. "is_cache": r[8],
  289. "menu_type": r[9],
  290. "visible": r[10],
  291. "status": r[11],
  292. "icon": r[12] or "",
  293. "perms": r[13] or "",
  294. })
  295. routers = _build_router_tree(menus, 0)
  296. return R.ok(data=routers)
  297. @router.get("/oss/listByIds/{oss_id}")
  298. def list_oss_by_ids(oss_id: str, db: Session = Depends(get_db)):
  299. ids = []
  300. for part in str(oss_id).split(","):
  301. part = part.strip()
  302. if part.isdigit():
  303. ids.append(int(part))
  304. if not ids:
  305. return R.ok(data=[])
  306. rows = db.query(SysOss).filter(SysOss.oss_id.in_(ids)).all()
  307. return R.ok(data=[{
  308. "ossId": o.oss_id,
  309. "fileName": o.file_name,
  310. "originalName": o.original_name,
  311. "fileSuffix": o.file_suffix,
  312. "url": o.url,
  313. "size": o.size if hasattr(o, "size") else "",
  314. } for o in rows])