When the vue project is doing menu permissions, there is an infinite loop problem in dynamic routing, and the problem of refreshing the page store data is lost and the page is blank.

The recent project requirement is to do menu permissions, button permissions, etc. We developed it with vue. Let’s take a look at the page style of our project background, as shown in the figure below. The user center is divided into user management, menu management and role management. User management, as the name suggests, is to manage who is using the system, including some common functions such as adding accounts, modifying accounts, disabling and activating, etc. Our system has a unified login password, so it is not required to fill in when adding an account For the password item, the personal center will look at the personal information, and you can change your mobile phone number and login password. These implementations are not difficult, just adjust the interface to add, delete, modify and check, and write down the business logic code.

User management and personal center module

insert image description here
insert image description here

Menu Management Module

insert image description here
insert image description here
insert image description here
insert image description here
This menu management module uses the vue-treeselect component, and the code name here is the name of our routing component or the unique identifier of the button, which is unique and bound to the menu permission or button permission of the page. The parent is the current directory Or the parent of the button, using the vue-treeselect component. If you are not familiar with this component, you can go to the vue-treeselect official website , first order npm install --save @riophae/vue-treeselect to install and then import and register before using, and paste the code:

//安装
npm install --save @riophae/vue-treeselect
//引入
  import Treeselect from '@riophae/vue-treeselect'
  // import the styles
  import '@riophae/vue-treeselect/dist/vue-treeselect.css'
  //注册局部组件
  components: {
    
     Treeselect },
<template>
  <div class="app-container">
    <div style="margin-top: 10px">
      <el-input
        v-model="search"
        placeholder="输入权限名称进行搜索"
        style="width: 200px"
        class="filter-item"
        @keyup.native="handleFilter"
      />

      <!-- :disabled="!$checkPermission(['menu_add'])" -->
      <el-button
        type="primary"
        icon="el-icon-plus"
        :disabled="!$checkPermission(['menu_add'])"
        @click="handleAdd"
        >新增</el-button
      >
    </div>
    <el-table
      v-loading="listLoading"
      :data="
        tableData.filter(
          data =>
            !search || data.name.toLowerCase().includes(search.toLowerCase())
        )
      "
      style="width: 100%; margin-top: 10px"
      border
      fit
      stripe
      highlight-current-row
      max-height="600"
      row-key="id"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
    >
      <el-table-column label="菜单名称">
        <template slot-scope="scope">{
    
    {
    
     scope.row.name }}</template>
      </el-table-column>
      <el-table-column label="类型">
        <template slot-scope="scope">{
    
    {
    
     TypeWays(scope.row.type) }}</template>
      </el-table-column>
      <el-table-column label="代号">
        <template slot-scope="scope">{
    
    {
    
     scope.row.url }}</template>
      </el-table-column>
      <el-table-column label="排序">
        <template slot-scope="scope">{
    
    {
    
     scope.row.status }}</template>
      </el-table-column>
      <el-table-column align="center" label="操作" width="170">
        <template slot-scope="scope">
          <el-button
            type="primary"
            :disabled="!$checkPermission(['menu_edit'])"
            size="small"
            @click="handleEdit(scope)"
            >编辑</el-button
          >

          <el-button
            type="danger"
            size="small"
            :disabled="!$checkPermission(['menu_delete'])"
            @click="handleDelete(scope)"
            >删除</el-button
          >
        </template>
      </el-table-column>
    </el-table>

    <el-dialog
      :visible.sync="dialogVisible"
      :title="dialogType === 'edit' ? '编辑' : '新增'"
    >
      <el-form
        ref="Form"
        :model="perm"
        label-width="80px"
        label-position="right"
        :rules="rule1"
      >
        <el-form-item label="类型">
          <el-radio-group v-model="perm.type" @change="typeChange">
            <el-radio :label="1">目录</el-radio>
            <el-radio :label="2">按钮</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="名称" prop="name">
          <el-input v-model="perm.name" placeholder="名称" />
        </el-form-item>
        <el-form-item label="代号" prop="url">
          <el-input v-model="perm.url" placeholder="代号" />
        </el-form-item>
        <el-form-item label="父级" prop="pid">
          <treeselect
            v-model="perm.pid"
            :multiple="false"
            :options="TreeData"
            placeholder="父级"
            :normalizer="normalizer"
          />
        </el-form-item>
        <el-form-item label="排序" prop="status">
          <el-input-number
            v-model="perm.status"
            :min="1"
            label="排序"
          ></el-input-number>
        </el-form-item>

        <el-form-item label="备注" prop="remarks">
          <el-input
            type="textarea"
            :rows="2"
            placeholder="请输入备注"
            v-model="perm.remarks"
          >
          </el-input>
        </el-form-item>
      </el-form>
      <div style="text-align: right">
        <el-button type="danger" @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="confirmPerm('Form')">确认</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
// import { getPermAll, createPerm, deletePerm, updatePerm } from "@/api/perm";
import * as user from "@/api/datax-user";
import {
    
    
  menuList,
  menuSaveForm,
  menuDetail,
  menuEdit,
  menuDelete,
  menuGetTree,
  menuGetTreeNotBtn
} from "@/api/datax-menu";

import {
    
     genTree, genTree2 } from "@/utils";

