__init__.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  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. def get_video_routers(db:Session):
  54. from utils.video_util import tag_get_video_tag_list
  55. query = db.query(SysDictData)
  56. query = query.filter(SysDictData.dict_type == 'video_type')
  57. query = query.filter(SysDictData.del_flag != '2')
  58. query = query.order_by(SysDictData.dict_sort)
  59. # dict_data = db.query(SysDictData).filter_by(dict_type==dict_type and del_flag != '2').all()
  60. dict_data = query.all()
  61. # 将模型转换为字典
  62. dict_data_list = [{
  63. "component": '4',
  64. "isVideo":False,
  65. "hidden": True,
  66. "name": '4',
  67. "path": '2',
  68. # "redirect":'noRedirect',
  69. # "alwaysShow":True,
  70. "meta": {
  71. "title": '附近视频',
  72. 'icon': 'icon6',
  73. 'noCache': False,
  74. }
  75. }]
  76. for d in dict_data:
  77. li = tag_get_video_tag_list(db, d.dict_value)
  78. if len(li) > 0:
  79. dict_data_list.append({
  80. "component": d.dict_value or 'Layout',
  81. "isVideo":True,
  82. "hidden": True,
  83. "name": d.dict_value,
  84. "path": '2',
  85. # "redirect":'noRedirect',
  86. # "alwaysShow":True,
  87. "meta": {
  88. "title": d.dict_label,
  89. 'icon': 'icon6',
  90. 'noCache': False,
  91. }
  92. })
  93. return dict_data_list
  94. @router.get('/getRouters')
  95. async def getRouters(request: Request, db: Session = Depends(get_db),
  96. body = Depends(remove_xss_json),
  97. ZT: str = Query(None, max_length=100),
  98. user_id = Depends(valid_access_token)):
  99. try:
  100. # 查询数据库中的所有菜单项,根据 parent_id 排序以构建树形结构
  101. query = db.query(SysMenuLayer)
  102. query = query.filter_by(parent_id=0)
  103. query = query.filter(SysMenuLayer.del_flag != '2')
  104. query = query.filter(SysMenuLayer.status != '1')
  105. if ZT:
  106. query = query.filter(SysMenuLayer.layer_template.like(f"%;{ZT};%"))
  107. query = query.order_by(SysMenuLayer.order_num)
  108. menus =query.all() # 顶级菜单
  109. # 递归函数用于构建树形结构
  110. def build_menu_tree(menus, parent_menu):
  111. menu_tree = [] # 初始化一个列表来存储菜单树结构
  112. for menu in menus:
  113. if menu.is_frame==0:
  114. menu_data = Router_frame(
  115. component=menu.component or 'Layout',
  116. hidden=menu.layer_visible == '1',
  117. name=menu.path,
  118. path='/'+menu.path,
  119. meta = Meta(
  120. title=menu.menu_name,
  121. icon=menu.icon,
  122. noCache=menu.is_cache == '1',
  123. link = menu.path
  124. ),
  125. children=[]
  126. )
  127. else:
  128. menu_data = Router(
  129. name=menu.path,#menu.menu_name,
  130. path='/'+menu.path,
  131. hidden=menu.layer_visible == '1',
  132. component=menu.component or 'Layout',
  133. meta=Meta(
  134. title=menu.menu_name,
  135. icon=menu.icon,
  136. noCache=menu.is_cache == '1'
  137. ),
  138. children=[] # 初始化 children 列表,即使没有子菜单
  139. )
  140. # 如果菜单有子菜单,则递归构建子菜单
  141. if menu.menu_type == 'D' or menu.menu_type == 'Z': # 假设 'M' 表示目录类型
  142. if menu.menu_id==11684:
  143. menu_data.children = get_video_routers(db)
  144. menu_tree.append(menu_data)
  145. continue
  146. query = db.query(SysMenuLayer)
  147. query = query.filter_by(parent_id=menu.menu_id)
  148. query = query.filter(SysMenuLayer.del_flag != '2')
  149. query = query.filter(SysMenuLayer.status != '1')
  150. if ZT:
  151. query = query.filter(SysMenuLayer.layer_template.like(f"%;{ZT};%"))
  152. query = query.order_by(SysMenuLayer.order_num)
  153. # children_menus = db.query(SysMenu).filter_by(parent_id=menu.menu_id).all()
  154. children_menus = query.all()
  155. menu_data.children = build_menu_tree(children_menus, menu)
  156. else:
  157. del menu_data.children #没有子菜单,删除children 列表
  158. del menu_data.redirect
  159. del menu_data.alwaysShow
  160. menu_data.path = menu_data.path[1:]
  161. menu_tree.append(menu_data) # 将当前菜单数据添加到菜单树列表
  162. return menu_tree
  163. # 构建顶级菜单的树形结构
  164. routers = build_menu_tree(menus, None)
  165. # routers_dict = [router.dict() for router in routers]
  166. routers_dict = []
  167. for router in routers:
  168. router_info = router.dict()
  169. print(router_info)
  170. if 'children' in router_info:
  171. if len(router_info['children'])==0:
  172. del router_info['children']
  173. del router_info['redirect']
  174. del router_info['alwaysShow']
  175. router_info['path'] = router_info['path'][1:]
  176. routers_dict.append(router_info)
  177. # 返回构建好的路由数据
  178. query = db.query(SysDictData)
  179. query = query.filter(SysDictData.del_flag != '2')
  180. query = query.filter(SysDictData.dict_type == 'sys_menu_layer_zt')
  181. if ZT is None:
  182. routers_dict = []
  183. # return {
  184. # "code": 200,
  185. # "data": [],
  186. # "msg": "操作成功"
  187. # }
  188. query = query.order_by(SysDictData.order_num)
  189. zt_list = query.all()
  190. zt = []
  191. for info in zt_list:
  192. zt.append({"data":[i for i in info.remark.split(';') if i != ''] if info.remark else [],'zt':info.dict_label,"zt_code":info.dict_value})
  193. return {
  194. "code": 200,
  195. "msg": "操作成功",
  196. "data": routers_dict, #[router.dict() for router in routers] # 如果没有顶级菜单,返回空列表
  197. 'zt':zt
  198. }
  199. except Exception as e:
  200. # 处理异常,返回错误信息
  201. traceback.print_exc()
  202. raise HTTPException(status_code=500, detail=str(e))
  203. @router.get('/list')
  204. async def get_list(
  205. # request: Request,
  206. menuName: str = Query(None, max_length=100),
  207. status: str = Query(None, max_length=100),
  208. ZT: str = Query(None, max_length=100),
  209. db: Session = Depends(get_db),
  210. body = Depends(remove_xss_json),
  211. user_id = Depends(valid_access_token)
  212. ):
  213. query = db.query(SysMenuLayer)
  214. query = query.filter(SysMenuLayer.del_flag != '2')
  215. if menuName:
  216. query = query.filter(SysMenuLayer.menu_name.like(f'%{menuName}%'))
  217. if status:
  218. query = query.filter(SysMenuLayer.status==status)
  219. if ZT:
  220. query = query.filter(SysMenuLayer.layer_template.like(f"%;{ZT};%"))
  221. query = query.order_by(SysMenuLayer.order_num)
  222. # 应用查询
  223. # menu_list = db.query(SysMenu).filter(
  224. # (SysMenu.menu_name.like(f'%{menu_name}%')) ,
  225. # (SysMenu.status.like(f'%{status}%'))
  226. # ).all()
  227. menu_list = query.all()
  228. # 将模型实例转换为字典
  229. menu_list_dict = [{
  230. "menuId": menu.menu_id,
  231. "menuName": menu.menu_name,
  232. "parentId": menu.parent_id,
  233. "orderNum": menu.order_num,
  234. "path": menu.path,
  235. "component": menu.component,
  236. # "queryParam": menu.query_param,
  237. # "isFrame": str(menu.is_frame),
  238. # "isCache": str(menu.is_cache),
  239. "menuType": menu.menu_type,
  240. # "layerVisible": menu.layer_visible,
  241. "status": menu.status,
  242. # "perms": menu.perms,
  243. "icon": menu.icon,
  244. # "createDept": menu.create_dept,
  245. "remark": menu.remark,
  246. "createTime": menu.create_time.strftime('%Y-%m-%d %H:%M:%S') if menu.create_time else '',
  247. "children": [] , # 递归调用以获取子菜单
  248. "ZT":[i for i in menu.layer_template.split(';') if i != ''] if menu.layer_template else []
  249. } for menu in menu_list]
  250. return {
  251. "code": 200,
  252. "data": menu_list_dict,
  253. "msg": "操作成功"
  254. }
  255. @router.get('/info/{menuid}')
  256. async def get_list(
  257. # request: Request,
  258. menuid: str = Query(None, max_length=100),
  259. db: Session = Depends(get_db),
  260. body = Depends(remove_xss_json),
  261. user_id = Depends(valid_access_token)
  262. ):
  263. query = db.query(SysMenuLayer)
  264. query = query.filter(SysMenuLayer.del_flag != '2')
  265. if menuid:
  266. query = query.filter(SysMenuLayer.menu_id==menuid)
  267. menu= query.first()
  268. # 将模型实例转换为字典
  269. menu_list_dict = {
  270. "menuId": menu.menu_id,
  271. "menuName": menu.menu_name,
  272. "parentId": menu.parent_id,
  273. "orderNum": menu.order_num,
  274. "path": menu.path,
  275. "component": menu.component,
  276. # "queryParam": menu.query_param,
  277. # "isFrame": str(menu.is_frame),
  278. # "isCache": str(menu.is_cache),
  279. "menuType": menu.menu_type,
  280. # "layerVisible": menu.layer_visible,
  281. "status": menu.status,
  282. # "perms": menu.perms,
  283. "icon": menu.icon,
  284. # "createDept": menu.create_dept,
  285. "remark": menu.remark,
  286. "createTime": menu.create_time.strftime('%Y-%m-%d %H:%M:%S') if menu.create_time else '',
  287. "children": [], # 递归调用以获取子菜单
  288. "ZT":[i for i in menu.layer_template.split(';') if i != ''] if menu.layer_template else []
  289. }
  290. return {
  291. "code": 200,
  292. "data": menu_list_dict,
  293. "msg": "操作成功"
  294. }
  295. @router.post('/create')
  296. async def create(
  297. request: Request,
  298. # form_data: SysMuneCreateForm,
  299. db: Session = Depends(get_db),
  300. body=Depends(remove_xss_json),
  301. auth_user: AuthUser = Depends(find_auth_user),
  302. user_id=Depends(valid_access_token)
  303. ):
  304. try:
  305. # 开始事务
  306. # db.begin()
  307. layer_template = ';'+';'.join(body['ZT'])+';'
  308. # 创建新的菜单层,此时还不能使用new_menu.menu_id,因为它还没有被赋值
  309. new_menu_layer = SysMenuLayer(
  310. menu_name=body['menuName'],
  311. parent_id=body['parentId'],
  312. order_num=body['orderNum'],
  313. path=body['path'],
  314. # is_frame=int(body['isFrame']),
  315. # is_cache=int(body['isCache']),
  316. menu_type=body['menuType'],
  317. # layer_visible=body['layerVisible'],
  318. status=body['status'],
  319. icon=body['icon'],
  320. component=body['component'],
  321. # perms=body['perms'],
  322. # query_param=body['queryParam'],
  323. create_by=user_id,
  324. layer_template=layer_template
  325. )
  326. db.add(new_menu_layer)
  327. # 提交事务
  328. db.commit()
  329. sys_menu_data.sign_table()
  330. sys_menu_layer_data.sign_table()
  331. db_czrz.log(db, auth_user, "系统管理", f"后台管理新建地图菜单【{body['menuName']}】成功", request.client.host)
  332. return {
  333. "code": 200,
  334. "data": None,#new_menu_layer.menu_id, # 返回新创建的SysMenuLayer的ID
  335. "msg": "操作成功"
  336. }
  337. except Exception as e:
  338. traceback.print_exc()
  339. # 如果发生异常,回滚事务
  340. db.rollback()
  341. raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
  342. @router.put('/update')
  343. async def update(
  344. request: Request,
  345. auth_user: AuthUser = Depends(find_auth_user),
  346. # form_data: SysMuneUpdateForm,
  347. db: Session = Depends(get_db),
  348. body = Depends(remove_xss_json),
  349. user_id = Depends(valid_access_token)
  350. ):
  351. try:
  352. queryLayer = db.query(SysMenuLayer)
  353. queryLayer = queryLayer.filter(SysMenuLayer.menu_id == body['menuId'])
  354. queryLayer = queryLayer.filter(SysMenuLayer.del_flag != '2')
  355. menu = queryLayer.first()
  356. if not menu:
  357. detail = "菜单不存在"
  358. raise HTTPException(status_code=404, detail="菜单不存在")
  359. # 更新字段,排除主键和不可更新的字段
  360. if 'component' in body:
  361. menu.component = body['component']
  362. if 'icon' in body:
  363. menu.icon = body['icon']
  364. # if 'isCache' in body:
  365. # menu.is_cache = body['isCache']
  366. # if 'isFrame' in body:
  367. # menu.is_frame = body['isFrame']
  368. if 'menuName' in body:
  369. menu.menu_name = body['menuName']
  370. if 'menuType' in body:
  371. menu.menu_type = body['menuType']
  372. if 'orderNum' in body:
  373. menu.order_num = body['orderNum']
  374. if 'parentId' in body:
  375. menu.parent_id = body['parentId']
  376. if 'path' in body:
  377. menu.path = body['path']
  378. # if 'perms' in body:
  379. # menu.perms = body['perms']
  380. # if 'queryParam' in body:
  381. # menu.query_param = body['queryParam']
  382. if 'status' in body:
  383. menu.status = body['status']
  384. # if 'layer_visible' in body:
  385. # menu.layer_visible = body['layerVisible']
  386. if 'ZT' in body:
  387. layer_template = ';' + ';'.join(body['ZT']) + ';'
  388. menu.layer_template = layer_template
  389. menu.update_by = user_id
  390. menu.update_time = datetime.now()
  391. menu.sign = sys_menu_layer_data.get_sign_hmac(menu)
  392. db.commit()
  393. db_czrz.log(db, auth_user, "系统管理", f"后台管理更新地图菜单【{body['menuName']}】成功", request.client.host)
  394. return {
  395. "code": 200,
  396. "msg": "菜单更新成功"
  397. }
  398. except Exception as e:
  399. traceback.print_exc()
  400. # db.rollback()
  401. if str(e)=='':
  402. e = detail
  403. raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
  404. @router.delete('/delete/{menu_id}')
  405. async def delete(
  406. request: Request,
  407. menu_id: int,
  408. db: Session = Depends(get_db),
  409. body = Depends(remove_xss_json),
  410. auth_user: AuthUser = Depends(find_auth_user),
  411. user_id = Depends(valid_access_token)
  412. ):
  413. try:
  414. queryLayer = db.query(SysMenuLayer)
  415. queryLayer = queryLayer.filter(SysMenuLayer.menu_id == menu_id)
  416. queryLayer = queryLayer.filter(SysMenuLayer.del_flag != '2')
  417. menu_to_delete = queryLayer.first()
  418. if not menu_to_delete:
  419. detail = "菜单不存在"
  420. return JSONResponse(status_code=404,content={"code":404,"msg":"该id不存在"})
  421. menu_to_delete.update_by = user_id
  422. menu_to_delete.update_time = datetime.now()
  423. menu_to_delete.del_flag = '2'
  424. menu_to_delete.sign = sys_menu_layer_data.get_sign_hmac(menu_to_delete)
  425. db.commit()
  426. db_czrz.log(db, auth_user, "系统管理", f"后台管理删除菜单【{menu_to_delete.menu_name}】成功", request.client.host)
  427. return {
  428. "code": 200,
  429. "msg": "菜单删除成功"
  430. }
  431. except Exception as e:
  432. traceback.print_exc()
  433. db.rollback()
  434. return JSONResponse(status_code=404, content={"code": 404, "msg": str(e)})
  435. @router.get('/zt/dt/list')
  436. async def get_list(
  437. ZT: str = Query(None, max_length=100),
  438. db: Session = Depends(get_db),
  439. body = Depends(remove_xss_json),
  440. user_id = Depends(valid_access_token)
  441. ):
  442. query = db.query(SysDictData)
  443. query = query.filter(SysDictData.del_flag != '2')
  444. query = query.filter(SysDictData.dict_type=='sys_menu_layer_zt')
  445. if ZT is None:
  446. return {
  447. "code": 200,
  448. "data": [],
  449. "msg": "操作成功"
  450. }
  451. query = query.filter(SysDictData.dict_value==ZT)
  452. # query = query.order_by(SysDictData.order_num)
  453. # 应用查询
  454. # menu_list = db.query(SysMenu).filter(
  455. # (SysMenu.menu_name.like(f'%{menu_name}%')) ,
  456. # (SysMenu.status.like(f'%{status}%'))
  457. # ).all()
  458. zt = query.first()
  459. if zt is None:
  460. return {
  461. "code": 200,
  462. "data": [],
  463. "msg": "操作成功"
  464. }
  465. # 将模型实例转换为字典
  466. zt_list = [i for i in zt.remark.split(';') if i != ''] if zt.remark else []
  467. return {
  468. "code": 200,
  469. "data": zt_list,
  470. "msg": "操作成功"
  471. }
  472. @router.put('/zt/{id}/dt/update')
  473. async def update(
  474. request: Request,
  475. id:str,
  476. auth_user: AuthUser = Depends(find_auth_user),
  477. # form_data: SysMuneUpdateForm,
  478. db: Session = Depends(get_db),
  479. body = Depends(remove_xss_json),
  480. user_id = Depends(valid_access_token)
  481. ):
  482. try:
  483. query = db.query(SysDictData)
  484. query = query.filter(SysDictData.del_flag != '2')
  485. query = query.filter(SysDictData.dict_type == 'sys_menu_layer_zt')
  486. query = query.filter(SysDictData.dict_value == id)
  487. zt = query.first()
  488. if zt is None:
  489. return JSONResponse(status_code=404, content={"code": 404, "msg": '专题不存在'})
  490. if 'dt' in body:
  491. remark = ';' + ';'.join(body['dt']) + ';'
  492. zt.remark = remark
  493. zt.update_by = user_id
  494. zt.update_time = datetime.now()
  495. db.commit()
  496. return {"code":200,"msg":"操作成功"}
  497. except Exception as e:
  498. traceback.print_exc()
  499. db.rollback()
  500. return JSONResponse(status_code=404, content={"code": 404, "msg": str(e)})