__init__.py 21 KB

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