__init__.py 14 KB

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