regionPermission.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. import store from '@/store'
  2. /**
  3. * 区域权限指令实现
  4. * 用于处理基于用户级别(省级、市级、县级)的权限控制
  5. */
  6. // 权限判断公共工具
  7. const permissionUtils = {
  8. /**
  9. * 获取当前登录用户信息
  10. * @returns {Object} 用户信息对象
  11. */
  12. getUserInfo() {
  13. const userInfo = store.state.user.userInfo || {}
  14. return userInfo.user || {}
  15. },
  16. /**
  17. * 判断是否为管理员账号
  18. * @returns {Boolean} 是否为管理员
  19. */
  20. isAdmin() {
  21. const user = this.getUserInfo()
  22. return !!user.admin
  23. },
  24. /**
  25. * 判断是否为省级账号
  26. * @returns {Boolean} 是否为省级账号
  27. */
  28. isProvince() {
  29. const user = this.getUserInfo()
  30. return user.dataScope === PERMISSION_LEVEL.PROVINCE
  31. },
  32. /**
  33. * 判断是否为管理员或省级账号
  34. * @returns {Boolean} 是否为管理员或省级账号
  35. */
  36. isAdminOrProvince() {
  37. return this.isAdmin() || this.isProvince()
  38. },
  39. /**
  40. * 根据操作和分类判断权限
  41. * @param {String} action - 操作类型:'view', 'add', 'edit', 'delete'
  42. * @param {String} category - 权限分类
  43. * @returns {Boolean} 是否有权限
  44. */
  45. hasPermission(action, category) {
  46. if (this.isAdmin()) {
  47. return true
  48. }
  49. const user = this.getUserInfo()
  50. const dataScope = user.dataScope ?? 999
  51. // 对于省级维护,市县查看的分类
  52. if (PERMISSION_CATEGORIES.ADMIN_PROVINCE_VIEW_OTHERS.includes(category)) {
  53. if (action === 'view') {
  54. return true
  55. } else {
  56. return dataScope === PERMISSION_LEVEL.PROVINCE
  57. }
  58. }
  59. return false
  60. },
  61. }
  62. // 权限级别定义
  63. export const PERMISSION_LEVEL = {
  64. PROVINCE: 0, // 省级
  65. CITY: 1, // 市级
  66. COUNTY: 2, // 县级
  67. }
  68. // 分类权限定义 - 基于表格结构
  69. export const PERMISSION_CATEGORIES = {
  70. // 第一类:省级维护,市县查看
  71. ADMIN_PROVINCE_VIEW_OTHERS: [
  72. 'catalogManage', // 监审目录管理
  73. 'auditEntityManage', // 被监审单位管理
  74. 'auditReviewDocManage', // 监审文书管理
  75. 'auditDocNoManage', // 监审文号管理
  76. 'auditDocManage', // 监审资料管理
  77. 'annualReviewPlan', // 年度审计计划
  78. 'auditInitiation', // 监审立项管理
  79. 'costFormManage', // 成本调查表模板管理
  80. 'financeSheetManage', // 财务数据表模板管理
  81. 'costVerifyManage', // 成本核定表模板管理
  82. ],
  83. // 第二类:省市县都可添加但各维护各,省级添加的市县查看,同级不可查看
  84. // LEVEL_BASED_MANAGE: [
  85. // 'costFormManage', // 成本调查表模板管理
  86. // 'financeSheetManage', // 财务数据表模板管理
  87. // 'costVerifyManage', // 成本核定表模板管理
  88. // ],
  89. // 第三类:跟着数据权限走
  90. // DATA_BASED_MANAGE: [
  91. // 'auditProject', // 监审项目管理
  92. // 'taskManagement', // 任务管理
  93. // 'superviseMatters' // 督办管理
  94. // ],
  95. }
  96. /**
  97. * 权限处理逻辑封装为函数
  98. * @param {HTMLElement} element - 要处理权限的DOM元素
  99. * @param {Object} binding - Vue指令绑定对象
  100. */
  101. export function handlePermission(element, binding) {
  102. // 获取用户信息
  103. const userInfo = store.state.user.userInfo || {}
  104. const user = userInfo.user || {}
  105. // 更加健壮的管理员权限判断,接受布尔值true、字符串'true'等真值
  106. const isAdmin = !!user.admin
  107. const dataScope = user.dataScope ?? 999 // 默认无权限
  108. // 解析绑定值
  109. const options = binding.value || {}
  110. const action = options.action || 'view' // 默认只有查看权限
  111. const category = options.category || '' // 权限分类标识
  112. const targetData = options.targetData || {} // 目标数据,用于判断同级等场景
  113. const displayMode = options.displayMode || 'hidden' // 无权限时的显示模式:'hidden'(隐藏)或 'disabled'(禁用)
  114. // 判断是否拥有权限
  115. let hasPermission = false
  116. // 管理员拥有所有权限
  117. if (isAdmin) {
  118. hasPermission = true
  119. } else {
  120. // 基于分类的权限判断逻辑
  121. // 第一类权限:省级维护,市县查看
  122. if (PERMISSION_CATEGORIES.ADMIN_PROVINCE_VIEW_OTHERS.includes(category)) {
  123. if (action === 'view') {
  124. // 所有级别都可查看
  125. hasPermission = true
  126. } else {
  127. // 新增、编辑、删除操作只有省级可执行
  128. // 确保dataScope为0的省级用户有正确权限
  129. hasPermission = dataScope === PERMISSION_LEVEL.PROVINCE
  130. }
  131. }
  132. // 第二类权限:省市县都可添加但各维护各,省级添加的市县查看,同级不可查看
  133. // if (PERMISSION_CATEGORIES.LEVEL_BASED_MANAGE.includes(category)) {
  134. // if (action === 'view') {
  135. // // 省级可查看所有添加的市县
  136. // hasPermission = true
  137. // } else {
  138. // // 新增、编辑、删除操作只有数据创建者和当前用户是用一个可执行
  139. // if (
  140. // targetData.createBy === user.username
  141. // ) {
  142. // hasPermission = true
  143. // }
  144. // // hasPermission = dataScope === PERMISSION_LEVEL[category.split('Manage')[0]]
  145. // }
  146. // }
  147. // 第三类权限:跟着数据权限走
  148. // if (PERMISSION_CATEGORIES.DATA_BASED_MANAGE.includes(category)) {
  149. // // 数据权限判断逻辑...
  150. // }
  151. }
  152. // 根据displayMode决定无权限时的处理方式
  153. if (!hasPermission) {
  154. if (displayMode === 'disabled') {
  155. // 禁用模式:保留元素但禁用交互
  156. element.setAttribute('disabled', 'disabled')
  157. element.style.cursor = 'not-allowed'
  158. element.style.opacity = '0.6'
  159. element.style.pointerEvents = 'none' // 禁用所有指针事件
  160. // 添加提示类名,可用于自定义样式
  161. element.classList.add('permission-disabled')
  162. // 对于a标签的特殊处理
  163. if (element.tagName === 'A') {
  164. // 移除href属性或设置为无效值
  165. if (element.hasAttribute('href')) {
  166. element.setAttribute(
  167. 'data-original-href',
  168. element.getAttribute('href')
  169. )
  170. element.removeAttribute('href')
  171. }
  172. element.setAttribute('tabindex', '-1') // 从Tab键序列中移除
  173. }
  174. // 阻止所有事件冒泡和默认行为,确保元素真正不可交互
  175. const preventEvent = (e) => {
  176. e.stopPropagation()
  177. e.preventDefault()
  178. return false
  179. }
  180. // 使用捕获模式添加所有可能的交互事件阻止
  181. const events = [
  182. 'click',
  183. 'mousedown',
  184. 'mouseup',
  185. 'dblclick',
  186. 'touchstart',
  187. 'touchend',
  188. 'touchmove',
  189. 'touchcancel',
  190. 'keydown',
  191. 'keypress',
  192. 'keyup',
  193. 'focus',
  194. 'blur',
  195. ]
  196. events.forEach((event) => {
  197. element.addEventListener(event, preventEvent, true)
  198. })
  199. // 重写元素上可能存在的onclick等属性
  200. element.onclick = null
  201. element.onmousedown = null
  202. element.onmouseup = null
  203. element.ondblclick = null
  204. } else {
  205. // 默认隐藏模式:移除元素
  206. element.parentNode && element.parentNode.removeChild(element)
  207. }
  208. }
  209. }
  210. // 区域权限指令定义 - 同时使用inserted和update钩子确保动态元素也能正确应用权限
  211. export const regionPermission = {
  212. inserted: handlePermission,
  213. update: handlePermission,
  214. }
  215. // 安装函数
  216. const install = function (Vue) {
  217. Vue.directive('region-permission', regionPermission)
  218. // 挂载权限判断工具到Vue原型
  219. Vue.prototype.$permission = permissionUtils
  220. // 全局挂载regionPermission对象,方便其他地方使用
  221. if (window.Vue) {
  222. window['regionPermission'] = regionPermission
  223. window['permissionUtils'] = permissionUtils
  224. }
  225. }
  226. // 全局安装
  227. if (window.Vue) {
  228. window['regionPermission'] = regionPermission
  229. Vue.use(install)
  230. }
  231. // 导出
  232. export default {
  233. regionPermission,
  234. handlePermission,
  235. PERMISSION_LEVEL,
  236. PERMISSION_CATEGORIES,
  237. permissionUtils,
  238. install,
  239. }
  240. // 同时导出permissionUtils,方便在非Vue组件中使用
  241. export { permissionUtils }