import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
const defaultPerm = {
    
    
  id: null,
  name: "",
  type: 1,
  url: "",
  status: 1,
  c: null,
  remarks: "",
  icon: ""
};
export default {
    
    
  components: {
    
     Treeselect },
  data() {
    
    
    return {
    
    
      perm: defaultPerm,
      search: "",
      tableData: [],
      TreeData: [],
      permList: [],
      listLoading: true,
      dialogVisible: false,
      dialogType: "new",
      rule1: {
    
    
        name: [{
    
     required: true, message: "请输入名称", trigger: "blur" }],
        url: [{
    
     required: true, message: "请输入代号", trigger: "blur" }]
      },
      normalizer(node) {
    
    
        if (node.childList && !node.childList.length) {
    
    
          delete node.childList;
        }

        return {
    
    
          id: node.id,
          pid: node.pid,
          value: node.id,
          label: node.name,
          name: node.name,
          children: node.childList
        };
      }
    };
  },
  computed: {
    
    },
  created() {
    
    
    this.getList();
  },
  methods: {
    
    
    getList() {
    
    
      this.listLoading = true;
      menuList({
    
    
        current: 1,
        size: 1000000,
        name: this.search,
        status: "",
        type: ""
      }).then(response => {
    
    
        console.log("菜单列表", response);
        if (response.code == 200) {
    
    
          this.permList = response.content.listpg;
          const data = genTree(response.content.listpg);
          this.tableData = data;
          this.listLoading = false;
        }
      });
    },

    traversalTree(arrs, result) {
    
    
      arrs.map((item, index) => {
    
    
        let obj = {
    
    
          key: item.id,
          title: item.name,
          children: []
        };
        result.push(obj);
        obj.children = obj.childList;

        if (item.childList.length !== 0) {
    
    
          traversalTree(item.childList, result[index].children);
        }
      });
    },

    //获取菜单树不包含按钮
    getTreeList() {
    
    
      menuGetTreeNotBtn({
    
    
        type: 0
      })
        .then(res => {
    
    
          this.TreeData = res.content;
        })
        .catch(err => {
    
    });
    },
    resetFilter() {
    
    
      this.getList();
    },
    handleFilter() {
    
    
      const newData = this.permList.filter(
        data =>
          !this.search ||
          data.name.toLowerCase().includes(this.search.toLowerCase())
      );
      this.tableData = genTree(newData);
    },
    handleAdd() {
    
    
      this.getTreeList();
      this.perm = Object.assign({
    
    }, defaultPerm);
      this.dialogType = "new";
      this.dialogVisible = true;
      this.$nextTick(() => {
    
    
        this.$refs["Form"].clearValidate();
      });
    },
    handleEdit(scope) {
    
    
      // console.log("点了编辑", scope);
      this.getTreeList();
      var dataT = JSON.parse(JSON.stringify(scope.row));
      this.perm = Object.assign({
    
    }, dataT); // copy obj

      if (scope.row.pid == 0) {
    
    
        this.perm.pid = null;
      }
      this.dialogType = "edit";
      this.dialogVisible = true;
      this.$nextTick(() => {
    
    
        this.$refs["Form"].clearValidate();
      });
    },
    handleDelete(scope) {
    
    
      this.$confirm("确认删除?", "警告", {
    
    
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "error"
      })
        .then(async () => {
    
    
          await menuDelete(scope.row);
          this.getList();
          this.getTreeList();
          this.$message({
    
    
            type: "success",
            message: "成功删除!"
          });
        })
        .catch(err => {
    
    
          console.error(err);
        });
    },
    async confirmPerm(form) {
    
    
      this.$refs[form].validate(valid => {
    
    
        if (valid) {
    
    
          const isEdit = this.dialogType === "edit";
          if (isEdit) {
    
    
            this.perm.children = [];
            console.log("编辑入参", this.perm);
            menuEdit(this.perm).then(() => {
    
    
              this.getList();
              this.dialogVisible = false;
              this.$message({
    
    
                message: "编辑成功",
                type: "success"
              });
            });
          } else {
    
    
            let addParams = {
    
    
              ...this.perm,
              pid: !this.perm.pid ? 0 : this.perm.pid
            };

            if (addParams.hasOwnProperty("id")) {
    
    
              delete addParams.id;
            }

            // console.log("新增入参", addParams);

            menuSaveForm(addParams).then(res => {
    
    
              // this.perm = res.data
              // this.tableData.unshift(this.perm)
              this.getList();
              this.dialogVisible = false;
              this.$message({
    
    
                message: "新增成功",
                type: "success"
              });
            });
          }
        } else {
    
    
          return false;
        }
      });
    },

    TypeWays(type) {
    
    
      if (type == 1) {
    
    
        return "目录";
      } else if (type == 2) {
    
    
        return "按钮";
      }
    },
    typeChange(val) {
    
    
      this.perm.pid = null;
    }
  }
};
</script>

Role Management Module

insert image description here
insert image description here
In our role management, there are only these four roles, and then our button permissions are configured by ticking in the menu directory when creating a role. Editing a role can also be edited by the way. Difficulty, the code is as follows:

