Vue 后臺(tái)管理項(xiàng)目13-權(quán)限管理實(shí)現(xiàn)

權(quán)限管理實(shí)現(xiàn)

1.角色列表頁

1.1 完成roles組件靜態(tài)布局
Elemenet組件 Table 表格 展開行:
通過設(shè)置 type="expand" 和 Scoped slot 可以開啟展開行功能,el-table-column 的模板會(huì)被渲染成為展開行的內(nèi)容,展開行可訪問的屬性與使用自定義列模板時(shí)的 Scoped slot 相同。
傳送門http://element-cn.eleme.io/#/zh-CN/component/table

Elemenet組件 Tag 標(biāo)簽 可移除標(biāo)簽 :
傳送們http://element-cn.eleme.io/#/zh-CN/component/tag

//直接復(fù)制user組件,重命名roles.vue,設(shè)置router.js,roles.vue組件demo
<template>
  <div id="user">
    <!-- 頂級(jí)面包屑 -->
    <el-row>
      <el-col :span="24">
        <breadcrumb :level2="level2" :level3="level3"></breadcrumb>
      </el-col>
    </el-row>
    <!-- 操縱框 -->
    <el-row class="operate">
      <el-col :span="24">
        <el-button type="primary" plain @click="visible=true">添加角色</el-button>
      </el-col>
    </el-row>
    <!-- 用戶數(shù)據(jù) -->
    <el-row>
      <el-col :sapn="24">
        <el-table :data="userList" style="width: 100%" border>
          <!-- 展開的table -->
          <el-table-column type="expand">
            <!-- 模板 -->
            <template slot-scope="props">
              <!-- {{props.row.children}} -->
              <!-- 生成tag標(biāo)簽 -->
              <!-- <el-tag closable>測(cè)試</el-tag> -->

              <!-- 生成最左邊的一級(jí)菜單 -->
              <el-row v-for="item in props.row.children" :key="item.id">
                <el-col :span="4">
                  <el-tag closable>{{item.authName}}</el-tag>
                  <!-- 小箭頭 -->
                  <i class="el-icon-arrow-right"></i>
                </el-col>
                <el-col :span="20">
                  <!-- 二級(jí)菜單 需要當(dāng)度占一行 用row嵌套即可-->
                  <el-row v-for="level2 in item.children" :key="level2.id">
                    <el-col :span="4">
                      <el-tag closable type="success">{{level2.authName}}</el-tag>
                      <!-- 小箭頭 -->
                      <i class="el-icon-arrow-right"></i>
                    </el-col>
                    <el-col :span="20">
                      <el-tag closable  v-for="level3 in level2.children" :key="level3.id" type="warning">{{level3.authName}}</el-tag>
                      <!-- 小箭頭 -->
                      <i class="el-icon-arrow-right"></i>
                    </el-col>
                  </el-row>
                </el-col>
              </el-row>
              <el-row v-if="props.row.children.length==0">
                <el-col :span="24">沒有分配權(quán)限</el-col>
              </el-row>
            </template>
          </el-table-column>
          <!-- 返回的數(shù)據(jù)沒有對(duì)應(yīng)的屬性名,把prop刪掉 -->
          <!-- 增加type="index",會(huì)設(shè)置排序 -->
          <el-table-column label="#" width="30" type="index"></el-table-column>
          <el-table-column prop="roleName" label="角色名稱" width="180"></el-table-column>
          <el-table-column prop="roleDesc" label="角色描述" width="300"></el-table-column>
          <el-table-column label="操作">
            <template slot-scope="scope">
              <el-button type="primary" plain size="mini" icon="el-icon-edit"></el-button>
              <el-button type="danger" plain size="mini" icon="el-icon-check"></el-button>
              <el-button type="warning" plain size="mini" icon="el-icon-delete"></el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-col>
    </el-row>
  </div>
