workDesktop.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. package entity
  2. import (
  3. MC "app.yhyue.com/moapp/jybase/common"
  4. "app.yhyue.com/moapp/jybase/encrypt"
  5. "bp.jydev.jianyu360.cn/BaseService/userCenter/rpc/pb"
  6. "database/sql"
  7. "encoding/json"
  8. "errors"
  9. "github.com/zeromicro/go-zero/core/logx"
  10. "sort"
  11. "strconv"
  12. "strings"
  13. )
  14. // WorkDesktopMenu 工作桌面菜单信息
  15. type WorkDesktopMenu struct {
  16. MenuTree []*JYMenu //菜单
  17. UserId string //用户id
  18. NewUserId string //base_userid
  19. EntId int64 //企业id
  20. EntUserId int64 //企业用户id
  21. AppId string //appid 剑鱼:10000
  22. IntranetBool bool //是否开启内网访问模式
  23. Platform string //平台来源
  24. }
  25. // JYMenu 工作桌面菜单内容
  26. type JYMenu struct {
  27. Id int
  28. Name string //菜单名称
  29. Match string //滤镜过滤正则
  30. OrderId int //菜单排序id
  31. ParentId int //父级id
  32. PowerIds string //权限id
  33. CheckCode int //是否必须验证权限才显示菜单
  34. Url string //菜单跳转链接
  35. Icon string //菜单图标
  36. AdditionalInfo Additional //附加弹窗信息
  37. AppType string //菜单模式
  38. OpenType string //打开方式
  39. Status int //是否是可用服务
  40. PermissionCode string //功能代码
  41. CapitalCode string //留资代码
  42. CapitalInfo Additional //留资弹窗
  43. Children []*JYMenu //菜单s
  44. }
  45. type Additional struct {
  46. Title string `json:"title"` //弹窗标题
  47. Content string `json:"content"` //弹窗提示信息
  48. ConfirmUrl string `json:"confirmUrl"` //确认按钮跳转地址
  49. ConfirmText string `json:"confirmText"` //确认按钮
  50. IsShowCancel bool `json:"isShowCancel,optional"` //是否显示取消按钮
  51. AppType string `json:"appType,optional,omitempty"` //跳转方式
  52. OpenType string `json:"openType,optional,omitempty"`
  53. }
  54. // 获取有效菜单数据
  55. func (m *WorkDesktopMenu) GetMenuTreeData() error {
  56. //tidb数据
  57. query := `SELECT * FROM ` + WorkMenu + ` WHERE appid=? AND status=0 ORDER BY id ASC`
  58. //是否开启内网访问数据权限---对应 api 配置文件
  59. if m.IntranetBool {
  60. query = `SELECT * FROM ` + WorkMenu + ` WHERE appid=? AND status>=0 ORDER BY id ASC`
  61. }
  62. menuData := BaseMysql.SelectBySql(query, m.AppId)
  63. if menuData == nil || len(*menuData) == 0 {
  64. return errors.New("查询数据异常")
  65. }
  66. for _, v := range *menuData {
  67. menu := &JYMenu{
  68. Id: MC.IntAll(v["id"]),
  69. Name: MC.ObjToString(v["name"]),
  70. Match: MC.ObjToString(v["match"]),
  71. OrderId: MC.IntAll(v["orderid"]),
  72. ParentId: MC.IntAll(v["parentid"]),
  73. PowerIds: MC.ObjToString(v["powerids"]),
  74. CheckCode: MC.IntAll(v["checkcode"]),
  75. Icon: MC.ObjToString(v["icon"]),
  76. AppType: MC.ObjToString(v["apptype"]),
  77. OpenType: MC.ObjToString(v["opentype"]),
  78. Status: MC.IntAll(v["status"]),
  79. PermissionCode: MC.ObjToString(v["permissioncode"]),
  80. CapitalCode: MC.ObjToString(v["capitalcode"]),
  81. }
  82. switch m.Platform {
  83. case "WX":
  84. menu.Url = MC.ObjToString(v["wxurl"])
  85. case "APP":
  86. menu.Url = MC.ObjToString(v["appurl"])
  87. default:
  88. menu.Url = MC.ObjToString(v["pcurl"])
  89. }
  90. if additionalInfo := MC.ObjToString(v["additionalinfo"]); additionalInfo != "" {
  91. additional := Additional{}
  92. if json.Unmarshal([]byte(additionalInfo), &additional) == nil {
  93. menu.AdditionalInfo = additional
  94. }
  95. }
  96. if capitalinfo := MC.ObjToString(v["capitalinfo"]); capitalinfo != "" {
  97. additional := Additional{}
  98. if json.Unmarshal([]byte(capitalinfo), &additional) == nil {
  99. menu.CapitalInfo = additional
  100. }
  101. }
  102. if menu.Id > 0 {
  103. m.MenuTree = append(m.MenuTree, menu)
  104. }
  105. }
  106. return nil
  107. }
  108. // WorkMenuTree 菜单-格式化-tree
  109. func (m *WorkDesktopMenu) WorkMenuTree(parentId int) (jyMenu []*JYMenu) {
  110. jyMenu = make([]*JYMenu, 0)
  111. for _, mv := range m.MenuTree {
  112. if mv.ParentId == parentId {
  113. mv.Children = m.WorkMenuTree(mv.Id)
  114. sort.SliceStable(mv.Children, func(i, j int) bool {
  115. return mv.Children[i].OrderId < mv.Children[j].OrderId
  116. })
  117. jyMenu = append(jyMenu, mv)
  118. }
  119. }
  120. sort.SliceStable(jyMenu, func(i, j int) bool {
  121. return jyMenu[i].OrderId < jyMenu[j].OrderId
  122. })
  123. return
  124. }
  125. // WorkMenuFormat 菜单 格式化
  126. func (m *WorkDesktopMenu) WorkMenuFormat() ([]*pb.MenuList, error) {
  127. //logx.Info("树的长度:", len(m.MenuTree))
  128. menuList := make([]*pb.MenuList, 0)
  129. for _, mv := range m.MenuTree {
  130. //if mv.Id < 466 {
  131. // continue
  132. //}
  133. //0:默认展示;1:需验证权限,有权限展示;2:需验证权限,无权限也可展示(可用服务无权限不展示)
  134. usable := m.VerifyPermissions(mv.PowerIds)
  135. //checkCode==1 验证权限结果 无权限不显示
  136. if !usable && mv.CheckCode == 1 {
  137. continue
  138. }
  139. //GetResources(m.AppId, m.NewUserId, m.EntId, m.EntUserId)
  140. oneLevel := &pb.MenuList{
  141. Name: mv.Name,
  142. Icon: mv.Icon,
  143. Url: mv.Url,
  144. Id: encrypt.SE.EncodeString(strconv.Itoa(mv.Id)), //功能id加密
  145. Usable: usable, //MC.If(mv.PowerIds != "", usable && mv.CheckCode == 1, true).(bool),
  146. AppType: mv.AppType,
  147. OpenType: mv.OpenType,
  148. Child: []*pb.SecondLevelMenu{},
  149. TipInfo: &pb.TipInfo{
  150. Title: mv.AdditionalInfo.Title,
  151. Content: mv.AdditionalInfo.Content,
  152. ConfirmUrl: mv.AdditionalInfo.ConfirmUrl,
  153. ConfirmText: mv.AdditionalInfo.ConfirmText,
  154. IsShowCancel: mv.AdditionalInfo.IsShowCancel,
  155. AppType: mv.AdditionalInfo.AppType,
  156. OpenType: mv.AdditionalInfo.OpenType,
  157. },
  158. Match: MC.If(mv.Match != "", strings.Split(mv.Match, ","), []string{}).([]string),
  159. }
  160. if len(mv.Children) > 0 {
  161. for _, sv := range mv.Children {
  162. //0:默认展示;1:需验证权限,有权限展示;2:需验证权限,无权限也可展示(可用服务无权限不展示)
  163. usable := m.VerifyPermissions(sv.PowerIds)
  164. //checkCode==1 验证权限结果 无权限不显示
  165. if !usable && sv.CheckCode == 1 {
  166. continue
  167. }
  168. secondLevel := &pb.SecondLevelMenu{
  169. Name: sv.Name,
  170. Icon: sv.Icon,
  171. Url: sv.Url,
  172. Id: encrypt.SE.EncodeString(strconv.Itoa(sv.Id)), //功能id加密
  173. Usable: usable, //MC.If(sv.PowerIds != "", usable && sv.CheckCode == 1, true).(bool),
  174. Child: []*pb.ThreeLevelMenu{},
  175. AppType: sv.AppType,
  176. OpenType: sv.OpenType,
  177. TipInfo: &pb.TipInfo{
  178. Title: sv.AdditionalInfo.Title,
  179. Content: sv.AdditionalInfo.Content,
  180. ConfirmUrl: sv.AdditionalInfo.ConfirmUrl,
  181. ConfirmText: sv.AdditionalInfo.ConfirmText,
  182. IsShowCancel: sv.AdditionalInfo.IsShowCancel,
  183. AppType: sv.AdditionalInfo.AppType,
  184. OpenType: sv.AdditionalInfo.OpenType,
  185. },
  186. Match: MC.If(sv.Match != "", strings.Split(sv.Match, ","), []string{}).([]string),
  187. }
  188. if len(sv.Children) > 0 {
  189. for _, tv := range sv.Children {
  190. //附件下载包、采购单位画像记录、企业画像记录 如果是大会员+超级订阅 排除此三项菜单
  191. //灵活性降低,不应该这么搞
  192. if (tv.Name == "附件下载包" && m.VerifyPermissions("3")) || (tv.Name == "采购单位画像记录" && m.VerifyPermissions("5")) || (tv.Name == "企业画像记录" && m.VerifyPermissions("4,12,13,19,20,21,23")) {
  193. continue
  194. }
  195. //0:默认展示;1:需验证权限,有权限展示;2:需验证权限,无权限也可展示(可用服务无权限不展示)
  196. usable := m.VerifyPermissions(tv.PowerIds)
  197. //checkCode==1 验证权限结果 无权限不显示
  198. if !usable && tv.CheckCode == 1 {
  199. continue
  200. }
  201. var (
  202. //数据库默认提示弹窗信息
  203. title, content, confirmUrl, confirmText, isShowCancel, appType, openType, feasibility = tv.AdditionalInfo.Title, tv.AdditionalInfo.Content, tv.AdditionalInfo.ConfirmUrl, tv.AdditionalInfo.ConfirmText, tv.AdditionalInfo.IsShowCancel, tv.AdditionalInfo.AppType, tv.AdditionalInfo.OpenType, usable
  204. )
  205. //三级菜单------
  206. if len(tv.Children) == 0 && (tv.CapitalCode != "" || tv.PermissionCode != "") {
  207. //用户是否需要留资
  208. //资源中台获取用户权限--没有权限:title等置空
  209. //ResourceLib.PowerHandle()
  210. title, content, confirmUrl, confirmText, appType, openType, isShowCancel, feasibility = CheckCapitalResources(tv, m, usable, m.VerifyPermissions(tv.PermissionCode))
  211. }
  212. threeLevel := &pb.ThreeLevelMenu{
  213. Name: tv.Name,
  214. Icon: tv.Icon,
  215. Url: tv.Url,
  216. Id: encrypt.SE.EncodeString(strconv.Itoa(tv.Id)), //功能id加密
  217. Usable: feasibility, //MC.If(tv.PowerIds != "", usable && tv.CheckCode == 1, true).(bool),
  218. AppType: tv.AppType,
  219. OpenType: tv.OpenType,
  220. TipInfo: &pb.TipInfo{
  221. Title: title,
  222. Content: content,
  223. ConfirmUrl: confirmUrl,
  224. ConfirmText: confirmText,
  225. IsShowCancel: isShowCancel,
  226. AppType: appType,
  227. OpenType: openType,
  228. },
  229. Match: MC.If(tv.Match != "", strings.Split(tv.Match, ","), []string{}).([]string),
  230. }
  231. if len(tv.Children) > 0 {
  232. L:
  233. for _, fv := range tv.Children {
  234. if fv.Name == "" {
  235. continue
  236. }
  237. if fv.CapitalCode != "" || fv.PermissionCode != "" {
  238. //用户是否需要留资
  239. //资源中台获取用户权限--没有权限:title等置空
  240. //ResourceLib.PowerHandle()
  241. //判断资源中台权限
  242. title, content, confirmUrl, confirmText, appType, openType, isShowCancel, feasibility = CheckCapitalResources(fv, m, usable, m.VerifyPermissions(fv.PermissionCode))
  243. }
  244. threeLevel.Url = MC.If(fv.Url != "", fv.Url, tv.Url).(string)
  245. threeLevel.Icon = MC.If(fv.Icon != "", fv.Icon, tv.Icon).(string)
  246. threeLevel.AppType = fv.AppType
  247. threeLevel.OpenType = fv.OpenType
  248. threeLevel.Usable = feasibility
  249. if title != "" {
  250. threeLevel.TipInfo = &pb.TipInfo{
  251. Title: title,
  252. Content: content,
  253. ConfirmUrl: confirmUrl,
  254. ConfirmText: confirmText,
  255. IsShowCancel: isShowCancel,
  256. AppType: appType,
  257. OpenType: openType,
  258. }
  259. }
  260. threeLevel.Match = MC.If(fv.Match != "", strings.Split(fv.Match, ","), []string{}).([]string)
  261. //四级菜单必须有顺序性,大会员》商机管理》超级订阅》免费用户
  262. name := MC.If(strings.Contains(fv.Name, "-"), strings.Split(fv.Name, "-")[0], "免费").(string)
  263. if len(UserRolePowers[name]) > 0 && m.VerifyPermissions(strings.Join(UserRolePowers[name], ",")) {
  264. break L
  265. }
  266. }
  267. }
  268. //无资源中台权限 菜单不显示
  269. if !feasibility && tv.CheckCode == 1 {
  270. continue
  271. }
  272. if threeLevel != nil {
  273. secondLevel.Child = append(secondLevel.Child, threeLevel)
  274. }
  275. }
  276. }
  277. //二级菜单 有三级子菜单;才会显示
  278. if len(secondLevel.Child) == 0 && sv.CheckCode == 1 {
  279. continue
  280. }
  281. oneLevel.Child = append(oneLevel.Child, secondLevel)
  282. }
  283. }
  284. //一级菜单 有二级子菜单;才会显示
  285. if len(oneLevel.Child) == 0 && mv.CheckCode == 1 {
  286. continue
  287. }
  288. menuList = append(menuList, oneLevel)
  289. }
  290. //清用户内存信息
  291. func(baseUserid string) {
  292. OverallLock.Lock()
  293. defer OverallLock.Unlock()
  294. userInfo := UserInfoMap[baseUserid]
  295. if userInfo != nil {
  296. userInfo.Lock.Lock()
  297. defer userInfo.Lock.Unlock()
  298. userInfo.Permissions = map[string]int{}
  299. userInfo.Capitals = map[string]int{}
  300. }
  301. }(m.NewUserId)
  302. //bytes, _ := json.MarshalIndent(menuList, "", " ")
  303. //fmt.Printf("%s\n", bytes)
  304. return menuList, nil
  305. }
  306. // VerifyPermissions 是否有权限可用此服务
  307. func (m *WorkDesktopMenu) VerifyPermissions(powerIds string) (b bool) {
  308. if powerIds == "" {
  309. return true
  310. }
  311. if len(strings.Split(powerIds, ",")) > 0 {
  312. userPower := m.AutoUserPowerInfo() //m.TimeOut, m.BigMemberOff,
  313. func(powerIds string) {
  314. for _, pv := range strings.Split(powerIds, ",") {
  315. if userPower[pv] > 0 {
  316. b = true
  317. break
  318. }
  319. }
  320. }(powerIds)
  321. }
  322. return
  323. }
  324. //常用功能
  325. const (
  326. WorkCommonly = "work_commonly"
  327. WorkMenu = "work_menu"
  328. )
  329. // CommonlyUpdate 更新常用功能
  330. func CommonlyUpdate(in *pb.WorkDesktopComprehensiveReq) (B bool, M string) {
  331. //事务 1:查; 2: 存;3: 删;
  332. var (
  333. ids []string
  334. mk int
  335. )
  336. for _, mid := range strings.Split(in.MenuIds, ",") {
  337. if mid == "" {
  338. continue
  339. }
  340. mk++
  341. //常用功能数量限制
  342. if ConfigJson.CommonlySize > 0 && mk >= int(ConfigJson.CommonlySize) {
  343. break
  344. }
  345. //id 解密
  346. ids = append(ids, encrypt.SE.DecodeString(mid))
  347. }
  348. //更新此用户设置的常用功能
  349. if B = BaseMysql.ExecTx("常用功能批量更新", func(tx *sql.Tx) bool {
  350. //查询此用户常用功能是否已存在记录
  351. var id = 0
  352. existingData := BaseMysql.SelectBySqlByTx(tx, `SELECT id FROM `+WorkCommonly+` WHERE base_userid = ? AND appid = ? AND field = ? AND platform = ? ORDER BY id DESC `, in.NewUserId, in.AppId, in.ActionMode, in.Platform)
  353. if existingData != nil && len(*existingData) > 0 {
  354. id = MC.IntAll((*existingData)[0]["id"])
  355. }
  356. switch {
  357. case id > 0: //更新
  358. if BaseMysql.UpdateOrDeleteBySqlByTx(tx, `UPDATE `+WorkCommonly+` SET value = ? WHERE id = ?`, strings.Join(ids, ","), id) < 0 {
  359. logx.Info("常用功能-更新数据失败")
  360. return false
  361. }
  362. default: //插入
  363. if BaseMysql.InsertBySqlByTx(tx, `INSERT INTO `+WorkCommonly+` (appid,base_userid,platform,field,value) VALUES (?,?,?,?,?)`, in.AppId, in.NewUserId, in.Platform, in.ActionMode, strings.Join(ids, ",")) < 0 {
  364. logx.Info("常用功能-插入数据失败")
  365. return false
  366. }
  367. }
  368. return true
  369. }); !B {
  370. M = "常用功能更新数据失败"
  371. }
  372. return
  373. }
  374. // CommonlyFormat 常用功能 格式化
  375. func (m *WorkDesktopMenu) CommonlyFormat(childMenus map[int][]*JYMenu) ([]*pb.ThreeLevelMenu, []string, bool) {
  376. menuList := make([]*pb.ThreeLevelMenu, 0)
  377. subLevel := map[int]bool{}
  378. delBool := false //更新因超级订阅用户,又购买大会员得用户 导致附件下载包||采购单位画像记录||企业画像记录 不应该展示
  379. var saveIds []string
  380. for _, mv := range m.MenuTree {
  381. //过滤子级 ++ 三级下架菜单:mv.Status == 1
  382. if subLevel[mv.ParentId] || mv.Status == 1 {
  383. continue
  384. }
  385. //附件下载包、采购单位画像记录、企业画像记录 如果是大会员+超级订阅 排除此三项菜单
  386. //灵活性降低,不应该这么搞
  387. if (mv.Name == "附件下载包" && m.VerifyPermissions("3")) || (mv.Name == "采购单位画像记录" && m.VerifyPermissions("5")) || (mv.Name == "企业画像记录" && m.VerifyPermissions("4,12,13,19,20,21,23")) {
  388. delBool = true
  389. continue
  390. }
  391. saveIds = append(saveIds, encrypt.SE.EncodeString(strconv.Itoa(mv.Id)))
  392. subLevel[mv.Id] = true
  393. //0:默认展示;1:需验证权限,有权限展示;2:需验证权限,无权限也可展示(可用服务无权限不展示)
  394. usable := m.VerifyPermissions(mv.PowerIds)
  395. oneLevel := &pb.ThreeLevelMenu{
  396. Name: mv.Name,
  397. Icon: mv.Icon,
  398. Url: mv.Url,
  399. Id: encrypt.SE.EncodeString(strconv.Itoa(mv.Id)), //功能id加密
  400. Usable: usable, //MC.If(mv.PowerIds != "", usable && mv.CheckCode == 1, true).(bool),
  401. AppType: mv.AppType,
  402. OpenType: mv.OpenType,
  403. TipInfo: &pb.TipInfo{
  404. Title: mv.AdditionalInfo.Title,
  405. Content: mv.AdditionalInfo.Content,
  406. ConfirmUrl: mv.AdditionalInfo.ConfirmUrl,
  407. ConfirmText: mv.AdditionalInfo.ConfirmText,
  408. IsShowCancel: mv.AdditionalInfo.IsShowCancel,
  409. AppType: mv.AppType,
  410. OpenType: mv.OpenType,
  411. },
  412. Match: MC.If(mv.Match != "", strings.Split(mv.Match, ","), []string{}).([]string),
  413. }
  414. //处理子级
  415. if childMenus[mv.Id] != nil && len(childMenus[mv.Id]) > 0 {
  416. childMenu := childMenus[mv.Id]
  417. sort.Slice(childMenu, func(i, j int) bool {
  418. return childMenu[i].OrderId > childMenu[j].OrderId
  419. })
  420. L:
  421. for _, cv := range childMenu {
  422. if cv.Name == "" || cv.ParentId != mv.Id {
  423. continue
  424. }
  425. oneLevel.Url = MC.If(cv.Url != "", cv.Url, mv.Url).(string)
  426. oneLevel.Icon = MC.If(cv.Icon != "", cv.Icon, mv.Icon).(string)
  427. oneLevel.AppType = cv.AppType
  428. oneLevel.OpenType = cv.OpenType
  429. if cv.AdditionalInfo.Title != "" {
  430. oneLevel.TipInfo = &pb.TipInfo{
  431. Title: cv.AdditionalInfo.Title,
  432. Content: cv.AdditionalInfo.Content,
  433. ConfirmUrl: cv.AdditionalInfo.ConfirmUrl,
  434. ConfirmText: cv.AdditionalInfo.ConfirmText,
  435. IsShowCancel: cv.AdditionalInfo.IsShowCancel,
  436. AppType: cv.AppType,
  437. OpenType: cv.OpenType,
  438. }
  439. }
  440. oneLevel.Match = MC.If(cv.Match != "", strings.Split(cv.Match, ","), []string{}).([]string)
  441. name := MC.If(strings.Contains(cv.Name, "-"), strings.Split(cv.Name, "-")[0], "免费").(string)
  442. if len(UserRolePowers[name]) > 0 && m.VerifyPermissions(strings.Join(UserRolePowers[name], ",")) {
  443. break L
  444. }
  445. }
  446. }
  447. menuList = append(menuList, oneLevel)
  448. }
  449. return menuList, saveIds, delBool
  450. }