<template>
  <!-- 角色列表 -->
  <div class="app-container">
    <div class="filter-container">
      <el-input
        v-model.trim="listQuery.name"
        placeholder="角色名称"
        style="width: 200px;"
        class="filter-item"
        clearable
      />
      <!-- <el-input
        v-model.trim="listQuery.roleId"
        placeholder="角色ID"
        style="width: 200px;"
        class="filter-item"
      /> -->

      <el-button
        v-waves
        class="filter-item"
        type="primary"
        icon="el-icon-search"
        @click="fetchData"
      >
        搜索
      </el-button>
      <el-button
        class="filter-item"
        style="margin-left: 0px;"
        type="primary"
        icon="el-icon-plus"
        :disabled="!$checkPermission(['role_add'])"
        @click="handleCreate"
      >
        添加
      </el-button>
    </div>
    <div class="cardWhite">
      <el-table
        v-loading="listLoading"
        :data="list"
        element-loading-text="Loading"
        :border="border"
        fit
        highlight-current-row
      >
        <el-table-column align="left" label="序号" width="95">
          <template slot-scope="scope">{
    
    {
    
     scope.$index + 1 }}</template>
        </el-table-column>
        <el-table-column label="角色名称" align="left">
          <template slot-scope="scope">{
    
    {
    
     scope.row.name }}</template>
        </el-table-column>

        <el-table-column label="创建时间" align="left">
          <template slot-scope="scope">{
    
    {
    
     scope.row.createTime }}</template>
        </el-table-column>

        <el-table-column label="修改时间" align="left">
          <template slot-scope="scope">{
    
    {
    
     scope.row.modifyTime }}</template>
        </el-table-column>

        <el-table-column label="角色是否启用" align="left">
          <template slot-scope="scope">
            <span>{
    
    {
    
     scope.row.status == 1 ? "启用" : "禁用" }}</span>
          </template>
        </el-table-column>

        <el-table-column label="备注" align="left">
          <template slot-scope="scope">
            <span>{
    
    {
    
     scope.row.remarks }}</span>
          </template>
        </el-table-column>

        <el-table-column
          label="操作"
          align="left"
          width="180"
          class-name="small-padding fixed-width"
        >
          <template slot-scope="{ row }">
            <el-button
              type="primary"
              size="mini"
              @click="handleUpdate(row)"
              :disabled="!$checkPermission(['role_edit'])"
            >
              编辑
            </el-button>
            <el-button
              size="mini"
              type="danger"
              @click="handleDelete(row)"
              :disabled="!$checkPermission(['role_delete'])"
            >
              删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <pagination
      v-show="total > 0"
      :total="total"
      :page.sync="listQuery.current"
      :limit.sync="listQuery.size"
      @pagination="fetchData"
    />

    <el-dialog
      :title="textMap[dialogStatus]"
      :visible.sync="dialogFormVisible"
      :close-on-click-modal="false"
      width="800px"
    >
      <el-form
        ref="dataForm"
        :rules="rules"
        :model="temp"
        label-position="right"
        label-width="160px"
      >
        <el-row>
          <el-col :span="12" :pull="1">
            <el-form-item label="角色名称" prop="name">
              <el-input v-model.trim="temp.name" placeholder="请输入角色名称" />
            </el-form-item>
            <el-form-item label="角色类型" prop="systemAdmin">
              <el-select
                v-model="temp.systemAdmin"
                class="filter-item"
                placeholder="角色类型"
                style="width:100%"
              >
                <el-option key="超级管理员" label="超级管理员" :value="1" />
                <el-option key="审计员" label="审计员" :value="2" />
                <el-option key="操作员" label="操作员" :value="3" />
                <el-option key="管理员" label="管理员" :value="4" />
              </el-select>
            </el-form-item>

            <el-form-item label="角色是否启用" prop="status">
              <el-select
                v-model="temp.status"
                class="filter-item"
                placeholder="角色是否启用"
                style="width:100%"
              >
                <el-option key="启用" label="启用" :value="1" />
                <el-option key="禁用" label="禁用" :value="2" />
              </el-select>
            </el-form-item>

            <el-form-item label="备注" prop="remarks">
              <el-input v-model.trim="temp.remarks" placeholder="请输入备注" />
            </el-form-item>
          </el-col>

          <el-col :span="12" :pull="1">
            <el-form-item label="菜单目录" prop="menuList">
              <!-- :default-checked-keys="temp.menuList" -->
              <el-tree
                :data="treeData"
                show-checkbox
                :check-strictly="true"
                ref="treeRef"
                node-key="id"
                :props="defaultProps"
                :default-checked-keys="defaultCheckedKeys"
                @check="checkTree"
              >
              </el-tree>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">
          取消
        </el-button>
        <el-button
          type="primary"
          @click="dialogStatus === 'create' ? createData() : updateData()"
        >
          确定
        </el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import * as user from "@/api/datax-user";
import * as api from "@/api/datax-role.js";
import * as apiMenu from "@/api/datax-menu";

import waves from "@/directive/waves"; // waves directive
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination

export default {
    
    
  name: "User",
  components: {
    
     Pagination },
  directives: {
    
     waves },
  filters: {
    
    
    statusFilter(status) {
    
    
      const statusMap = {
    
    
        published: "success",
        draft: "gray",
        deleted: "danger"
      };
      return statusMap[status];
    }
  },
  data() {
    
    
    return {
    
    
      list: null,
      listLoading: true,
      total: 0,
      listQuery: {
    
    
        current: 1,
        size: 10,
        name: "",
        status: "",
        type: ""
      },
      roles: ["ROLE_USER", "ROLE_ADMIN"],
      dialogPluginVisible: false,
      pluginData: [],
      dialogFormVisible: false,
      dialogStatus: "",
      textMap: {
    
    
        update: "编辑角色",
        create: "创建角色"
      },
      rules: {
    
    
        name: [{
    
     required: true, message: "请输入角色名称", trigger: "blur" }],
        systemAdmin: [
          {
    
    
            required: true,
            message: "请选择角色类型",
            trigger: "change"
          }
        ],
        status: [
          {
    
     required: true, message: "请选择角色是否启用", trigger: "change" }
        ],
        remarks: [{
    
     required: false, message: "请输入备注", trigger: "blur" }],
        menuList: [
          {
    
     required: false, message: "请选择菜单列表", trigger: "change" }
        ]
      },
      temp: {
    
    
        name: "",
        systemAdmin: 1,
        status: 1,
        remarks: "",
        menuList: []
      },
      resetTemp() {
    
    
        this.temp = this.$options.data().temp;
      },
      border: window.g.borderFlag,
      selectList: [],
      treeData: [],
      defaultProps: {
    
    
        children: "childList",
        label: "name"
      },
      defaultCheckedKeys: []
    };
  },
  created() {
    
    
    this.getMenuList();
    this.fetchData();
  },
  methods: {
    
    
    getMenuList() {
    
    
      apiMenu
        .menuGetTree()
        .then(response => {
    
    
          console.log("菜单树", response);
          this.treeData = response.content;

          // this.listLoading = false;
        })
        .catch(err => {
    
    
          // this.listLoading = false;
        });
    },
    fetchData() {
    
    
      this.listLoading = true;
      api
        .roleList(this.listQuery)
        .then(response => {
    
    
          // console.log("角色列表", response);
          const {
    
     content } = response;
          this.total = content.totalResult;
          this.list = content.listpg;
          this.listLoading = false;
        })
        .catch(err => {
    
    });
    },
    handleCreate() {
    
    
      this.resetTemp();

      this.dialogStatus = "create";
      this.dialogFormVisible = true;
      this.$nextTick(() => {
    
    
        this.defaultCheckedKeys = [];
        this.$refs.treeRef.setCheckedKeys([]);
        this.$refs["dataForm"].clearValidate();
      });
    },
    createData() {
    
    
      if (this.temp.menuList.length <= 0) {
    
    
        this.$notify({
    
    
          title: "提示",
          message: "请先选择菜单后再提交",
          type: "error",
          duration: 2000
        });
        return false;
      }
      this.$refs["dataForm"].validate(valid => {
    
    
        if (valid) {
    
    
          api.roleSaveForm(this.temp).then(() => {
    
    
            this.fetchData();
            this.dialogFormVisible = false;
            this.$notify({
    
    
              title: "完成",
              message: "创建成功",
              type: "success",
              duration: 2000
            });
          });
        }
      });
    },
    handleUpdate(row) {
    
    
      // this.temp = Object.assign({}, row); // copy obj
      this.dialogStatus = "update";
      this.defaultCheckedKeys = [];

      this.dialogFormVisible = true;
      this.$nextTick(() => {
    
    
        this.$refs.treeRef.setCheckedKeys([]);
        this.$refs["dataForm"].clearValidate();
      });

      let obj = {
    
    
        id: row.id
      };
      api
        .roleDetail(obj)
        .then(res => {
    
    
          this.temp = res.content ? res.content : {
    
    };
          this.defaultCheckedKeys = res.content.menuList;
          // console.log("角色详情", this.defaultCheckedKeys);
        })
        .catch(() => {
    
    });
    },
    updateData() {
    
    
      if (this.temp.menuList.length <= 0) {
    
    
        this.$notify({
    
    
          title: "提示",
          message: "请先选择菜单后再提交",
          type: "error",
          duration: 2000
        });
        return false;
      }
      this.$refs["dataForm"].validate(valid => {
    
    
        if (valid) {
    
    
          const tempData = Object.assign({
    
    }, this.temp);
          api.roleEdit(tempData).then(() => {
    
    
            this.fetchData();
            this.dialogFormVisible = false;
            this.$notify({
    
    
              title: "完成",
              message: "编辑成功",
              type: "success",
              duration: 2000
            });
          });
        }
      });
    },
    handleDelete(row) {
    
    
      this.$confirm("确定删除这条数据吗", "提示", {
    
    
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
    
    
          api.roleDelete(row).then(response => {
    
    
            this.fetchData();
            this.$notify({
    
    
              title: "完成",
              message: "删除成功",
              type: "success",
              duration: 2000
            });
          });
        })
        .catch(() => {
    
    });
    },

    checkTree(node, data) {
    
    
      console.log("role的checkTree", node, data);
      this.temp.menuList = data.checkedKeys;
    }
  }
};
</script>