</template>
<script>
export default {
  //寫了name方便在Vue Devtools谷歌插件應(yīng)用內(nèi)找到對(duì)應(yīng)的組件
  name: "user",
  data() {
    return {
      level2: "權(quán)限管理",
      level3: "角色列表",
      //用戶的數(shù)據(jù)
      userList: []
    };
  },
  methods: {},
  //生命周期函數(shù),回調(diào)函數(shù)
  async created() {
    let res = await this.$axios.get("roles");
    console.log(res);
    this.userList = res.data.data;
  }
};
</script>
<style lang="scss">
#user {
  .operate {
    background-color: #e8edf3;
  }
  .el-dialog {
    width: 30%;
  }
}
</style>

難點(diǎn):餓了嗎組件 柵格布局

效果預(yù)覽

1.2 完成roles組件動(dòng)態(tài)交互


Ⅰ. 添加角色:同user組件類似(完整代碼在頁面底部)

代碼邏輯同user組件差不多,由于顯示狀態(tài)碼201之前沒在axios攔截器上設(shè)置,所以修改vue-axios.js


//原先的代碼
<script>
if(response.data.meta.status===200){
    //成功,提示返回的信息
    Vue.prototype.$message.success(response.data.meta.msg);
  }else if(response.data.meta.status===400){
    //失敗,提示返回的信息
    Vue.prototype.$message.error(response.data.meta.msg);
  }
</script>

//修改后代碼
<script>
  //if(response.data.meta.status===200){
  //便捷寫法,indexOf判斷響應(yīng)的狀態(tài)碼是否存在
  if([200,201].indexOf(response.data.meta.status)){
    //成功,提示返回的信息
    Vue.prototype.$message.success(response.data.meta.msg);
  }else if(response.data.meta.status===400){
    //失敗,提示返回的信息
    Vue.prototype.$message.error(response.data.meta.msg);
  }
</script>

Ⅱ. 刪除角色:同user組件類似(完整代碼在頁面底部)

Ⅲ. 編輯角色:同user組件類似(完整代碼在頁面底部)

Ⅳ. 權(quán)限分配:

Elemenet組件 Tree 樹形控件 默認(rèn)展開和默認(rèn)選中:
傳送門http://element-cn.eleme.io/#/zh-CN/component/tree

常用 作用
1.default-expand-all 是否默認(rèn)展開所有節(jié)點(diǎn),默認(rèn)為false
2.default-checked-keys 默認(rèn)勾選的節(jié)點(diǎn)的 key 的數(shù)組
3.node-key 每個(gè)樹節(jié)點(diǎn)用來作為唯一標(biāo)識(shí)的屬性,整棵樹應(yīng)該是唯一的
4.ref="tree" 獲取和設(shè)置選中節(jié)點(diǎn)

Ⅴ. 刪除單個(gè) Tag 標(biāo)簽 權(quán)限

Elemenet組件 Tag 標(biāo)簽 事件 close,表示關(guān)閉 Tag 時(shí)觸發(fā)的事件

@close="delCurrentTag(當(dāng)前角色,當(dāng)前權(quán)限)"

VI. 子組件修改權(quán)限后,父組件菜單欄不同步更新

