permissions.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import store from '@/store'
  2. // 现有权限指令
  3. const permissions = {
  4. inserted(element, binding) {
  5. const { value } = binding
  6. const permissions = store.getters['user/permissions']
  7. if (value && value instanceof Array && value.length > 0) {
  8. const hasPermission = permissions.some((role) => value.includes(role))
  9. if (!hasPermission)
  10. element.parentNode && element.parentNode.removeChild(element)
  11. }
  12. },
  13. }
  14. // 权限处理逻辑封装为函数,方便inserted和update钩子复用
  15. function handlePermission(element, binding) {
  16. // 获取用户信息
  17. const userInfo = store.state.user.userInfo || {}
  18. const user = userInfo.user || {}
  19. // 更加健壮的管理员权限判断,接受布尔值true、字符串'true'等真值
  20. const isAdmin = !!user.admin
  21. const dataScope = user.dataScope ?? 999 // 默认无权限
  22. // 权限级别定义
  23. const PERMISSION_LEVEL = {
  24. PROVINCE: 0, // 省级
  25. CITY: 1, // 市级
  26. COUNTY: 2, // 县级
  27. }
  28. // 分类权限定义 - 基于表格结构
  29. const PERMISSION_CATEGORIES = {
  30. // 第一类:省级维护,市县查看
  31. ADMIN_PROVINCE_VIEW_OTHERS: [
  32. 'catalogManage', // 监审目录管理
  33. 'auditEntityManage', // 被监审单位管理
  34. 'costFormManage', // 成本监审表模板管理
  35. 'financeSheetManage', // 财务数据表模板管理
  36. 'costVerifyManage', // 成本核定表模板管理
  37. 'auditReviewDocManage', // 监审文书管理
  38. 'auditDocNoManage', // 监审文号管理
  39. 'auditDocManage', // 监审资料管理
  40. 'annualReviewPlan', // 年度审计计划
  41. 'auditInitiation', // 监审立项管理
  42. ],
  43. // 第二类:省市县可查看添加本级及下级,同级不可查看添加
  44. // LEVEL_BASED_MANAGE: [
  45. // 'annualReviewPlan', // 年度审计计划
  46. // 'auditInitiation', // 监审立项管理
  47. // ],
  48. // 第三类:跟着数据权限走
  49. // DATA_BASED_MANAGE: [
  50. // 'auditProject', // 监审项目管理
  51. // 'taskManagement', // 任务管理
  52. // 'superviseMatters' // 督办管理
  53. // ],
  54. }
  55. // 解析绑定值
  56. const options = binding.value || {}
  57. const action = options.action || 'view' // 默认只有查看权限
  58. const category = options.category || '' // 权限分类标识
  59. const targetData = options.targetData || {} // 目标数据,用于判断同级等场景
  60. const displayMode = options.displayMode || 'hidden' // 无权限时的显示模式:'hidden'(隐藏)或 'disabled'(禁用)
  61. // 判断是否拥有权限
  62. let hasPermission = false
  63. // 管理员拥有所有权限
  64. if (isAdmin) {
  65. hasPermission = true
  66. } else {
  67. // 基于分类的权限判断逻辑
  68. // 第一类权限:省级维护,市县查看
  69. if (PERMISSION_CATEGORIES.ADMIN_PROVINCE_VIEW_OTHERS.includes(category)) {
  70. if (action === 'view') {
  71. // 所有级别都可查看
  72. hasPermission = true
  73. } else {
  74. // 新增、编辑、删除操作只有省级可执行
  75. // 确保dataScope为0的省级用户有正确权限
  76. hasPermission = dataScope === PERMISSION_LEVEL.PROVINCE
  77. }
  78. }
  79. }
  80. // 根据displayMode决定无权限时的处理方式
  81. if (!hasPermission) {
  82. if (displayMode === 'disabled') {
  83. // 禁用模式:保留元素但禁用交互
  84. element.setAttribute('disabled', 'disabled')
  85. element.style.cursor = 'not-allowed'
  86. element.style.opacity = '0.6'
  87. element.style.pointerEvents = 'none' // 禁用所有指针事件
  88. // 添加提示类名,可用于自定义样式
  89. element.classList.add('permission-disabled')
  90. // 对于a标签的特殊处理
  91. if (element.tagName === 'A') {
  92. // 移除href属性或设置为无效值
  93. if (element.hasAttribute('href')) {
  94. element.setAttribute(
  95. 'data-original-href',
  96. element.getAttribute('href')
  97. )
  98. element.removeAttribute('href')
  99. }
  100. element.setAttribute('tabindex', '-1') // 从Tab键序列中移除
  101. }
  102. // 阻止所有事件冒泡和默认行为,确保元素真正不可交互
  103. const preventEvent = (e) => {
  104. e.stopPropagation()
  105. e.preventDefault()
  106. return false
  107. }
  108. // 使用捕获模式添加所有可能的交互事件阻止
  109. const events = [
  110. 'click',
  111. 'mousedown',
  112. 'mouseup',
  113. 'dblclick',
  114. 'touchstart',
  115. 'touchend',
  116. 'touchmove',
  117. 'touchcancel',
  118. 'keydown',
  119. 'keypress',
  120. 'keyup',
  121. 'focus',
  122. 'blur',
  123. ]
  124. events.forEach((event) => {
  125. element.addEventListener(event, preventEvent, true)
  126. })
  127. // 重写元素上可能存在的onclick等属性
  128. element.onclick = null
  129. element.onmousedown = null
  130. element.onmouseup = null
  131. element.ondblclick = null
  132. } else {
  133. // 默认隐藏模式:移除元素
  134. element.parentNode && element.parentNode.removeChild(element)
  135. }
  136. }
  137. }
  138. // 区域权限指令定义 - 同时使用inserted和update钩子确保动态元素也能正确应用权限
  139. const regionPermission = {
  140. inserted: handlePermission,
  141. update: handlePermission,
  142. }
  143. // 安装函数
  144. const install = function (Vue) {
  145. Vue.directive('permissions', permissions)
  146. Vue.directive('region-permission', regionPermission)
  147. }
  148. // 全局安装
  149. if (window.Vue) {
  150. window['permissions'] = permissions
  151. window['regionPermission'] = regionPermission
  152. Vue.use(install)
  153. }
  154. // 导出
  155. permissions.install = install
  156. export default permissions