Dynamic Routing Configuration

Earlier we explained user management, menu management, and role management. These are all business codes, which is not a big problem. Now we want to log in to the system according to different roles to see different side navigation menus, and then different roles can have Different button permissions, let's learn together here. After we enter the user name and password on the login interface, after successful login, the backend will return to the front-end the menu authority set and button authority set owned by the current role. For example, I am logged in as the administrator admin account, and the menu authority has menuList: ["home ", "system", "user", "menu", "role"] The button permissions have btnList: ["user_add", "user_edit", "user_delete"] The local routing is as follows: the complete code is as
insert image description here
insert image description here
follows
insert image description here
:

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

/* Layout */
import Layout from '@/layout'
import LayoutEx from '@/layoutEx'

var showAgent = window.g.showAgent
/* Router Modules */

import toolRouter from './modules/tool'


//===固定路由===
export const constantRoutes = [
  {
    
    
    path: '/redirect',
    component: Layout,
    hidden: true,
    children: [
      {
    
    
        path: '/redirect/:path*',
        component: () => import('@/views/redirect/index'),
      },
    ],
  },
  {
    
    
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true,
  },
  {
    
    
    path: '/auth-redirect',
    component: () => import('@/views/login/auth-redirect'),
    hidden: true,
  },
  {
    
    
    path: '/404',
    component: () => import('@/views/error-page/404'),
    hidden: true,
  },
  {
    
    
    path: '/401',
    component: () => import('@/views/error-page/401'),
    hidden: true,
  },
  {
    
    
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [
      // {
    
    
      //   path: 'dashboard',
      //   component: () => import('@/views/dashboard/admin/index'),
      //   name: '首 页',
      //   meta: { title: '首页', icon: 'el-icon-s-home', affix: true }
      // },
      {
    
    
        path: 'dashboard',
        component: () => import('@/views/homePage/index'),
        // name: '首 页',
        name: 'HomePage',
        meta: {
    
     title: '首页', icon: 'el-icon-s-home' },
      },
    ],
  }
 
]
//===动态路由 menuName就是前端页面配置菜单里的代号,要保持一致===
export const asyncRoutes = [

  {
    
    
    path: '/datax/project',
    component: Layout,
    redirect: '/datax/project/jobProject',
    name: 'datasource',
    meta: {
    
    
      title: '任务组管理',
      icon: 'el-icon-s-grid',
      menuName: 'datasource',
    },
    children: [
      {
    
    
        path: 'jobProject',
        name: 'jobProject',
        component: () => import('@/views/datax/jobProject/index'),
        meta: {
    
    
          title: '任务组管理',
          icon: 'el-icon-s-grid',
          menuName: 'jobProject',
        },
      },
    ],
  },
  {
    
    
    path: '/datax/job',
    component: Layout,
    redirect: '/datax/job/jobInfo',
    name: 'job',
    meta: {
    
     title: '任务管理', icon: 'el-icon-set-up', menuName: 'job' },
    children: [
      {
    
    
        path: 'jobInfo',
        name: 'JobInfo',
        component: () => import('@/views/datax/jobInfo/fileJob'),
        meta: {
    
    
          title: '文件任务',
          icon: 'el-icon-set-up',
          menuName: 'JobInfo',
        },
      },
      {
    
    
        path: 'missionData',
        name: 'missionData',
        component: () => import('@/views/datax/jobInfo/dataJob'),
        meta: {
    
    
          title: '数据库任务',
          icon: 'el-icon-set-up',
          menuName: 'missionData',
        },
      },
      {
    
    
        path: 'jsonBuild',
        name: 'JsonBuild',
        hidden: true,
        component: () => import('@/views/datax/json-build/index'),
        meta: {
    
    
          title: '任务构建',
          icon: 'guide',
          noCache: false,
          menuName: 'jsonBuild',
        },
      },
      {
    
    
        path: 'jsonBuildBatch',
        name: 'JsonBuildBatch',
        hidden: true,
        component: () => import('@/views/datax/json-build-batch/index'),
        meta: {
    
    
          title: '任务批量构建',
          icon: 'batch-create',
          noCache: false,
          menuName: 'jsonBuildBatch',
        },
      },
      {
    
    
        path: 'jobTemplate',
        name: 'JobTemplate',
        hidden: true,
        component: () => import('@/views/datax/jobTemplate/index'),
        meta: {
    
    
          title: 'DataX任务模板',
          icon: 'task-tmp',
          menuName: 'jobTemplate',
        },
      },
    ],
  },
  {
    
    
    path: '/datax/datasource',
    component: Layout,
    redirect: '/datax/datasource/fileDatasource',
    name: 'datasource',
    meta: {
    
     title: '资源管理', icon: 'el-icon-files', menuName: 'datasource' },
    children: [
      {
    
    
        path: 'fileDatasource',
        name: 'fileDatasource',
        component: () => import('@/views/datax/jdbc-datasource/fileControl'),
        meta: {
    
    
          title: '文件资源',
          icon: 'el-icon-files',
          menuName: 'fileDatasource',
        },
      },
      {
    
    
        path: 'jdbcDatasource',
        name: 'JdbcDatasource',
        component: () => import('@/views/datax/jdbc-datasource/dataControl'),
        meta: {
    
    
          title: '数据库资源',
          icon: 'el-icon-files',
          menuName: 'jdbcDatasource',
        },
      },
    ],
  },
  {
    
    
    path: '/datax/jobLog',
    component: Layout,
    redirect: '/datax/jobLog/jobLog',
    name: 'log',

    meta: {
    
     title: '日志管理', icon: 'el-icon-date', menuName: 'log' },
    children: [
      {
    
    
        path: 'jobLog',
        name: 'JobLog',
        component: () => import('@/views/datax/jobLog/index'),
        meta: {
    
    
          title: '业务日志管理',
          icon: 'el-icon-date',
          menuName: 'JobLog',
        },
      },
      {
    
    
        path: 'auditLog',
        name: 'auditLog',
        component: () => import('@/views/datax/jobLog/auditLog'),
        meta: {
    
    
          title: '审计日志管理',
          icon: 'el-icon-date',
          menuName: 'auditLog',
        },
      },

      {
    
    
        path: 'normalLog',
        name: 'normalLog',
        component: () => import('@/views/datax/jobLog/normalLog'),
        meta: {
    
     title: '日志', icon: 'el-icon-date', menuName: 'normalLog' },
      },
    ],
  },
  {
    
    
    path: '/datax/executor',
    component: Layout,
    redirect: '/datax/executor/executor',
    name: 'executor',
    meta: {
    
    
      title: '链路管理',
      icon: 'el-icon-set-up',
      menuName: 'executorManage',
    },
    children: [
      {
    
    
        path: 'executor',
        name: 'Executor',
        component: () => import('@/views/datax/executor/index'),
        // meta: { title: '链路管理', icon: 'exe-cfg' },
        meta: {
    
    
          title: '链路管理',
          icon: 'el-icon-set-up',
          menuName: 'Executor',
        },
      },
    ],
  },
  {
    
    
    path: '/service/exchangeTask',
    component: Layout,
    redirect: '/service/exchangeTask/index',
    name: 'exchangeTask',

    meta: {
    
    
      title: '服务请求交换管理',
      icon: 'el-icon-date',
      menuName: 'exchangeTaskManage',
    },
    children: [
      {
    
    
        path: 'exchangeTask',
        name: 'exchangeTask',
        component: () => import('@/views/service/exchangeTask/index'),
        meta: {
    
    
          title: '交换任务管理',
          icon: 'el-icon-date',
          menuName: 'exchangeTask',
        },
      },
      {
    
    
        path: 'exchangeLog',
        name: 'exchangeLog',
        component: () => import('@/views/service/exchangeLog/index'),
        meta: {
    
    
          title: '交换日志管理',
          icon: 'el-icon-date',
          menuName: 'exchangeLog',
        },
      },

      {
    
    
        path: 'resourcesManage',
        name: 'resourcesManage',
        component: () => import('@/views/service/resourcesManage/index'),
        meta: {
    
    
          title: '资源组管理',
          icon: 'el-icon-date',
          menuName: 'resourcesManage',
        },
      },
      {
    
    
        path: 'visitManage',
        name: 'visitManage',
        component: () => import('@/views/service/visitManage/index'),
        meta: {
    
    
          title: '访问组管理',
          icon: 'el-icon-date',
          menuName: 'visitManage',
        },
      },
      {
    
    
        path: 'limitManage',
        name: 'limitManage',
        component: () => import('@/views/service/limitManage/index'),
        meta: {
    
    
          title: '限制组管理',
          icon: 'el-icon-date',
          menuName: 'limitManage',
        },
      },
      {
    
    
        path: 'boundaryManage',
        name: 'boundaryManage',
        component: () => import('@/views/service/boundaryManage/index'),
        meta: {
    
    
          title: '边界地址管理',
          icon: 'el-icon-date',
          menuName: 'boundaryManage',
        },
      },
    ],
  },

  {
    
    
    path: '/datax/registry',
    component: Layout,
    redirect: '/datax/registry/registry',
    name: 'registry',
    hidden: true,
    meta: {
    
     title: '资源监控', icon: 'work', menuName: 'registryManage' },
    children: [
      {
    
    
        path: 'registry',
        name: 'Registry',
        component: () => import('@/views/datax/registry/index'),
        meta: {
    
     title: '资源监控', icon: 'battery-line', menuName: 'registry' },
      },
    ],
  },
  {
    
    
    path: '/system',
    component: Layout,
    redirect: '/system/user/index',

    meta: {
    
     title: '用户中心', icon: 'el-icon-date', menuName: 'system' },
    children: [
      {
    
    
        path: '/user',
        name: 'user',
        component: () => import('@/views/system/user/index'),
        meta: {
    
     title: '用户管理', icon: 'el-icon-s-custom', menuName: 'user' },
      },
      {
    
    
        path: 'menu',
        name: 'menu',
        component: () => import('@/views/system/menu/index'),
        meta: {
    
     title: '菜单管理', icon: 'el-icon-menu', menuName: 'menu' },
      },
      {
    
    
        path: 'role',
        name: 'role',
        component: () => import('@/views/system/role/index'),
        meta: {
    
     title: '角色管理', icon: 'el-icon-menu', menuName: 'role' },
      },
      {
    
    
        path: 'personal',
        name: 'personal',
        hidden: true,
        component: () => import('@/views/system/personal/index'),
        meta: {
    
     title: '个人中心', icon: 'el-icon-menu', menuName: 'personal' },
      },
    ],
  },

 

  {
    
     path: '*', redirect: '/404', hidden: true },
]