解決方法 局限性
1.window.location.reload() 畫面閃爍效果不好
2.$emit子組件向父組件通信 代碼比方法1多,效果好,詳情看Vue 后臺(tái)管理項(xiàng)目11-Vue中的通信傳值
Snipaste_2019-04-09_12-41-27.png
//完整roles組件代碼
<template>
  <div id="roles">
    <!-- 頂級(jí)面包屑 -->
    <el-row>
      <el-col :span="24">
        <breadcrumb :level2="level2" :level3="level3"></breadcrumb>
      </el-col>
    </el-row>
    <!-- 操縱框 -->
    <el-row class="operate">
      <el-col :span="24">
        <el-button type="primary" plain @click="addVistable=true">添加角色</el-button>
      </el-col>
    </el-row>
    <!-- 用戶數(shù)據(jù) -->
    <el-row>
      <el-col :sapn="24">
        <el-table :data="rolesList" style="width: 100%" border>
          <!-- 展開的table -->
          <el-table-column type="expand">
            <!-- 模板 -->
            <template slot-scope="props">
              <!-- {{props.row.children}} -->
              <!-- 生成tag標(biāo)簽 -->
              <!-- <el-tag closable>測(cè)試</el-tag> -->

              <!-- 生成最左邊的一級(jí)菜單 -->
              <el-row v-for="item in props.row.children" :key="item.id">
                <el-col :span="4">
                  <el-tag closable @close="delCurrentTag(props.row,item)">{{item.authName}}</el-tag>
                  <!-- 小箭頭 -->
                  <i class="el-icon-arrow-right"></i>
                </el-col>
                <el-col :span="20">
                  <!-- 二級(jí)菜單 需要當(dāng)度占一行 用row嵌套即可-->
                  <el-row v-for="level2 in item.children" :key="level2.id">
                    <el-col :span="4">
                      <el-tag closable @close="delCurrentTag(props.row,level2)" type="success">{{level2.authName}}</el-tag>
                      <!-- 小箭頭 -->
                      <i class="el-icon-arrow-right"></i>
                    </el-col>
                    <el-col :span="20">
                      <el-tag closable @close="delCurrentTag(props.row,level3)" v-for="level3 in level2.children" :key="level3.id" type="warning">{{level3.authName}}</el-tag>
                      <!-- 小箭頭 -->
                      <i class="el-icon-arrow-right"></i>
                    </el-col>
                  </el-row>
                </el-col>
              </el-row>
              <el-row v-if="props.row.children.length==0">
                <el-col :span="24">沒有分配權(quán)限</el-col>
              </el-row>
            </template>
          </el-table-column>
          <!-- 返回的數(shù)據(jù)沒有對(duì)應(yīng)的屬性名,把prop刪掉 -->
          <!-- 增加type="index",會(huì)設(shè)置排序 -->
          <el-table-column label="#" width="40" type="index"></el-table-column>
          <el-table-column prop="roleName" label="角色名稱" width="180"></el-table-column>
          <el-table-column prop="roleDesc" label="角色描述" width="300"></el-table-column>
          <el-table-column label="操作">
            <template slot-scope="scope">
              <el-button type="primary" @click="showEditDialog(scope.row)" plain size="mini" icon="el-icon-edit"></el-button>
              <el-button type="danger" @click="delOne(scope.row)" plain size="mini" icon="el-icon-delete"></el-button>
              <el-button type="warning" plain size="mini" icon="el-icon-check" @click="showRolesDialog(scope.row)"></el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-col>
    </el-row>
    <!-- 添加角色的對(duì)話框 -->
    <el-dialog title="添加角色" :visible.sync="addVistable">
      <!-- label-position控制label名的顯示位置,注意要設(shè)置label-width才能生效 -->
      <!-- 表單數(shù)據(jù)驗(yàn)證要加form上添加:rules="rules"屬性 -->
      <!-- 表單提交驗(yàn)證要加ref="userForm"屬性,并將userForm傳給提交按鈕 -->
      <el-form :model="addForm" :rules="rules" ref="addForm" label-position="left" label-width="80px">
        <el-form-item label="角色名稱" prop="roleName">
          <el-input v-model="addForm.roleName" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="角色描述" prop="roleDesc">
          <el-input v-model="addForm.roleDesc" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="addVistable = false">取 消</el-button>
        <!-- 記住這邊的userForm要加單引號(hào) -->
        <el-button type="primary" @click="submitForm('addForm')">確 定</el-button>
      </div>
    </el-dialog>
    <!-- 編輯角色的對(duì)話框 -->
    <el-dialog title="編輯角色" :visible.sync="editVistable">
      <!-- 這里不能用addForm,因?yàn)閍ddForm默認(rèn)是空,而編輯點(diǎn)誰就有 -->
      <el-form :model="editForm" :rules="rules" ref="editForm" label-position="left" label-width="80px">
        <el-form-item label="角色名稱" prop="roleName">
          <el-input v-model="editForm.roleName" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="角色描述" prop="roleDesc">
          <el-input v-model="editForm.roleDesc" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="editVistable = false">取 消</el-button>
        <!-- 記住這邊的userForm要加單引號(hào) -->
        <el-button type="primary" @click="submitEdit('editForm')">確 定</el-button>
      </div>
    </el-dialog>
    <!-- 權(quán)限分配對(duì)話框 -->
    <el-dialog title="分配權(quán)限" :visible.sync="roleVistable">
      <!-- label-position控制label名的顯示位置,注意要設(shè)置label-width才能生效 -->
      <!-- 表單數(shù)據(jù)驗(yàn)證要加form上添加:rules="rules"屬性 -->
      <!-- 表單提交驗(yàn)證要加ref="userForm"屬性,并將userForm傳給提交按鈕 -->
      <el-row>
        <el-col :span="24">
          <!-- 樹形結(jié)構(gòu) -->
          <el-tree
            :data="totalRoles"
            show-checkbox
            node-key="id"
            :default-checked-keys="checkedKeys"
            :props="defaultProps"
            default-expand-all
            ref="tree">
          </el-tree>
        </el-col>
      </el-row>
      <div slot="footer" class="dialog-footer">
        <el-button @click="roleVistable = false">取 消</el-button>
        <!-- 這里不是獲取from了而是要獲取樹形結(jié)構(gòu)的數(shù)據(jù) -->
        <el-button type="primary" @click="submitRoles">確 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>
