zhou zhou
10 小时以前 46d872c1a5b77aa8799de4a64888a0a24a1422d6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
class RoutePermissionValidator {
  /**
   * 验证路径是否在用户菜单权限中
   * @param targetPath 目标路径
   * @param menuList 菜单列表
   * @returns 是否有权限访问
   */
  static hasPermission(targetPath, menuList) {
    if (targetPath === '/') {
      return true
    }
    return this.matchRoute(targetPath, menuList)
  }
  /**
   * 构建菜单路径集合(扁平化处理)
   * @param menuList 菜单列表
   * @param pathSet 路径集合
   * @returns 路径集合
   */
  static buildMenuPathSet(menuList, pathSet = /* @__PURE__ */ new Set()) {
    if (!Array.isArray(menuList) || menuList.length === 0) {
      return pathSet
    }
    for (const menuItem of menuList) {
      if (!menuItem.path) {
        continue
      }
      const menuPath = menuItem.path.startsWith('/') ? menuItem.path : `/${menuItem.path}`
      pathSet.add(menuPath)
      if (menuItem.children?.length) {
        this.buildMenuPathSet(menuItem.children, pathSet)
      }
    }
    return pathSet
  }
  /**
   * 检查目标路径是否匹配集合中的某个路径前缀
   * 用于支持动态路由参数匹配,如 /user/123 匹配 /user
   * @param targetPath 目标路径
   * @param pathSet 路径集合
   * @returns 是否匹配
   */
  static checkPathPrefix(targetPath, pathSet) {
    for (const menuPath of pathSet) {
      if (targetPath.startsWith(`${menuPath}/`)) {
        return true
      }
    }
    return false
  }
  /**
   * 递归匹配路由配置,支持隐藏路由和动态参数路由
   */
  static matchRoute(targetPath, routes) {
    if (!Array.isArray(routes) || routes.length === 0) {
      return false
    }
    for (const route of routes) {
      if (!route.path) {
        continue
      }
      const routePath = route.path.startsWith('/') ? route.path : `/${route.path}`
      if (
        routePath === targetPath ||
        this.isDynamicRouteMatch(targetPath, routePath) ||
        targetPath.startsWith(`${routePath}/`)
      ) {
        return true
      }
      if (route.children?.length && this.matchRoute(targetPath, route.children)) {
        return true
      }
    }
    return false
  }
  /**
   * 检查目标路径是否匹配动态参数路由,如 /demo/123 匹配 /demo/:id
   */
  static isDynamicRouteMatch(targetPath, routePath) {
    if (!routePath.includes(':')) {
      return false
    }
    const pattern = routePath
      .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
      .replace(/:([^/]+)/g, '[^/]+')
      .replace(/\\\*/g, '.*')
    return new RegExp(`^${pattern}$`).test(targetPath)
  }
  /**
   * 验证并返回有效的路径
   * 如果目标路径无权限,返回首页路径
   * @param targetPath 目标路径
   * @param menuList 菜单列表
   * @param homePath 首页路径
   * @returns 验证后的路径
   */
  static validatePath(targetPath, menuList, homePath = '/') {
    const hasPermission = this.hasPermission(targetPath, menuList)
    if (hasPermission) {
      return { path: targetPath, hasPermission: true }
    }
    return { path: homePath, hasPermission: false }
  }
}
export { RoutePermissionValidator }