sys_menu.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. package service
  2. import (
  3. dto2 "Medical_OAuth/common/dto"
  4. "Medical_OAuth/common/global"
  5. "encoding/json"
  6. "fmt"
  7. "gogs.baozhida.cn/zoie/OAuth-core/service"
  8. "sort"
  9. "strings"
  10. "github.com/pkg/errors"
  11. "gorm.io/gorm"
  12. "Medical_OAuth/app/admin/model"
  13. "Medical_OAuth/app/admin/service/dto"
  14. "gogs.baozhida.cn/zoie/OAuth-core/pkg"
  15. )
  16. type SysMenu struct {
  17. service.Service
  18. }
  19. // GetPage 获取SysMenu列表
  20. func (e *SysMenu) GetPage(c *dto.SysMenuGetPageReq, menus *[]model.SysMenu) *SysMenu {
  21. var menu = make([]model.SysMenu, 0)
  22. err := e.getPage(c, &menu).Error
  23. if err != nil {
  24. _ = e.AddError(global.GetFailedErr)
  25. return e
  26. }
  27. for i := 0; i < len(menu); i++ {
  28. if menu[i].ParentId != 0 {
  29. continue
  30. }
  31. menusInfo := menuCall(&menu, menu[i])
  32. *menus = append(*menus, menusInfo)
  33. }
  34. if len(*menus) == 0 {
  35. parentMap, flag := getMenuParent(&menu)
  36. if flag {
  37. for i := 0; i < len(menu); i++ {
  38. if parentMap[menu[i].ParentId] {
  39. continue
  40. }
  41. menusInfo := menuCall(&menu, menu[i])
  42. *menus = append(*menus, menusInfo)
  43. }
  44. } else {
  45. for i := 0; i < len(menu); i++ {
  46. menusInfo := menuCall(&menu, menu[i])
  47. *menus = append(*menus, menusInfo)
  48. }
  49. }
  50. }
  51. return e
  52. }
  53. func getMenuParent(menuList *[]model.SysMenu) (map[int]bool, bool) {
  54. list := *menuList
  55. var flag = false
  56. var parentMap = map[int]bool{}
  57. for j := 0; j < len(list); j++ {
  58. parentMap[list[j].ParentId] = false
  59. }
  60. for j := 0; j < len(list); j++ {
  61. if _, ok := parentMap[list[j].Id]; !ok {
  62. continue
  63. }
  64. parentMap[list[j].Id] = true
  65. flag = true
  66. }
  67. return parentMap, flag
  68. }
  69. // getPage 菜单分页列表
  70. func (e *SysMenu) getPage(c *dto.SysMenuGetPageReq, list *[]model.SysMenu) *SysMenu {
  71. var err error
  72. var data model.SysMenu
  73. var tempList []model.SysMenu
  74. var temp2List []model.SysMenu
  75. var temp3List []dto.SysMenu
  76. err = e.Orm.Model(&data).
  77. Scopes(dto2.MakeCondition(c.GetNeedSearch())).
  78. Find(&tempList).Error
  79. if err != nil {
  80. e.Log.Errorf("getSysMenuPage error: %s", err)
  81. _ = e.AddError(err)
  82. return e
  83. }
  84. // 获取菜单及其子菜单下ID
  85. for _, menu := range tempList {
  86. var menuList = make([]model.SysMenu, 0)
  87. err = e.Orm.Where("menu_path like ?", menu.MenuPath+"%").Order(fmt.Sprintf("sort %s", c.SortOrder)).Find(&menuList).Error
  88. temp2List = append(temp2List, menuList...)
  89. }
  90. ids := DeduplicateSysMenuIds(temp2List)
  91. err = e.Orm.Table("sys_menu").
  92. Select("*,sys_menu.id as id,sys_menu.parent_id as parent_id,sys_menu.visible as visible").
  93. Joins("left join serv_menu on sys_menu.service_menu_id=serv_menu.id and sys_menu.service_id=serv_menu.service_id").
  94. Where("sys_menu.id in (?) and serv_menu.name like ?", ids, "%"+c.Name+"%").
  95. Scan(&temp3List).Error
  96. for _, menu := range temp3List {
  97. *list = append(*list, menu.Generate())
  98. }
  99. return e
  100. }
  101. // DeduplicateSysMenuIds 去掉重复的ID
  102. func DeduplicateSysMenuIds(list []model.SysMenu) (deduplicated []int) {
  103. seen := make(map[string]bool)
  104. for _, v := range list {
  105. // 将结构体编码为 JSON 字符串
  106. key, err := json.Marshal(v)
  107. if err != nil {
  108. // 处理错误
  109. continue
  110. }
  111. // 将 JSON 字符串作为键插入到 map 中
  112. if _, ok := seen[string(key)]; !ok {
  113. seen[string(key)] = true
  114. deduplicated = append(deduplicated, v.Id)
  115. }
  116. }
  117. return deduplicated
  118. }
  119. // Get 获取SysMenu对象
  120. func (e *SysMenu) Get(d *dto.SysMenuGetReq, menuModel *model.SysMenu) *SysMenu {
  121. err := e.Orm.First(menuModel, d.GetId()).Error
  122. if err != nil {
  123. e.Log.Errorf("db error: %s", err)
  124. if errors.Is(err, gorm.ErrRecordNotFound) {
  125. err = global.GetNotFoundErr
  126. } else {
  127. err = global.GetFailedErr
  128. }
  129. _ = e.AddError(err)
  130. return e
  131. }
  132. var servMenu model.ServMenu
  133. _ = e.Orm.Where("id = ? and service_id = ?", menuModel.ServiceMenuId, menuModel.ServiceId).First(&servMenu).Error
  134. menuModel.Name = servMenu.Name
  135. menuModel.MenuType = servMenu.MenuType
  136. menuModel.Icon = servMenu.Icon
  137. menuModel.Component = servMenu.Component
  138. menuModel.IsFrame = servMenu.IsFrame
  139. menuModel.Path = servMenu.Path
  140. menuModel.Permission = servMenu.Permission
  141. return e
  142. }
  143. // Insert 创建SysMenu对象
  144. func (e *SysMenu) Insert(c *dto.SysMenuInsertReq) *SysMenu {
  145. var err error
  146. var data model.SysMenu
  147. c.Generate(&data)
  148. err = e.Orm.Create(&data).Error
  149. if err != nil {
  150. e.Log.Errorf("db error: %s", err)
  151. _ = e.AddError(global.CreateFailedErr)
  152. }
  153. c.Id = data.Id
  154. err = e.initPaths(&data)
  155. if err != nil {
  156. e.Log.Errorf("db error: %s", err)
  157. _ = e.AddError(err)
  158. }
  159. return e
  160. }
  161. // initPaths 初始化菜单paths
  162. func (e *SysMenu) initPaths(menu *model.SysMenu) error {
  163. var err error
  164. var data model.SysMenu
  165. parentMenu := new(model.SysMenu)
  166. if menu.ParentId != 0 {
  167. e.Orm.Model(&data).First(parentMenu, menu.ParentId)
  168. if parentMenu.MenuPath == "" {
  169. err = errors.New("父级paths异常,请尝试对当前节点父级菜单进行更新操作!")
  170. return err
  171. }
  172. menu.MenuPath = parentMenu.MenuPath + "/" + pkg.IntToString(menu.Id)
  173. } else {
  174. menu.MenuPath = "/0/" + pkg.IntToString(menu.Id)
  175. }
  176. e.Orm.Model(&data).Where("id = ?", menu.Id).Update("menu_path", menu.MenuPath)
  177. return err
  178. }
  179. // Update 修改SysMenu对象
  180. func (e *SysMenu) Update(c *dto.SysMenuUpdateReq) *SysMenu {
  181. var err error
  182. tx := e.Orm.Debug().Begin()
  183. defer func() {
  184. if err != nil {
  185. tx.Rollback()
  186. } else {
  187. tx.Commit()
  188. }
  189. }()
  190. var menuModel = model.SysMenu{}
  191. err = tx.First(&menuModel, c.GetId()).Error
  192. if err != nil {
  193. e.Log.Errorf("db error: %s", err)
  194. if errors.Is(err, gorm.ErrRecordNotFound) {
  195. err = global.UpdateNotFoundOrNoPermissionErr
  196. } else {
  197. err = global.UpdateFailedErr
  198. }
  199. _ = e.AddError(err)
  200. return e
  201. }
  202. oldPath := menuModel.MenuPath
  203. c.Generate(&menuModel)
  204. err = tx.Model(&menuModel).Save(&menuModel).Error
  205. if err != nil {
  206. e.Log.Errorf("db error: %s", err)
  207. _ = e.AddError(global.UpdateFailedErr)
  208. return e
  209. }
  210. var menuList []model.SysMenu
  211. tx.Where("paths like ?", oldPath+"%").Find(&menuList)
  212. for _, v := range menuList {
  213. v.MenuPath = strings.Replace(v.MenuPath, oldPath, menuModel.MenuPath, 1)
  214. tx.Model(&v).Update("paths", v.MenuPath)
  215. }
  216. return e
  217. }
  218. // Remove 删除SysMenu
  219. func (e *SysMenu) Remove(d *dto.SysMenuDeleteReq) *SysMenu {
  220. var err error
  221. tx := e.Orm.Begin()
  222. defer func() {
  223. if err != nil {
  224. tx.Rollback()
  225. } else {
  226. tx.Commit()
  227. }
  228. }()
  229. var menuList = make([]model.SysMenu, 0)
  230. tx.Where("id in (?)", d.GetId(), d.GetId()).Find(&menuList)
  231. if len(menuList) == 0 {
  232. return e
  233. }
  234. for _, menu := range menuList {
  235. err = e.Orm.Where("menu_path like ?", menu.MenuPath+"%").Delete(&model.SysMenu{}).Error
  236. if err != nil {
  237. e.Log.Errorf("Delete error: %s", err)
  238. _ = e.AddError(global.DeleteFailedErr)
  239. return e
  240. }
  241. }
  242. return e
  243. }
  244. // GetList 获取菜单数据
  245. func (e *SysMenu) GetList(c *dto.SysMenuGetPageReq, list *[]model.SysMenu) error {
  246. var err error
  247. var tempList []dto.SysMenu
  248. err = e.Orm.Table("sys_menu").
  249. Select("sys_menu.id as id,sys_menu.parent_id as parent_id,sys_menu.visible as visible,name").
  250. Joins("left join serv_menu on sys_menu.service_menu_id=serv_menu.id and sys_menu.service_id=serv_menu.service_id").
  251. Where("serv_menu.name like ?", "%"+c.Name+"%").
  252. Scan(&tempList).Error
  253. if err != nil {
  254. e.Log.Errorf("db error: %s", err)
  255. return global.GetFailedErr
  256. }
  257. for _, menu := range tempList {
  258. *list = append(*list, menu.Generate())
  259. }
  260. return nil
  261. }
  262. // SetLabel 修改角色中 设置菜单基础数据
  263. func (e *SysMenu) SetLabel() (m []dto.MenuLabel, err error) {
  264. var list []model.SysMenu
  265. err = e.GetList(&dto.SysMenuGetPageReq{}, &list)
  266. if err != nil {
  267. return
  268. }
  269. m = make([]dto.MenuLabel, 0)
  270. for i := 0; i < len(list); i++ {
  271. if list[i].ParentId != 0 {
  272. continue
  273. }
  274. e := dto.MenuLabel{}
  275. e.Id = list[i].Id
  276. e.Label = list[i].Name
  277. menuInfo := menuLabelCall(&list, e)
  278. m = append(m, menuInfo)
  279. }
  280. return
  281. }
  282. // menuLabelCall 递归构造组织数据
  283. func menuLabelCall(eList *[]model.SysMenu, organ dto.MenuLabel) dto.MenuLabel {
  284. list := *eList
  285. min := make([]dto.MenuLabel, 0)
  286. for j := 0; j < len(list); j++ {
  287. if organ.Id != list[j].ParentId {
  288. continue
  289. }
  290. mi := dto.MenuLabel{}
  291. mi.Id = list[j].Id
  292. mi.Label = list[j].Name
  293. mi.Children = []dto.MenuLabel{}
  294. if list[j].MenuType != "F" {
  295. ms := menuLabelCall(eList, mi)
  296. min = append(min, ms)
  297. } else {
  298. min = append(min, mi)
  299. }
  300. }
  301. if len(min) > 0 {
  302. organ.Children = min
  303. } else {
  304. organ.Children = nil
  305. }
  306. return organ
  307. }
  308. // menuCall 构建菜单树
  309. func menuCall(menuList *[]model.SysMenu, menu model.SysMenu) model.SysMenu {
  310. list := *menuList
  311. min := make([]model.SysMenu, 0)
  312. for j := 0; j < len(list); j++ {
  313. if menu.Id != list[j].ParentId {
  314. continue
  315. }
  316. mi := model.SysMenu{}
  317. mi.Id = list[j].Id
  318. mi.Name = list[j].Name
  319. mi.Icon = list[j].Icon
  320. mi.Path = list[j].Path
  321. mi.MenuType = list[j].MenuType
  322. mi.Permission = list[j].Permission
  323. mi.ParentId = list[j].ParentId
  324. mi.Component = list[j].Component
  325. mi.Sort = list[j].Sort
  326. mi.Visible = list[j].Visible
  327. mi.CreatedAt = list[j].CreatedAt
  328. mi.Children = []model.SysMenu{}
  329. ms := menuCall(menuList, mi)
  330. min = append(min, ms)
  331. }
  332. menu.Children = min
  333. return menu
  334. }
  335. // 去掉重复菜单
  336. func menuDistinct(menuList []model.SysMenu) (result []model.SysMenu) {
  337. distinctMap := make(map[int]struct{}, len(menuList))
  338. for _, menu := range menuList {
  339. if _, ok := distinctMap[menu.Id]; !ok {
  340. distinctMap[menu.Id] = struct{}{}
  341. result = append(result, menu)
  342. }
  343. }
  344. return result
  345. }
  346. func recursiveSetMenu(orm *gorm.DB, mIds []int, menus *[]model.SysMenu) error {
  347. if len(mIds) == 0 || menus == nil {
  348. return nil
  349. }
  350. var subMenus []model.SysMenu
  351. err := orm.Where("id in ?", mIds).Find(&subMenus).Error
  352. if err != nil {
  353. return err
  354. }
  355. subIds := make([]int, 0)
  356. for _, menu := range subMenus {
  357. if menu.ParentId != 0 {
  358. subIds = append(subIds, menu.ParentId)
  359. }
  360. //if menu.MenuType != cModel.Button {
  361. // *menus = append(*menus, menu)
  362. //}
  363. *menus = append(*menus, menu)
  364. }
  365. return recursiveSetMenu(orm, subIds, menus)
  366. }
  367. // SetMenuRole 获取左侧菜单树使用
  368. func (e *SysMenu) SetMenuRole(roleName string) (m []model.SysMenu, err error) {
  369. // 从缓存获取角色关联的菜单
  370. if err := model.GetRoleMenuCache(roleName, &m); err == nil {
  371. return m, nil
  372. }
  373. menus, err := e.getByRoleName(roleName)
  374. if err != nil {
  375. return m, global.GetFailedErr
  376. }
  377. menuIds := make([]int, 0)
  378. for _, menu := range menus {
  379. menuIds = append(menuIds, menu.Id)
  380. }
  381. var tempList []dto.SysMenu
  382. var menuList []model.SysMenu
  383. err = e.Orm.Table("sys_menu").
  384. Select("*,sys_menu.id as id,sys_menu.parent_id as parent_id,sys_menu.visible as visible").
  385. Joins("left join serv_menu on sys_menu.service_menu_id=serv_menu.id and sys_menu.service_id=serv_menu.service_id").
  386. Where("sys_menu.id in (?) and sys_menu.visible = 1", menuIds).
  387. Order("sys_menu.sort").
  388. Scan(&tempList).Error
  389. for _, menu := range tempList {
  390. menuList = append(menuList, menu.Generate())
  391. }
  392. sort.Sort(model.SysMenuSlice(menuList))
  393. m = make([]model.SysMenu, 0)
  394. for i := 0; i < len(menuList); i++ {
  395. if menuList[i].ParentId != 0 {
  396. continue
  397. }
  398. menusInfo := menuCall(&menuList, menuList[i])
  399. m = append(m, menusInfo)
  400. }
  401. // 保存角色菜单到缓存
  402. _ = model.SetRoleMenuCache(roleName, m)
  403. return
  404. }
  405. // 通过roleName获取菜单列表
  406. func (e *SysMenu) getByRoleName(roleName string) ([]model.SysMenu, error) {
  407. var err error
  408. data := make([]model.SysMenu, 0)
  409. if roleName == "admin" {
  410. err = e.Orm.Find(&data).Error
  411. } else {
  412. roleMenuIds := make([]int, 0)
  413. err = e.Orm.Model(&model.SysRoleMenu{}).Select("menu_id").Where("role_key = ? ", roleName).Scan(&roleMenuIds).Error
  414. if len(roleMenuIds) > 0 {
  415. if err = recursiveSetMenu(e.Orm, roleMenuIds, &data); err != nil {
  416. return nil, err
  417. }
  418. // 菜单id及父id 去重
  419. data = menuDistinct(data)
  420. }
  421. }
  422. return data, err
  423. }