sys_menu.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. package service
  2. import (
  3. "cold-delivery/common/actions"
  4. dto2 "cold-delivery/common/dto"
  5. "cold-delivery/common/global"
  6. cModel "cold-delivery/common/model"
  7. "encoding/json"
  8. "fmt"
  9. "gogs.baozhida.cn/zoie/OAuth-core/service"
  10. "strings"
  11. "github.com/pkg/errors"
  12. "gorm.io/gorm"
  13. "cold-delivery/app/admin/model"
  14. "cold-delivery/app/admin/service/dto"
  15. "gogs.baozhida.cn/zoie/OAuth-core/pkg"
  16. )
  17. type SysMenu struct {
  18. service.Service
  19. }
  20. // GetPage 获取SysMenu列表
  21. func (e *SysMenu) GetPage(c *dto.SysMenuGetPageReq, menus *[]model.SysMenu) *SysMenu {
  22. var menu = make([]model.SysMenu, 0)
  23. err := e.getPage(c, &menu).Error
  24. if err != nil {
  25. _ = e.AddError(global.GetFailedErr)
  26. return e
  27. }
  28. for i := 0; i < len(menu); i++ {
  29. if menu[i].ParentId != 0 {
  30. continue
  31. }
  32. menusInfo := SysMenuCall(&menu, menu[i])
  33. *menus = append(*menus, menusInfo)
  34. }
  35. if len(*menus) == 0 {
  36. parentMap, flag := getSysMenuParent(&menu)
  37. if flag {
  38. for i := 0; i < len(menu); i++ {
  39. if parentMap[menu[i].ParentId] {
  40. continue
  41. }
  42. menusInfo := SysMenuCall(&menu, menu[i])
  43. *menus = append(*menus, menusInfo)
  44. }
  45. } else {
  46. for i := 0; i < len(menu); i++ {
  47. menusInfo := SysMenuCall(&menu, menu[i])
  48. *menus = append(*menus, menusInfo)
  49. }
  50. }
  51. }
  52. return e
  53. }
  54. // 获取搜索出来的菜单的父菜单
  55. func getSysMenuParent(menuList *[]model.SysMenu) (map[int]bool, bool) {
  56. list := *menuList
  57. var flag = false
  58. var parentMap = map[int]bool{}
  59. for j := 0; j < len(list); j++ {
  60. parentMap[list[j].ParentId] = false
  61. }
  62. for j := 0; j < len(list); j++ {
  63. if _, ok := parentMap[list[j].Id]; !ok {
  64. continue
  65. }
  66. parentMap[list[j].Id] = true
  67. flag = true
  68. }
  69. return parentMap, flag
  70. }
  71. // getPage 菜单分页列表
  72. func (e *SysMenu) getPage(c *dto.SysMenuGetPageReq, list *[]model.SysMenu) *SysMenu {
  73. var err error
  74. var data model.SysMenu
  75. var tempList []model.SysMenu
  76. err = e.Orm.Model(&data).
  77. Scopes(dto2.MakeCondition(c.GetNeedSearch())).
  78. Order("id").
  79. Find(&tempList).Error
  80. if err != nil {
  81. e.Log.Errorf("getSysMenuPage error: %s", err)
  82. _ = e.AddError(err)
  83. return e
  84. }
  85. // 获取菜单及其子菜单下ID
  86. for _, menu := range tempList {
  87. var menuList = make([]model.SysMenu, 0)
  88. err = e.Orm.Where("menu_path like ?", menu.MenuPath+"%").Order(fmt.Sprintf("sort %s", c.SortOrder)).Order("id").Find(&menuList).Error
  89. *list = append(*list, menuList...)
  90. }
  91. *list = DeduplicateSysMenu(*list)
  92. return e
  93. }
  94. // Get 获取SysMenu对象
  95. func (e *SysMenu) Get(d *dto.SysMenuGetReq, menuModel *model.SysMenu) *SysMenu {
  96. err := e.Orm.First(menuModel, d.GetId()).Error
  97. if err != nil {
  98. e.Log.Errorf("db error: %s", err)
  99. if errors.Is(err, gorm.ErrRecordNotFound) {
  100. err = global.GetNotFoundOrNoPermissionErr
  101. } else {
  102. err = global.GetFailedErr
  103. }
  104. _ = e.AddError(err)
  105. return e
  106. }
  107. return e
  108. }
  109. // Insert 创建SysMenu对象
  110. func (e *SysMenu) Insert(c *dto.SysMenuInsertReq) *SysMenu {
  111. var err error
  112. var data model.SysMenu
  113. tx := e.Orm.Begin()
  114. defer func() {
  115. if err != nil {
  116. tx.Rollback()
  117. } else {
  118. tx.Commit()
  119. }
  120. }()
  121. c.Generate(&data)
  122. err = tx.Create(&data).Error
  123. if err != nil {
  124. e.Log.Errorf("db error: %s", err)
  125. _ = e.AddError(global.CreateFailedErr)
  126. return e
  127. }
  128. c.Id = data.Id
  129. menuPath, err := e.initPaths(&data)
  130. if err != nil {
  131. e.Log.Errorf("db error: %s", err)
  132. _ = e.AddError(err)
  133. return e
  134. }
  135. err = tx.Model(&data).Where("id = ?", data.Id).Update("menu_path", menuPath).Error
  136. if err != nil {
  137. e.Log.Errorf("db error: %s", err)
  138. _ = e.AddError(global.CreateFailedErr)
  139. return e
  140. }
  141. // 添加菜单后删除角色菜单缓存,防止系统菜单与服务菜单不同步
  142. err = model.DeleteAllRoleMenuCache()
  143. if err != nil {
  144. e.Log.Errorf("删除角色菜单缓存失败 %s", err)
  145. _ = e.AddError(err)
  146. return e
  147. }
  148. return e
  149. }
  150. func (e *SysMenu) initPaths(menu *model.SysMenu) (menuPath string, err error) {
  151. var data model.SysMenu
  152. parentMenu := new(model.SysMenu)
  153. if menu.ParentId != 0 {
  154. e.Orm.Model(&data).First(parentMenu, menu.ParentId)
  155. if parentMenu.MenuPath == "" {
  156. err = errors.New("父级menu_path异常,请尝试对当前节点父级菜单进行更新操作!")
  157. return menuPath, err
  158. }
  159. menuPath = parentMenu.MenuPath + "/" + pkg.IntToString(menu.Id)
  160. } else {
  161. menuPath = "/0/" + pkg.IntToString(menu.Id)
  162. }
  163. return menuPath, nil
  164. }
  165. // Update 修改SysMenu对象
  166. func (e *SysMenu) Update(c *dto.SysMenuUpdateReq) *SysMenu {
  167. var err error
  168. tx := e.Orm.Debug().Begin()
  169. defer func() {
  170. if err != nil {
  171. tx.Rollback()
  172. } else {
  173. tx.Commit()
  174. }
  175. }()
  176. var menuModel = model.SysMenu{}
  177. err = tx.First(&menuModel, c.GetId()).Error
  178. if err != nil {
  179. e.Log.Errorf("db error: %s", err)
  180. if errors.Is(err, gorm.ErrRecordNotFound) {
  181. err = global.UpdateNotFoundOrNoPermissionErr
  182. } else {
  183. err = global.UpdateFailedErr
  184. }
  185. _ = e.AddError(err)
  186. return e
  187. }
  188. oldPath := menuModel.MenuPath
  189. oldParentId := menuModel.ParentId
  190. c.Generate(&menuModel)
  191. // 替换旧的path
  192. if c.ParentId != oldParentId {
  193. menuPath, err := e.initPaths(&menuModel)
  194. if err != nil {
  195. e.Log.Errorf("db error: %s", err)
  196. _ = e.AddError(err)
  197. return e
  198. }
  199. menuModel.MenuPath = menuPath
  200. }
  201. // 更新菜单信息
  202. err = tx.Model(&menuModel).Save(&menuModel).Error
  203. if err != nil {
  204. e.Log.Errorf("db error: %s", err)
  205. _ = e.AddError(global.UpdateFailedErr)
  206. return e
  207. }
  208. // 替换旧的path
  209. if oldPath != menuModel.MenuPath {
  210. var menuList []model.SysMenu
  211. tx.Where("menu_path like ?", oldPath+"%").Find(&menuList)
  212. for _, v := range menuList {
  213. v.MenuPath = strings.Replace(v.MenuPath, oldPath, menuModel.MenuPath, 1)
  214. err := tx.Model(&v).Update("menu_path", v.MenuPath).Error
  215. if err != nil {
  216. e.Log.Errorf("db error: %s", err)
  217. _ = e.AddError(global.CreateFailedErr)
  218. return e
  219. }
  220. }
  221. }
  222. // 修改服务菜单后删除角色菜单缓存,防止系统菜单与服务菜单不同步
  223. err = model.DeleteAllRoleMenuCache()
  224. if err != nil {
  225. _ = e.AddError(err)
  226. return e
  227. }
  228. return e
  229. }
  230. // Remove 删除SysMenu
  231. func (e *SysMenu) Remove(d *dto.SysMenuDeleteReq) *SysMenu {
  232. var err error
  233. tx := e.Orm.Begin()
  234. defer func() {
  235. if err != nil {
  236. tx.Rollback()
  237. } else {
  238. tx.Commit()
  239. }
  240. }()
  241. var menuModel model.SysMenu
  242. err = tx.First(&menuModel, d.GetId()).Error
  243. if err != nil {
  244. e.Log.Errorf("db error: %s", err)
  245. if errors.Is(err, gorm.ErrRecordNotFound) {
  246. err = global.DeleteNotFoundOrNoPermissionErr
  247. } else {
  248. err = global.DeleteFailedErr
  249. }
  250. _ = e.AddError(err)
  251. return e
  252. }
  253. err = e.Orm.Where("menu_path like ?", menuModel.MenuPath+"%").Delete(&model.SysMenu{}).Error
  254. if err != nil {
  255. e.Log.Errorf("Delete error: %s", err)
  256. _ = e.AddError(global.DeleteFailedErr)
  257. return e
  258. }
  259. // 删除服务菜单后删除角色菜单缓存,防止系统菜单与服务菜单不同步
  260. err = model.DeleteAllRoleMenuCache()
  261. if err != nil {
  262. e.Log.Errorf("删除角色菜单缓存失败 %s", err)
  263. _ = e.AddError(err)
  264. return e
  265. }
  266. return e
  267. }
  268. // GetList 获取菜单数据
  269. func (e *SysMenu) GetList(c *dto.SysMenuGetPageReq, list *[]model.SysMenu) error {
  270. var err error
  271. var data model.SysMenu
  272. err = e.Orm.Model(&data).
  273. Scopes(
  274. dto2.MakeCondition(c.GetNeedSearch()),
  275. ).
  276. Find(list).Error
  277. if err != nil {
  278. e.Log.Errorf("db error: %s", err)
  279. return global.GetFailedErr
  280. }
  281. return nil
  282. }
  283. // SysMenuCall 构建菜单树
  284. func SysMenuCall(menuList *[]model.SysMenu, menu model.SysMenu) model.SysMenu {
  285. list := *menuList
  286. min := make([]model.SysMenu, 0)
  287. for j := 0; j < len(list); j++ {
  288. if menu.Id != list[j].ParentId {
  289. continue
  290. }
  291. mi := model.SysMenu{}
  292. mi.Id = list[j].Id
  293. mi.Title = list[j].Title
  294. mi.Icon = list[j].Icon
  295. mi.Path = list[j].Path
  296. mi.MenuType = list[j].MenuType
  297. mi.Name = list[j].Name
  298. mi.ParentId = list[j].ParentId
  299. mi.Component = list[j].Component
  300. mi.Sort = list[j].Sort
  301. mi.Visible = list[j].Visible
  302. mi.Redirect = list[j].Redirect
  303. mi.CreatedAt = list[j].CreatedAt
  304. mi.Children = []model.SysMenu{}
  305. if mi.MenuType != cModel.Button {
  306. ms := SysMenuCall(menuList, mi)
  307. min = append(min, ms)
  308. } else {
  309. min = append(min, mi)
  310. }
  311. }
  312. menu.Children = min
  313. return menu
  314. }
  315. // DeduplicateSysMenu 菜单列表去重
  316. func DeduplicateSysMenu(list []model.SysMenu) []model.SysMenu {
  317. seen := make(map[string]bool)
  318. deduplicated := []model.SysMenu{}
  319. for _, v := range list {
  320. // 将结构体编码为 JSON 字符串
  321. key, err := json.Marshal(v)
  322. if err != nil {
  323. // 处理错误
  324. continue
  325. }
  326. // 将 JSON 字符串作为键插入到 map 中
  327. if _, ok := seen[string(key)]; !ok {
  328. seen[string(key)] = true
  329. deduplicated = append(deduplicated, v)
  330. }
  331. }
  332. return deduplicated
  333. }
  334. // menuLabelCall 递归构造组织数据
  335. func menuLabelCall(eList *[]model.SysMenu, organ dto.MenuLabel) dto.MenuLabel {
  336. list := *eList
  337. min := make([]dto.MenuLabel, 0)
  338. for j := 0; j < len(list); j++ {
  339. if organ.Id != list[j].ParentId {
  340. continue
  341. }
  342. mi := dto.MenuLabel{}
  343. mi.Id = list[j].Id
  344. mi.Label = list[j].Title
  345. mi.Children = []dto.MenuLabel{}
  346. if list[j].MenuType != "F" {
  347. ms := menuLabelCall(eList, mi)
  348. min = append(min, ms)
  349. } else {
  350. min = append(min, mi)
  351. }
  352. }
  353. if len(min) > 0 {
  354. organ.Children = min
  355. } else {
  356. organ.Children = nil
  357. }
  358. return organ
  359. }
  360. // SetLabel 修改角色中 设置菜单基础数据
  361. func (e *SysMenu) SetLabel() (m []dto.MenuLabel, err error) {
  362. var list []model.SysMenu
  363. err = e.GetList(&dto.SysMenuGetPageReq{}, &list)
  364. if err != nil {
  365. return
  366. }
  367. m = make([]dto.MenuLabel, 0)
  368. for i := 0; i < len(list); i++ {
  369. if list[i].ParentId != 0 {
  370. continue
  371. }
  372. e := dto.MenuLabel{}
  373. e.Id = list[i].Id
  374. e.Label = list[i].Title
  375. menuInfo := menuLabelCall(&list, e)
  376. m = append(m, menuInfo)
  377. }
  378. return
  379. }
  380. // menuCall 构建菜单树
  381. func menuCall(menuList *[]model.SysMenu, menu model.SysMenu) model.SysMenu {
  382. list := *menuList
  383. min := make([]model.SysMenu, 0)
  384. for j := 0; j < len(list); j++ {
  385. if menu.Id != list[j].ParentId {
  386. continue
  387. }
  388. mi := model.SysMenu{}
  389. mi.Id = list[j].Id
  390. mi.Title = list[j].Title
  391. mi.Icon = list[j].Icon
  392. mi.Path = list[j].Path
  393. mi.MenuType = list[j].MenuType
  394. mi.Name = list[j].Name
  395. mi.ParentId = list[j].ParentId
  396. mi.Component = list[j].Component
  397. mi.Sort = list[j].Sort
  398. mi.Visible = list[j].Visible
  399. mi.CreatedAt = list[j].CreatedAt
  400. mi.Children = []model.SysMenu{}
  401. ms := menuCall(menuList, mi)
  402. min = append(min, ms)
  403. }
  404. menu.Children = min
  405. return menu
  406. }
  407. // 通过roleName获取菜单列表
  408. func (e *SysMenu) getByRoleName(roleName string) ([]model.SysMenu, error) {
  409. var err error
  410. data := make([]model.SysMenu, 0)
  411. if roleName == "admin" {
  412. err = e.Orm.Find(&data).Error
  413. } else {
  414. roleMenuIds := make([]int, 0)
  415. err = e.Orm.Model(&model.SysRoleMenu{}).Select("menu_id").Where("role_key = ? ", roleName).Scan(&roleMenuIds).Error
  416. if len(roleMenuIds) > 0 {
  417. if err = recursiveSetMenu(e.Orm, roleMenuIds, &data); err != nil {
  418. return nil, err
  419. }
  420. // 菜单id及父id 去重
  421. data = menuDistinct(data)
  422. }
  423. }
  424. return data, err
  425. }
  426. func recursiveSetMenu(orm *gorm.DB, mIds []int, menus *[]model.SysMenu) error {
  427. if len(mIds) == 0 || menus == nil {
  428. return nil
  429. }
  430. var subMenus []model.SysMenu
  431. err := orm.Where("id in ?", mIds).Find(&subMenus).Error
  432. if err != nil {
  433. return err
  434. }
  435. subIds := make([]int, 0)
  436. for _, menu := range subMenus {
  437. if menu.ParentId != 0 {
  438. subIds = append(subIds, menu.ParentId)
  439. }
  440. //if menu.MenuType != cModel.Button {
  441. // *menus = append(*menus, menu)
  442. //}
  443. *menus = append(*menus, menu)
  444. }
  445. return recursiveSetMenu(orm, subIds, menus)
  446. }
  447. // 去掉重复菜单
  448. func menuDistinct(menuList []model.SysMenu) (result []model.SysMenu) {
  449. distinctMap := make(map[int]struct{}, len(menuList))
  450. for _, menu := range menuList {
  451. if _, ok := distinctMap[menu.Id]; !ok {
  452. distinctMap[menu.Id] = struct{}{}
  453. result = append(result, menu)
  454. }
  455. }
  456. return result
  457. }
  458. // SetMenuRole 获取左侧菜单树使用
  459. func (e *SysMenu) SetMenuRole(roleKey string, userId int, p *actions.DataPermission) (m []model.SysMenu, err error) {
  460. // 从缓存获取角色关联的菜单
  461. var cacheKey string
  462. if p.DeptId > 0 {
  463. //cacheKey = fmt.Sprintf("%s-1-%d", roleKey, userId)
  464. cacheKey = fmt.Sprintf("%s-1", roleKey)
  465. } else {
  466. //cacheKey = fmt.Sprintf("%s-0-%d", roleKey, userId)
  467. cacheKey = fmt.Sprintf("%s-0", roleKey)
  468. }
  469. if err := model.GetRoleMenuCache(cacheKey, &m); err == nil {
  470. return m, nil
  471. }
  472. menus, err := e.getByRoleName(roleKey)
  473. if err != nil {
  474. return m, global.GetFailedErr
  475. }
  476. m = make([]model.SysMenu, 0)
  477. var menuList []model.SysMenu
  478. if p.DeptId == 0 {
  479. if roleKey == "admin" {
  480. err = e.Orm.Table("sys_menu").
  481. Where("sys_menu.visible = 1 and sys_menu.deleted_at is null and is_dept = 0").
  482. Order("sys_menu.sort").
  483. Order("id").
  484. Scan(&menuList).Error
  485. if err != nil {
  486. return m, global.GetFailedErr
  487. }
  488. } else {
  489. menuIds := make([]int, 0)
  490. for _, menu := range menus {
  491. menuIds = append(menuIds, menu.Id)
  492. }
  493. err = e.Orm.Table("sys_menu").
  494. Where("sys_menu.id in (?) and sys_menu.visible = 1 and sys_menu.deleted_at is null and is_dept = 0", menuIds).
  495. Order("sys_menu.sort").
  496. Order("id").
  497. Scan(&menuList).Error
  498. if err != nil {
  499. return m, global.GetFailedErr
  500. }
  501. }
  502. } else {
  503. if roleKey == "admin" {
  504. err = e.Orm.Table("sys_menu").
  505. Where("sys_menu.visible = 1 and sys_menu.deleted_at is null").
  506. Order("sys_menu.sort").
  507. Order("id").
  508. Scan(&menuList).Error
  509. if err != nil {
  510. return m, global.GetFailedErr
  511. }
  512. } else {
  513. menuIds := make([]int, 0)
  514. for _, menu := range menus {
  515. menuIds = append(menuIds, menu.Id)
  516. }
  517. err = e.Orm.Table("sys_menu").
  518. Where("sys_menu.id in (?) and sys_menu.visible = 1 and sys_menu.deleted_at is null", menuIds).
  519. Order("sys_menu.sort").
  520. Order("id").
  521. Scan(&menuList).Error
  522. if err != nil {
  523. return m, global.GetFailedErr
  524. }
  525. }
  526. }
  527. //sort.Sort(model.SysMenuSlice(menuList))
  528. for i := 0; i < len(menuList); i++ {
  529. if menuList[i].ParentId != 0 {
  530. continue
  531. }
  532. menusInfo := menuCall(&menuList, menuList[i])
  533. m = append(m, menusInfo)
  534. }
  535. // 保存角色菜单到缓存
  536. _ = model.SetRoleMenuCache(cacheKey, m)
  537. return
  538. }
  539. func (e *SysMenu) MenuSelect(roleKey string, userId int, p *actions.DataPermission) (m []model.SysMenu, err error) {
  540. menus, err := e.getByRoleName(roleKey)
  541. if err != nil {
  542. return m, global.GetFailedErr
  543. }
  544. m = make([]model.SysMenu, 0)
  545. var menuList []model.SysMenu
  546. if p.DeptId == 0 {
  547. if roleKey == "admin" {
  548. err = e.Orm.Table("sys_menu").
  549. Where("sys_menu.visible = 1 and sys_menu.deleted_at is null").
  550. Order("sys_menu.sort").
  551. Order("id").
  552. Scan(&menuList).Error
  553. if err != nil {
  554. return m, global.GetFailedErr
  555. }
  556. } else {
  557. menuIds := make([]int, 0)
  558. for _, menu := range menus {
  559. menuIds = append(menuIds, menu.Id)
  560. }
  561. err = e.Orm.Table("sys_menu").
  562. Where("sys_menu.id in (?) and sys_menu.visible = 1 and sys_menu.deleted_at is null", menuIds).
  563. Order("sys_menu.sort").
  564. Order("id").
  565. Scan(&menuList).Error
  566. if err != nil {
  567. return m, global.GetFailedErr
  568. }
  569. }
  570. } else {
  571. if roleKey == "admin" {
  572. err = e.Orm.Table("sys_menu").
  573. Where("sys_menu.visible = 1 and sys_menu.deleted_at is null").
  574. Order("sys_menu.sort").
  575. Order("id").
  576. Scan(&menuList).Error
  577. if err != nil {
  578. return m, global.GetFailedErr
  579. }
  580. } else {
  581. menuIds := make([]int, 0)
  582. for _, menu := range menus {
  583. menuIds = append(menuIds, menu.Id)
  584. }
  585. err = e.Orm.Table("sys_menu").
  586. Where("sys_menu.id in (?) and sys_menu.visible = 1 and sys_menu.deleted_at is null", menuIds).
  587. Order("sys_menu.sort").
  588. Order("id").
  589. Scan(&menuList).Error
  590. if err != nil {
  591. return m, global.GetFailedErr
  592. }
  593. }
  594. }
  595. //sort.Sort(model.SysMenuSlice(menuList))
  596. for i := 0; i < len(menuList); i++ {
  597. if menuList[i].ParentId != 0 {
  598. continue
  599. }
  600. menusInfo := menuCall(&menuList, menuList[i])
  601. m = append(m, menusInfo)
  602. }
  603. return
  604. }