<script>
export default {
  //寫了name方便在Vue Devtools谷歌插件應(yīng)用內(nèi)找到對(duì)應(yīng)的組件
  name: "roles",
  data() {
    return {
      level2: "權(quán)限管理",
      level3: "角色列表",
      //角色的數(shù)據(jù)
      rolesList: [],
      //新增框顯示標(biāo)記
      addVistable:false,
      //新增的數(shù)據(jù)
      addForm: {
        roleName:"",
        roleDesc:""
      },
      //編輯的數(shù)據(jù)
      editForm: {
        roleName:"",
        roleDesc:""
      },
      //編輯框顯示標(biāo)記
      editVistable:false,
      //權(quán)限框顯示標(biāo)記
      roleVistable:false,
      //所有的權(quán)限數(shù)據(jù)
      totalRoles:[],
      //提交權(quán)限分配需要,共享角色數(shù)據(jù)
      selectRole:{},
      //權(quán)限tree的對(duì)應(yīng)關(guān)系
      defaultProps:{
        label:'authName'
      },
      //默認(rèn)選中的字段
      checkedKeys:[],
      //表單驗(yàn)證規(guī)則
      rules: {
        roleName:[
          {required:true,message:"請(qǐng)輸入角色名",trigger:"blur"},
          {min:3,max:32,message:"長(zhǎng)度在3到32個(gè)字符",trigger:"blur"}
        ],
        roleDesc:[
          {required:true,message:"請(qǐng)輸入角色描述",trigger:"blur"},
          {min:3,max:32,message:"長(zhǎng)度在3到32個(gè)字符",trigger:"blur"}
        ]
      }
    };
  },
  methods: {
    //獲取roles數(shù)據(jù)的方法
    async getRoles() {
      //依次往下執(zhí)行
      let res = await this.$axios.get("roles");
      this.rolesList = res.data.data;
    },
    submitForm(addForm){
      this.addVistable = true;
      //直接獲取表單驗(yàn)證
      this.$refs[addForm].validate(async valid=>{
        if(valid){
          //提交數(shù)據(jù)
          let res = await this.$axios.post('roles',this.addForm)
          //關(guān)閉對(duì)話框
          this.addVistable = false;
          if(res.data.meta.status == 201) {
            //成功重新獲取數(shù)據(jù)
            this.getRoles()
          }else{
            //提示失敗,axios攔截器有了
          }
        }else {
          this.$message.error('請(qǐng)檢查數(shù)據(jù)');
          return false;
        }
      })
    },
    delOne(data){
       console.log(data);
       let id = data.id;
       //提示用戶
       this.$confirm('此操作將永久刪除這類角色,是否繼續(xù)?',"提示",{
         confirmButtonText:"確定",
         cancelButtonText:"取消",
         type:"danger"
       })
       .then(async()=>{
         //確定
         let res = await this.$axios.delete(`roles/${id}`);
         //console.log(res);
         //重新獲取用戶數(shù)據(jù)即可
         this.getRoles();
       })
       .catch(()=>{
         //取消
       })
    },
    //顯示編輯框
    showEditDialog(data){
      this.editVistable = true;
      this.editForm = data;
    },
    //保存編輯結(jié)果
    submitEdit(formName){
         this.$refs[formName].validate(async valid => {
         if (valid) {
           //驗(yàn)證成功
           //調(diào)用接口
           let res = await this.$axios.put(`roles/${this.editForm.id}`,this.editForm);
           console.log(res);
           if(res.data.meta.status===200){
           //201表示成功請(qǐng)求并創(chuàng)建了新的資源,可以繼續(xù)執(zhí)行下一步
           //關(guān)閉彈框
           this.editVistable=false;
           //重新獲取數(shù)據(jù)
           this.getRoles();
           }
         } else {
           //驗(yàn)證失敗
           this.$message.error('請(qǐng)檢查數(shù)據(jù)')
           return false;
         }
       });
    },
    //顯示權(quán)限框
    async showRolesDialog(data){
      //提交權(quán)限分配需要:保存正在編輯權(quán)限的角色數(shù)據(jù)
      this.selectRole = data;
      //顯示對(duì)話框
      this.roleVistable = true;
      //獲取所有權(quán)限列表
      let res = await this.$axios.get('rights/tree');
      console.log(res);
      //保存數(shù)據(jù)到data中
      this.totalRoles = res.data.data;
      // 每次調(diào)用前先將this.checkedKeys變?yōu)榭諗?shù)組,避免被之前的權(quán)限覆蓋
      this.checkedKeys = []
      //利用遞歸獲取所有的權(quán)限id
      let findChild = (father)=>{
        //找后代
        if(father.children){
          // console.log('有兒子');
          father.children.forEach(v=>{
            // this.checkedKeys.push(v.id)
            //每一個(gè)兒子都可能有后代
            findChild(v);
          })
        }else{
          //沒有后代
          //  console.log('沒有后代了');
          //因?yàn)閠ree這個(gè)組件的問題,如果父id設(shè)置選中,會(huì)默認(rèn)選中它的所有子節(jié)點(diǎn)
          //只需要添加最底層的即可
          this.checkedKeys.push(father.id)
        }
      }
      //調(diào)用遞歸
      // console.log(data);
      findChild(data)
    },
    //提交權(quán)限分配
    async submitRoles(){
      //獲取選中的權(quán)限對(duì)象數(shù)據(jù)
      // console.log(this.$refs.tree.getCheckedNodes());
      //獲取半選中的節(jié)點(diǎn)對(duì)象數(shù)據(jù)
      // console.log(this.$refs.tree.getHalfCheckedNodes());
      //獲取半選中的權(quán)限ID
      // console.log(this.$refs.tree.getHalfCheckedKeys());
      //獲取選中的權(quán)限ID
      // console.log(this.$refs.tree.getCheckedKeys());

      //選中的key
      let checkedKeys = this.$refs.tree.getCheckedKeys();
      //半選中的key,父節(jié)點(diǎn)的id也要獲取
      let halfCheckedKeys = this.$refs.tree.getHalfCheckedKeys();
      //兩個(gè)數(shù)組→id1,id2,id3的字符串
      //concat數(shù)組拼接方法
      //用join將數(shù)組轉(zhuǎn)換成分隔符隔開的字符串
      let totalKeys = checkedKeys.concat(halfCheckedKeys);
      let rids = totalKeys.join(',')
      console.log(rids);
      console.log(this.selectRole);
      
      let res = await this.$axios.post(`roles/${this.selectRole.id}/rights`,{
        rids
      })
      console.log(res);
      //隱藏權(quán)限框
      this.roleVistable = false;
      //重新獲取角色數(shù)據(jù)即可
      this.getRoles();

    },
    //刪除角色的指定權(quán)限
    async delCurrentTag(role,right){
      // console.log(role);
      // console.log(right);
      let res = await this.$axios.delete(`roles/${role.id}/rights/${right.id}`);
      console.log(res);
      //這邊全部重新獲取頁面數(shù)據(jù),會(huì)折疊起來,用戶體驗(yàn)不好
      // this.getRoles();

      //可以直接把服務(wù)器返回的權(quán)限賦值給當(dāng)前角色
      role.children = res.data.data;
    }
  },
  //生命周期函數(shù),回調(diào)函數(shù)
  async created() {
    this.getRoles()
  }
};
</script>
<style lang="scss">
#roles {
  .operate {
    background-color: #e8edf3;
  }
  .el-dialog {
    width: 30%;
  }
}
</style>