const createRouter = () =>
  new Router({
    
    
    // mode: 'history', // require service support
    scrollBehavior: () => ({
    
     y: 0 }),
    routes: constantRoutes.concat(asyncRoutes),
  })

const router = createRouter()

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
    
    
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export default router

Because my login method is written in the store, after the login is successful, I will cache some data locally, for example, I cache the user name and user id here, and then change the token and name in the state and the permissions of the current role through the commit method Collect roles, generate an accessible routing table through dispatch and trigger the asynchronous method generateRoutesMe in the actions under the permission module. In the method generateRoutesMe, another method filterAsyncRoutes is used to process local routes. If the menu permission list set menuList is related to the local If the menuName in the route is consistent, set its hidden to false, indicating that the menu is displayed and has permission, otherwise it is set to true without permission and will not be displayed. The button permission is much simpler. After getting the button permission set btnList, the button of the module is processed through a global public method check Permission and passed the specified code parameter. This parameter is the code we configured on the page. We set the button button Its permission has two effects. If there is no permission, it cannot be clicked, or it will not be displayed without permission. The code is: disabled = "! checkPermission and pass the specified code parameter to process. This parameter is the code we configured on the page. We set the permissions on the button button, and there are two effects to display. If there is no permission, it cannot be clicked, or it will not be displayed without permission. The code is: disabled="!c h ec k P er miss i o n and pass the specified code parameter to process. This parameter is the code we configured on the page. We set the authority for the button b u tt o n , and there are two effects. If there is no Permissions cannot be clicked, or if there is no permission, it will not be displayed directly. The code is:disabled=" ! checkPermission(['user_add'])" or v-show="!$checkPermission(['user_add'])". This is the idea of ​​menu permissions and button permissions. Paste the code below:
Encapsulate the global public method checkPermission in permission.js under the utils directory, then import it into main.js and mount it on the prototype, so that it can be used globally, as follows Figure:
insert image description hereinsert image description here
The code is as follows:

//=====utils目录下的permission.js里=====
import store from '@/store'

/**
 * @param {Array} value
 * @returns {Boolean}
 * @example see @/views/permission/directive.vue
 */
export default function checkPermission(value) {
    
    
  if (value && value instanceof Array && value.length > 0) {
    
    
    const roles = store.getters && store.getters.roles
    const permissionRoles = value
    // console.log('验证按钮权限', store, roles, permissionRoles)
    const hasPermission = roles.some((role) => {
    
    
      return permissionRoles.includes(role)
    })

    if (!hasPermission) {
    
    
      return false
    } else {
    
    
      return true
    }
  } else {
    
    
    console.error(`need roles! Like v-permission="['admin','editor']"`)
    return false
  }
}

//=========main.js里=========
//将验证按钮权限的方法挂载到this以便全局使用
import checkPermission from './utils/permission.js'
Vue.prototype.$checkPermission = checkPermission


The index.js code in the store directory
is as follows:
insert image description here

//================store目录下的getters.js代码如下:================
const getters = {
    
    
  sidebar: (state) => state.app.sidebar,
  size: (state) => state.app.size,
  device: (state) => state.app.device,
  visitedViews: (state) => state.tagsView.visitedViews,
  cachedViews: (state) => state.tagsView.cachedViews,
  token: (state) => state.user.token,
  avatar: (state) => state.user.avatar,
  name: (state) => state.user.name,
  introduction: (state) => state.user.introduction,
  roles: (state) => state.user.roles,
  permission_routes: (state) => state.permission.routes,
  addRoutes: (state) => state.permission.addRoutes,
  ifchange: (state) => state.permission.ifchange,
  errorLogs: (state) => state.errorLog.logs,
}
export default getters

//========store目录下的modules里的user.js代码如下:===============
import {
    
     login, logout } from '@/api/user'
import {
    
     menuGetTree } from '@/api/datax-menu'
import {
    
     getToken, setToken, removeToken } from '@/utils/auth'
import router, {
    
     resetRouter } from '@/router'
import store from '../index.js'

const state = {
    
    
  token: getToken(),
  name: '',
  avatar: '',
  introduction: '',
  roles: [],
}

const mutations = {
    
    
  SET_TOKEN: (state, token) => {
    
    
    // console.log('SET_TOKEN', token)
    state.token = token
  },
  SET_INTRODUCTION: (state, introduction) => {
    
    
    state.introduction = introduction
  },
  SET_NAME: (state, name) => {
    
    
    state.name = name
  },
  SET_AVATAR: (state, avatar) => {
    
    
    state.avatar = avatar
  },
  SET_ROLES: (state, roles) => {
    
    
    state.roles = roles
  },
}

