__init__.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. from fastapi import APIRouter, Request, Depends, Query, HTTPException, status
  4. from common.security import valid_access_token
  5. from pydantic import BaseModel
  6. from database import get_db
  7. from sqlalchemy.orm import Session
  8. from typing import List
  9. from models import *
  10. from utils import *
  11. from utils.ry_system_util import *
  12. import json
  13. from sqlalchemy.sql import func
  14. from common.auth_user import *
  15. from common.enc import mpfun, sys_menu_data, sys_menu_layer_data
  16. import traceback
  17. from common.db import db_czrz
  18. from exceptions import HmacException
  19. router = APIRouter()
  20. # 定义 Meta 和 Child 模型用于嵌套结构
  21. class Meta(BaseModel):
  22. title: str
  23. icon: str
  24. noCache: bool
  25. link: str = None
  26. class Child(BaseModel):
  27. name: str
  28. path: str
  29. hidden: bool
  30. component: str
  31. meta: Meta
  32. children: List['Child'] = []
  33. class Router(BaseModel):
  34. name: str
  35. path: str
  36. hidden: bool
  37. redirect: str = 'noRedirect'
  38. component: str
  39. alwaysShow: bool = True
  40. meta: Meta
  41. children: List[Child] = []
  42. class Router_frame(BaseModel):
  43. component:str
  44. hidden: bool
  45. meta:Meta
  46. name: str
  47. path: str
  48. redirect: str = 'noRedirect'
  49. children: List[Child] = []
  50. alwaysShow: bool = True
  51. # checkedKeys roleMenuTreeselect
  52. @router.get('/getRouters')
  53. async def getRouters(request: Request, db: Session = Depends(get_db),
  54. body = Depends(remove_xss_json),
  55. user_id = Depends(valid_access_token)):
  56. try:
  57. # 查询数据库中的所有菜单项,根据 parent_id 排序以构建树形结构
  58. query = db.query(SysMenuLayer)
  59. query = query.filter_by(parent_id=0)
  60. query = query.filter(SysMenuLayer.del_flag != '2')
  61. menus =query.all() # 顶级菜单
  62. # 递归函数用于构建树形结构
  63. def build_menu_tree(menus, parent_menu):
  64. menu_tree = [] # 初始化一个列表来存储菜单树结构
  65. for menu in menus:
  66. if menu.is_frame==0:
  67. menu_data = Router_frame(
  68. component=menu.component or 'Layout',
  69. hidden=menu.layer_visible == '1',
  70. name=menu.path,
  71. path='/'+menu.path,
  72. meta = Meta(
  73. title=menu.menu_name,
  74. icon=menu.icon,
  75. noCache=menu.is_cache == '1',
  76. link = menu.path
  77. ),
  78. children=[]
  79. )
  80. else:
  81. menu_data = Router(
  82. name=menu.path,#menu.menu_name,
  83. path='/'+menu.path,
  84. hidden=menu.layer_visible == '1',
  85. component=menu.component or 'Layout',
  86. meta=Meta(
  87. title=menu.menu_name,
  88. icon=menu.icon,
  89. noCache=menu.is_cache == '1'
  90. ),
  91. children=[] # 初始化 children 列表,即使没有子菜单
  92. )
  93. # 如果菜单有子菜单,则递归构建子菜单
  94. if menu.menu_type == 'M': # 假设 'M' 表示目录类型
  95. query = db.query(SysMenuLayer)
  96. query = query.filter_by(parent_id=menu.menu_id)
  97. query = query.filter(SysMenuLayer.del_flag != '2')
  98. # children_menus = db.query(SysMenu).filter_by(parent_id=menu.menu_id).all()
  99. children_menus = query.all()
  100. menu_data.children = build_menu_tree(children_menus, menu)
  101. else:
  102. del menu_data.children #没有子菜单,删除children 列表
  103. del menu_data.redirect
  104. del menu_data.alwaysShow
  105. menu_data.path = menu_data.path[1:]
  106. menu_tree.append(menu_data) # 将当前菜单数据添加到菜单树列表
  107. return menu_tree
  108. # 构建顶级菜单的树形结构
  109. routers = build_menu_tree(menus, None)
  110. # routers_dict = [router.dict() for router in routers]
  111. routers_dict = []
  112. for router in routers:
  113. router_info = router.dict()
  114. if len(router_info['children'])==0:
  115. del router_info['children']
  116. del router_info['redirect']
  117. del router_info['alwaysShow']
  118. router_info['path'] = router_info['path'][1:]
  119. routers_dict.append(router_info)
  120. # 返回构建好的路由数据
  121. return {
  122. "code": 200,
  123. "msg": "操作成功",
  124. "data": routers_dict #[router.dict() for router in routers] # 如果没有顶级菜单,返回空列表
  125. }
  126. except Exception as e:
  127. # 处理异常,返回错误信息
  128. raise HTTPException(status_code=500, detail=str(e))
  129. @router.get('/list')
  130. async def get_list(
  131. # request: Request,
  132. menuName: str = Query(None, max_length=100),
  133. status: str = Query(None, max_length=100),
  134. db: Session = Depends(get_db),
  135. body = Depends(remove_xss_json),
  136. user_id = Depends(valid_access_token)
  137. ):
  138. query = db.query(SysMenuLayer)
  139. query = query.filter(SysMenuLayer.del_flag != '2')
  140. if menuName:
  141. query = query.filter(SysMenuLayer.menu_name.like(f'%{menuName}%'))
  142. if status:
  143. query = query.filter(SysMenuLayer.status.like(f'%{status}%'))
  144. # 应用查询
  145. # menu_list = db.query(SysMenu).filter(
  146. # (SysMenu.menu_name.like(f'%{menu_name}%')) ,
  147. # (SysMenu.status.like(f'%{status}%'))
  148. # ).all()
  149. menu_list = query.all()
  150. # 将模型实例转换为字典
  151. menu_list_dict = [{
  152. "menuId": menu.menu_id,
  153. "menuName": menu.menu_name,
  154. "parentId": menu.parent_id,
  155. "orderNum": menu.order_num,
  156. "path": menu.path,
  157. "component": menu.component,
  158. "queryParam": menu.query_param,
  159. "isFrame": str(menu.is_frame),
  160. "isCache": str(menu.is_cache),
  161. "menuType": menu.menu_type,
  162. "layer_visible": menu.layer_visible,
  163. "status": menu.status,
  164. "perms": menu.perms,
  165. "icon": menu.icon,
  166. "createDept": menu.create_dept,
  167. "remark": menu.remark,
  168. "createTime": menu.create_time.strftime('%Y-%m-%d %H:%M:%S') if menu.create_time else '',
  169. "children": [] # 递归调用以获取子菜单
  170. } for menu in menu_list]
  171. # 构建分页响应
  172. # pagination_info = {
  173. # "total": total_count,
  174. # "page_num": page_num,
  175. # "page_size": page_size,
  176. # "total_pages": (total_count + page_size - 1) // page_size # 计算总页数
  177. # }
  178. return {
  179. "code": 200,
  180. "data": menu_list_dict,
  181. # 'pages': page_num, # 总页数
  182. # 'currentPage': page_num, # 当前页数
  183. # # 'current':current,
  184. # # 'total' : total,
  185. # 'total': total_count, # 总数据量
  186. # # 'size':size,
  187. # 'pageSize': page_size, # 页码
  188. # {
  189. # "items": menu_list_dict,
  190. # "pagination": pagination_info
  191. # },
  192. "msg": "操作成功"
  193. }
  194. @router.get('/info/{menuid}')
  195. async def get_list(
  196. # request: Request,
  197. menuid: str = Query(None, max_length=100),
  198. db: Session = Depends(get_db),
  199. body = Depends(remove_xss_json),
  200. user_id = Depends(valid_access_token)
  201. ):
  202. query = db.query(SysMenuLayer)
  203. query = query.filter(SysMenuLayer.del_flag != '2')
  204. if menuid:
  205. query = query.filter(SysMenuLayer.menu_id.like(f'{menuid}'))
  206. menu= query.first()
  207. # 将模型实例转换为字典
  208. menu_list_dict = {
  209. "menuId": menu.menu_id,
  210. "menuName": menu.menu_name,
  211. "parentId": menu.parent_id,
  212. "orderNum": menu.order_num,
  213. "path": menu.path,
  214. "component": menu.component,
  215. "queryParam": menu.query_param,
  216. "isFrame": str(menu.is_frame),
  217. "isCache": str(menu.is_cache),
  218. "menuType": menu.menu_type,
  219. "layer_visible": menu.layer_visible,
  220. "status": menu.status,
  221. "perms": menu.perms,
  222. "icon": menu.icon,
  223. "createDept": menu.create_dept,
  224. "remark": menu.remark,
  225. "createTime": menu.create_time.strftime('%Y-%m-%d %H:%M:%S') if menu.create_time else '',
  226. "children": [], # 递归调用以获取子菜单
  227. "layer_template":menu.layer_template
  228. }
  229. return {
  230. "code": 200,
  231. "data": menu_list_dict,
  232. "msg": "操作成功"
  233. }
  234. @router.post('/create')
  235. async def create(
  236. request: Request,
  237. # form_data: SysMuneCreateForm,
  238. db: Session = Depends(get_db),
  239. body=Depends(remove_xss_json),
  240. auth_user: AuthUser = Depends(find_auth_user),
  241. user_id=Depends(valid_access_token)
  242. ):
  243. try:
  244. # 开始事务
  245. # db.begin()
  246. # 创建新的菜单层,此时还不能使用new_menu.menu_id,因为它还没有被赋值
  247. new_menu_layer = SysMenuLayer(
  248. menu_name=body['menuName'],
  249. parent_id=body['parentId'],
  250. order_num=body['orderNum'],
  251. path=body['path'],
  252. is_frame=int(body['isFrame']),
  253. is_cache=int(body['isCache']),
  254. menu_type=body['menuType'],
  255. layer_visible=body['layer_visible'],
  256. status=body['status'],
  257. icon=body['icon'],
  258. component=body['component'],
  259. perms=body['perms'],
  260. query_param=body['queryParam'],
  261. create_by=user_id,
  262. layer_template=body['layer_template']
  263. )
  264. db.add(new_menu_layer)
  265. # 提交事务
  266. db.commit()
  267. sys_menu_data.sign_table()
  268. sys_menu_layer_data.sign_table()
  269. db_czrz.log(db, auth_user, "系统管理", f"后台管理新建地图菜单【{body['menuName']}】成功", request.client.host)
  270. return {
  271. "code": 200,
  272. "data": None,#new_menu_layer.menu_id, # 返回新创建的SysMenuLayer的ID
  273. "msg": "操作成功"
  274. }
  275. except Exception as e:
  276. traceback.print_exc()
  277. # 如果发生异常,回滚事务
  278. db.rollback()
  279. raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
  280. @router.put('/update')
  281. async def update(
  282. request: Request,
  283. auth_user: AuthUser = Depends(find_auth_user),
  284. # form_data: SysMuneUpdateForm,
  285. db: Session = Depends(get_db),
  286. body = Depends(remove_xss_json),
  287. user_id = Depends(valid_access_token)
  288. ):
  289. try:
  290. queryLayer = db.query(SysMenuLayer)
  291. queryLayer = queryLayer.filter(SysMenuLayer.menu_id == body['menuId'])
  292. queryLayer = queryLayer.filter(SysMenuLayer.del_flag != '2')
  293. menu = queryLayer.first()
  294. if not menu:
  295. detail = "菜单不存在"
  296. raise HTTPException(status_code=404, detail="菜单不存在")
  297. # 更新字段,排除主键和不可更新的字段
  298. if 'component' in body:
  299. menu.component = body['component']
  300. if 'icon' in body:
  301. menu.icon = body['icon']
  302. if 'isCache' in body:
  303. menu.is_cache = body['isCache']
  304. if 'isFrame' in body:
  305. menu.is_frame = body['isFrame']
  306. if 'menuName' in body:
  307. menu.menu_name = body['menuName']
  308. if 'menuType' in body:
  309. menu.menu_type = body['menuType']
  310. if 'orderNum' in body:
  311. menu.order_num = body['orderNum']
  312. if 'parentId' in body:
  313. menu.parent_id = body['parentId']
  314. if 'path' in body:
  315. menu.path = body['path']
  316. if 'perms' in body:
  317. menu.perms = body['perms']
  318. if 'queryParam' in body:
  319. menu.query_param = body['queryParam']
  320. if 'status' in body:
  321. menu.status = body['status']
  322. if 'layer_visible' in body:
  323. menu.layer_visible = body['layer_visible']
  324. if 'layer_template' in body:
  325. menu.layer_template = body['layer_template']
  326. menu.update_by = user_id
  327. menu.update_time = datetime.now()
  328. menu.sign = sys_menu_layer_data.get_sign_hmac(menu)
  329. db.commit()
  330. db_czrz.log(db, auth_user, "系统管理", f"后台管理更新地图菜单【{body['menuName']}】成功", request.client.host)
  331. return {
  332. "code": 200,
  333. "msg": "菜单更新成功"
  334. }
  335. except Exception as e:
  336. traceback.print_exc()
  337. # db.rollback()
  338. if str(e)=='':
  339. e = detail
  340. raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
  341. @router.delete('/delete/{menu_id}')
  342. async def delete(
  343. request: Request,
  344. menu_id: int,
  345. db: Session = Depends(get_db),
  346. body = Depends(remove_xss_json),
  347. auth_user: AuthUser = Depends(find_auth_user),
  348. user_id = Depends(valid_access_token)
  349. ):
  350. try:
  351. db.begin()
  352. query = db.query(SysMenu)
  353. query = query.filter(SysMenu.menu_id == menu_id)
  354. query = query.filter(SysMenu.del_flag != '2')
  355. menu_to_delete =query.first()
  356. if not menu_to_delete:
  357. detail = "菜单不存在"
  358. raise HTTPException(status_code=404, detail="菜单不存在")
  359. menu_to_delete.create_by = user_id
  360. menu_to_delete.del_flag='2'
  361. # db.delete(menu_to_delete)
  362. # db.commit()
  363. queryLayer = db.query(SysMenuLayer)
  364. queryLayer = queryLayer.filter(SysMenuLayer.menu_id == menu_id)
  365. queryLayer = queryLayer.filter(SysMenuLayer.del_flag != '2')
  366. menu_to_delete = queryLayer.first()
  367. if not menu_to_delete:
  368. detail = "菜单不存在"
  369. raise HTTPException(status_code=404, detail="菜单不存在")
  370. menu_to_delete.update_by = user_id
  371. menu_to_delete.update_time = datetime.now()
  372. menu_to_delete.del_flag = '2'
  373. menu_to_delete.sign = sys_menu_layer_data.get_sign_hmac(menu_to_delete)
  374. db.commit()
  375. db_czrz.log(db, auth_user, "系统管理", f"后台管理删除菜单【{menu_to_delete.menu_name}】成功", request.client.host)
  376. return {
  377. "code": 200,
  378. "msg": "菜单删除成功"
  379. }
  380. except Exception as e:
  381. traceback.print_exc()
  382. db.rollback()
  383. if str(e)=='':
  384. e = detail
  385. raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))