2.權(quán)限列表頁

直接參照之前的頁面寫,沒什么交互,效果如下:


Snipaste_2019-04-03_14-23-52.png
<template>
  <div id="user">
    <!-- 頂級(jí)面包屑 -->
    <el-row>
      <el-col :span="24">
        <breadcrumb :level2="level2" :level3="level3"></breadcrumb>
      </el-col>
    </el-row>
    <!-- 用戶數(shù)據(jù) -->
    <el-row>
      <el-col :sapn="24">
        <el-table :data="rightList" style="width: 100%" border>
          <!-- 返回的數(shù)據(jù)沒有對(duì)應(yīng)的屬性名,把prop刪掉 -->
          <!-- 增加type="index",會(huì)設(shè)置排序 -->
          <el-table-column label="#" width="40" type="index"></el-table-column>
          <el-table-column prop="authName" label="權(quán)限名稱" width="180"></el-table-column>
          <el-table-column prop="path" label="路徑" width="200"></el-table-column>
          <el-table-column prop="level" label="層級(jí)" width="80">
             <template slot-scope="scope">
                <span v-if="scope.row.level==='0'">一級(jí)</span>
                <span v-if="scope.row.level==='1'">二級(jí)</span>
                <span v-if="scope.row.level==='2'">三級(jí)</span>
            </template>
          </el-table-column>
        </el-table>
      </el-col>
    </el-row>
  </div>
</template>
<script>
export default {
  //寫了name方便在Vue Devtools谷歌插件應(yīng)用內(nèi)找到對(duì)應(yīng)的組件
  name: "user",
  data() {
    return {
      level2: "權(quán)限管理",
      level3: "權(quán)限列表",
      //權(quán)限的數(shù)據(jù)
      rightList: []
    }
  },
  methods: {
  },
  //生命周期函數(shù),回調(diào)函數(shù)
  async created() {
    //get請(qǐng)求需要通過params屬性來傳對(duì)象
    let res = await this.$axios.get("rights/list");
    console.log(res);
    this.rightList = res.data.data
    
  }
};
</script>
<style lang="scss">
#user {
  .operate {
    background-color: #e8edf3;
  }
  .el-dialog {
    width:30%;
  }
}
</style>

PS:有讀者問我要這階段寫的源碼,這里共享下百度云地址
鏈接:https://pan.baidu.com/s/1hJAZU28I2PFjueBfzd7M6g
提取碼:4zn9

本文同步發(fā)表在我的個(gè)人博客:https://www.lubaojun.com/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容