const actions = {
    
    
  // user login
  login({
     
      commit }, userInfo) {
    
    
    const {
    
     username, password, code } = userInfo

    return new Promise((resolve, reject) => {
    
    
      login({
    
    
        username: username.trim(),
        password: password,
        // rememberMe: 1,
        code: code,
      })
        .then(async (response) => {
    
    
          console.log('登录进来', response)
          const {
    
     data } = response.content
          const {
    
     roles } = response.content
          commit('SET_TOKEN', response.content.token)
          commit('SET_NAME', response.content.username)
          sessionStorage.setItem('name', response.content.username)

          if (roles) {
    
    
            localStorage.setItem('roles', JSON.stringify(roles))
          }

          setToken(response.content.token)

          //缓存当前角色菜单树
          // sessionStorage.setItem('menuList', response.content.menuList)

          //缓存当前角色拥有的按钮权限集合
          commit('SET_ROLES', response.content.btnList)

          let menuIdArr = response.content.menuList

          //生成可访问的路由表
          const accessRoutes = await store.dispatch(
            'permission/generateRoutesMe',
            menuIdArr,
          )

          // console.log('user的accessRoutes', accessRoutes)
          // store.commit('permission/SET_ROUTES', accessRoutes)

          //缓存修改密码的id
          localStorage.setItem('userId', JSON.stringify(response.content.id))

          resolve()
        })
        .catch((error) => {
    
    
          reject(error)
        })
    })
  },

  // get user info
  getInfo({
     
      commit, state }) {
    
    
    return new Promise((resolve, reject) => {
    
    
      const data = {
    
    }

      try {
    
    
        if (localStorage.getItem('roles')) {
    
    
          data.roles = JSON.parse(localStorage.getItem('roles'))
        }
      } catch (err) {
    
    }

      // console.log('data.roles123', data.roles)
      commit('SET_ROLES', data.roles)
      resolve(data)
    })
  },

  // user logout
  logout({
     
      commit, state }) {
    
    
    return new Promise((resolve, reject) => {
    
    
      logout({
    
    
        username: sessionStorage.getItem('name'),
      })
        .then(() => {
    
    
          commit('SET_TOKEN', '')
          commit('SET_ROLES', [])
          commit('SET_NAME', '')
          removeToken()
          resetRouter()
          resolve()
        })
        .catch((error) => {
    
    
          reject(error)
        })
    })
  },

  // remove token
  resetToken({
     
      commit }) {
    
    
    return new Promise((resolve) => {
    
    
      commit('SET_TOKEN', '')
      commit('SET_ROLES', [])

      removeToken()
      resolve()
    })
  },

  // dynamically modify permissions
  changeRoles({
     
      commit, dispatch }, role) {
    
    
    return new Promise(async (resolve) => {
    
    
      const token = role + '-token'

      commit('SET_TOKEN', token)
      setToken(token)

      const {
    
     roles } = await dispatch('getInfo')

      resetRouter()

      // generate accessible routes map based on roles
      const accessRoutes = await dispatch('permission/generateRoutes', roles, {
    
    
        root: true,
      })

      // dynamically add accessible routes
      router.addRoutes(accessRoutes)

      // reset visited views and cached views
      dispatch('tagsView/delAllViews', null, {
    
     root: true })

      resolve()
    })
  },
}

export default {
    
    
  namespaced: true,
  state,
  mutations,
  actions,
}

//========store目录下的modules里的permission.js代码如下:===============
import {
    
     asyncRoutes, constantRoutes } from '@/router'
import router from '../../router'
import Layout from '@/layout'

/**
 * Use meta.role to determine if the current user has permission
 * @param roles
 * @param route
 */
function hasPermission(roles, route) {
    
    
  // console.log('hasPermission里', roles, route)
  if (route.meta && route.meta.roles) {
    
    
    if (roles) {
    
    
      return roles.some((role) => route.meta.roles.includes(role))
    } else {
    
    
      return true
    }
  } else {
    
    
    return true
  }
}

/**
 * Filter asynchronous routing tables by recursion
 * @param routes asyncRoutes
 * @param roles
 */
export function filterAsyncRoutes(routes, roles, menuIdArr) {
    
    
  const res = []

  // console.log('filterAsyncRoutes里', routes, roles, menuIdArr)

  routes.forEach((route) => {
    
    
    const tmp = {
    
     ...route }
    if (hasPermission(roles, tmp)) {
    
    
      if (tmp.children) {
    
    
        tmp.children = filterAsyncRoutes(tmp.children, roles)
      }
      res.push(tmp)
    } else {
    
    
      res = routes
    }
  })

  return res
}

export function filterAsyncRoutesMe(routes, menuIdArr) {
    
    
  // console.log(
  //   'filterAsyncRoutesMe里',
  //   routes,
  //   menuIdArr,
  //   Object.prototype.toString.call(menuIdArr),
  // )

  if (Object.prototype.toString.call(menuIdArr) == '[object String]') {
    
    
    menuIdArr = menuIdArr.split(',')
  }
  let data
  var findRoute = function (arr) {
    
    
    data = arr.map((item) => {
    
    
      // console.log('filterAsyncRoutesMe', item)
      let myItem = {
    
    
        ...item,
        hidden:
          (item.meta &&
            Array.isArray(menuIdArr) &&
            menuIdArr.length > 0 &&
            menuIdArr.some((i) => i == item.meta.menuName)) ||
          !item.hasOwnProperty('hidden') ||
          !item.hidden
            ? false
            : true,
        children:
          item.children && item.children.length > 0
            ? findRoute(item.children)
            : [],
      }

      return {
    
    
        ...myItem,
      }
    })

    return data
  }

  let finallyRoutes = findRoute(routes)
  // console.log('finallyRoutes', finallyRoutes)

  return finallyRoutes
}

// const state = {
    
    
//   routes: [],
//   addRoutes: [],
//   ifchange: false,
// }

const state = {
    
    
  routes: constantRoutes,
  addRoutes: [],
  ifchange: false,
}

const mutations = {
    
    
  SET_ROUTES: (state, routes) => {
    
    
    // state.routes = []
    state.addRoutes = routes
    state.routes = constantRoutes.concat(routes)
    // state.routes = [...constantRoutes, ...routes]
    // console.log('pe132321', state.routes)
    // router.addRoutes(routes)
    state.ifchange = true
  },
}

