gaoluyang
4 天以前 c7566bba45e6f90594d36ec4b80ac4ff89f577ee
src/store/modules/permission.js
@@ -36,9 +36,11 @@
        return new Promise(resolve => {
          // 向后端请求路由数据
          getRouters().then(res => {
            const sdata = JSON.parse(JSON.stringify(res.data))
            const rdata = JSON.parse(JSON.stringify(res.data))
            const defaultData = JSON.parse(JSON.stringify(res.data))
            // 三份数据各自深拷贝后分别构建,normalizeRouteNames 是确定性的,
            // 因此三处得到的 name 完全一致,页签缓存不会对不上。
            const sdata = normalizeRouteNames(JSON.parse(JSON.stringify(res.data)))
            const rdata = normalizeRouteNames(JSON.parse(JSON.stringify(res.data)))
            const defaultData = normalizeRouteNames(JSON.parse(JSON.stringify(res.data)))
            const sidebarRoutes = filterAsyncRouter(sdata)
            const rewriteRoutes = filterAsyncRouter(rdata, false, true)
            const defaultRoutes = filterAsyncRouter(defaultData)
@@ -55,6 +57,52 @@
    }
  })
const isContainerRoute = (route) =>
  route.component === 'Layout' || route.component === 'ParentView' || route.component === 'InnerLink'
/**
 * 修正后端菜单里的路由重名。
 *
 * 两种情况 vue-router 4 会因重名丢路由或直接报错:
 * 1. 父容器与后代页面同名(如 /standardMaterial 容器与其下的标准物质清单页都叫
 *    StandardMaterial)——vue-router 3 允许,vue-router 4 抛
 *    "A route named X has been added as a child of a route with the same name";
 * 2. 两个不同菜单项取了同一个 name(如两个「报告结果」都叫 ReportResults)——
 *    addRoute 时后者会把前者挤掉,被挤掉的那条路径就点不开了。
 *
 * 处理策略:先保留第一次出现的 name,后续重名一律加数字后缀。容器与后代叶子重名
 * 时优先改容器名(页面 name 与组件 name 一致,是页签缓存的键,尽量不动)。
 */
function normalizeRouteNames(routes) {
  const leafNames = new Set()
  const collectLeafNames = (list) => {
    list.forEach(route => {
      if (route.name && !isContainerRoute(route)) leafNames.add(route.name)
      if (route.children && route.children.length) collectLeafNames(route.children)
    })
  }
  collectLeafNames(routes)
  const used = new Set()
  const walk = (list) => {
    list.forEach(route => {
      if (route.name) {
        const conflict = used.has(route.name) ||
          (isContainerRoute(route) && leafNames.has(route.name))
        if (conflict) {
          let suffix = 2
          while (leafNames.has(`${route.name}${suffix}`) || used.has(`${route.name}${suffix}`)) suffix++
          route.name = `${route.name}${suffix}`
        }
        used.add(route.name)
      }
      if (route.children && route.children.length) walk(route.children)
    })
  }
  walk(routes)
  return routes
}
// 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
  return asyncRouterMap.filter(route => {