const actions = {
    
    
  generateRoutes({
     
      commit }, roles, menuIdArr) {
    
    
    return new Promise((resolve) => {
    
    
      let accessedRoutes
      // console.log('generateRoutes里', asyncRoutes, roles, menuIdArr)

      if (roles && roles.includes('ROLE_ADMIN')) {
    
    
        accessedRoutes = asyncRoutes || []
      } else {
    
    
        // accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
        let myRoutes = filterAsyncRoutes(asyncRoutes, roles, menuIdArr)
        // console.log('myRoutes', myRoutes)
        accessedRoutes = myRoutes
      }
      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  },

  generateRoutesMe({
     
      commit }, menuIdArr) {
    
    
    return new Promise((resolve) => {
    
    
      let accessedRoutes = filterAsyncRoutesMe(asyncRoutes, menuIdArr)

      // console.log('generateRoutesMe里', asyncRoutes, menuIdArr,accessedRoutes)

      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  },
}

export default {
    
    
  namespaced: true,
  state,
  mutations,
  actions,
}

Then one of the problems I encountered at that time was that there was an infinite loop in routing. That was because the exit next of router.beforeEach was not written correctly. My previous codes were all commented as follows:
insert image description here

import router from './router'
import store from './store'
import {
    
     Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import {
    
     getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'

NProgress.configure({
    
     showSpinner: false }) // NProgress Configuration

const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist

router.beforeEach(async (to, from, next) => {
    
    
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()
  if (hasToken) {
    
    
    if (to.path === '/login') {
    
    
      // if is logged in, redirect to the home page
      next({
    
     path: '/' })
      NProgress.done()
    } else {
    
    
      const hasRoles = store.getters.roles && store.getters.roles.length > 0
      // console.log(
      //   'hasRoles看看',
      //   hasRoles,
      //   store,
      //   store.getters.addRoutes,
      //   store.getters.permission_routes,
      //   JSON.parse(localStorage.getItem('MenuPrmStore')),
      // )
      if (hasRoles) {
    
    
        next()
      } else {
    
    
        try {
    
    
          //拉取info信息
          // const { roles } = await store.dispatch('user/getInfo')
          //获取当前角色所拥有的菜单

          // let menuIdArr = await sessionStorage.getItem('menuList')

          // //生成可访问的路由表
          // const accessRoutes = await store.dispatch(
          //   'permission/generateRoutesMe',
          //   menuIdArr,
          // )

          next()

          // console.log('roles4444', menuIdArr, accessRoutes)

          // if (
          //   store.getters.permission_routes.length > 0 ||
          //   to.name != null ||
          //   store.getters.addRoutes.length > 0
          // ) {
    
    
          //   //放行

          //   next()
          // } else {
    
    
          //   //动态添加可访问路由表
          //   store.commit('SET_ROUTES', accessRoutes)
          //   router.addRoutes(accessRoutes)
          //   // next({ ...to, replace: true })

          //   // for (let i = 0; i < accessRoutes.length; i += 1) {
    
    
          //   //   const element = accessRoutes[i]
          //   //   router.addRoute(element)
          //   // }
          //   // router.options.isAddAsyncMenuData = true

          //   next({ ...to, replace: true })
          // }

          // if (!store.getters.ifchange) {
    
    
          //   //动态添加可访问路由表
          //   router.addRoutes(accessRoutes)
          //   // store.commit('SET_ROUTES', accessRoutes)

          //   next({ ...to, replace: true })
          // } else {
    
    
          //   next()
          // }

             //=====直接下面这样addRoutes会死循环=====
          // router.addRoutes(accessRoutes)
          // next()

          // hack method to ensure that addRoutes is complete
          // set the replace: true, so the navigation will not leave a history record
        } catch (error) {
    
    
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')

          // Message.error(error || 'Has Error')
          Message.error({
    
     message: error || 'Has Error' })

          next(`/login?redirect=${
      
      to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    
    
    /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {
    
    
      // in the free login whitelist, go directly
      next()
    } else {
    
    
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${
      
      to.path}`)
      NProgress.done()
    }
  }
})

router.afterEach(() => {
    
    
  // finish progress bar
  NProgress.done()
})

I had an infinite loop here at the time because I directly used router.addRoutes(accessRoutes) at the beginning and then next( ) to let go. Finally, the browser crashed, and then I tried to judge the length of permission_routes. If it is greater than 0, it means addRoutes once. Direct next( ) release, otherwise, first traverse accessRoutes and then add one by one or directly inject at one time, the result is not enough, then I try to define a variable ifchange in the state, if it is false, accessRoutes and then next({ ...to , replace: true }), otherwise it will be released by next(). In fact, it is similar to my method of judging the length of permission_routes, but the end result is that either no route can be found, or an endless loop. Later, I found out that I did not write the correct route when registering the route. The code is as follows:
insert image description here
I should concat the dynamic route asyncRoutes when registering the route. Here it was written as fixed route routes: constantRoutes, which is wrong. The correct one is routes: constantRoutes.concat(asyncRoutes)

Solve the problem of data loss in the store after refreshing the page

When the page is refreshed, the vue instance is reloaded, so the store is also reset. store is used to store component state, not for local data storage. Therefore, for data that you do not want to be reset after the page is refreshed, use local storage for storage. For example, in this example, as soon as I refresh the page, the menu and role data in my store will be lost and the page will be blank. I directly add an event beforeunload to monitor page refresh in App.vue, and the beforeunload event is on the page Trigger before refreshing, which gives us time to cache the data in the store, and then judge whether there is data in the cache, and change the data in the state in the store if there is data, the code is as follows:
insert image description here

<template>
  <div id="app">
    <router-view />
  </div>
</template>

<script>
import store from "./store";
export default {
    
    
  name: "App",
  mounted() {
    
    
    var that = this;
    window.onresize = function() {
    
    
      that.$EventBus.$emit("resize");
    };
  },
  created() {
    
    
    this.refresh();
  },
  methods: {
    
    
    //刷新时重新用本地缓存的路由替换之前router里的路由

    refresh() {
    
    
      // console.log(
      //   "store去去去",
      //   store,
      //   JSON.parse(localStorage.getItem("MenuPrmStore"))
      // );
      // console.log("store.state", store.state);

      try {
    
    
        if (localStorage.getItem("MenuPrmStore")) {
    
    
          store.commit(
            "permission/SET_ROUTES",
            JSON.parse(localStorage.getItem("MenuPrmStore"))
          );
        }

        if (localStorage.getItem("roleList")) {
    
    
          store.commit(
            "user/SET_ROLES",
            JSON.parse(localStorage.getItem("roleList"))
          );
        }
      } catch (e) {
    
    
        console.log("刷新出错", e);
      }

      // console.log(
      //   "目前store.state.permission.routes",
      //   store.state.permission.routes
      // );
      // }
      // 在页面刷新时将vuex里的信息保存到localStorage里
      // beforeunload事件在页面刷新之前先触发
      window.addEventListener("beforeunload", () => {
    
    
        //存菜单列表

        localStorage.setItem(
          "MenuPrmStore",
          JSON.stringify(store.state.permission.addRoutes)
        );

        //存角色权限列表
        localStorage.setItem(
          "roleList",
          JSON.stringify(store.state.user.roles)
        );
      });
    }
  }
};
</script>

Guess you like

Origin blog.csdn.net/qq_37635012/article/details/127786033