Vue 后台管理项目12-用户列表页实现

用户列表页实现

1.完成user组件静态布局

页面结构:组件盒子内分五部分,顶级面包屑(全局组件)+ 操作框 + 用户数据列表 + 底部的分页 + 用户增删改弹框(后面写动态交互再添加),都用el-row(饿了吗Layout 布局)包裹

Ⅰ.顶级面包屑的实现:参照前两章

Ⅱ.操纵框:
饿了吗组件 复合型输入框传送们http://element-cn.eleme.io/#/zh-CN/component/input
   button按钮 传送门http://element-cn.eleme.io/#/zh-CN/component/button

Ⅲ.用户数据列表:
饿了吗组件 Table表格(固定列表格) 传送门http://element-cn.eleme.io/#/zh-CN/component/table
   Switch 开关传送门http://element-cn.eleme.io/#/zh-CN/component/switch

Ⅳ.底部的分页:
饿了吗组件 Pagination 分页(完整功能)传送门http://element-cn.eleme.io/#/zh-CN/component/pagination

效果图:

示例代码

<template>
  <div id="user">
    <!-- 顶级面包屑 -->
    <el-row>
      <el-col :span="24">
        <breadcrumb :level2="level2" :level3="level3"></breadcrumb>
      </el-col>
    </el-row>
    <!-- 操纵框 -->
    <el-row class="operate">
      <el-col :span="4">
        <!-- 输入的内容最终是放在搜索里面 -->
        <el-input placeholder="请输入内容" v-model="pageData.query">
          <template slot="append">
            <i class="el-icon-search"></i>
          </template>
        </el-input>
      </el-col>
      <el-col :span="20">
        <el-button type="success" plain>添加用户</el-button>
      </el-col>
    </el-row>
    <!-- 用户数据 -->
    <el-row>
      <el-col :sapn="24">
        <el-table :data="userList" style="width: 100%" border>
          <!-- 返回的数据没有对应的属性名,把prop删掉 -->
          <!-- 增加type="index",会设置排序 -->
          <el-table-column label="#" width="30" type="index"></el-table-column>
          <el-table-column prop="username" label="姓名" width="180"></el-table-column>
          <el-table-column prop="email" label="邮箱" width="300"></el-table-column>
          <el-table-column prop="mobile" label="电话" width="300"></el-table-column>
          <el-table-column prop="mg_state" label="用户状态" width="80">
            <!-- slot-scope 废弃,已经被v-slot代替,为插槽传入 prop 的时候使用 -->
            <template slot-scope="scope">
              <el-switch
                v-model="scope.row.mg_state"
                active-color="#13ce66"
                inactive-color="#ff4949"
              ></el-switch>
            </template>
          </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>
    <!-- 底部的分页 -->
    <el-row>
      <el-col :span="24">
        <!-- 删掉el-pagination如下的默认事件 -->
        <!-- @size-change="handleSizeChange"
        @current-change="handleCurrentChange" -->
        <el-pagination
          :current-page="pageData.pagenum"
          :page-sizes="[2, 4, 6, 8, 10]"
          :page-size="pageData.pagesize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
        ></el-pagination>
      </el-col>
    </el-row>
  </div>
</template>
<script>
export default {
  data() {
    return {
      level2: "用户管理",
      level3: "用户列表",
      //页码
      pageData: {
        pagenum: 1,
        pagesize: 10,
        query: ""
      },
      //总页数,默认为0
      total: 0,
      //用户的数据
      userList: []
    };
  },
  created() {
    //get请求需要通过params属性来传对象
    this.$axios.get("users", { params: this.pageData }).then(res => {
      console.log(res);
      this.userList = res.data.data.users;
      this.total = res.data.data.total;
    });
  }
};
</script>
<style lang="scss">
#user {
  .operate {
    background-color: #e8edf3;
  }
}
</style>

2.完成user组件动态交互

Ⅰ.用户查询

NO. 题外话:组件中写name的好处
1 vue开发者界面语义更明确
2 可以使用搜索快速定位到组件

用户查询步骤:点搜索→发请求→调接口→拿数据

NO. 用户查询步骤
1 根据input输入的查询字段可以进行模糊搜索,如果input输入为空默认搜索到全部用户
2 搜索方法和页面刷新created调用的方法一样,可以封装复用

Ⅱ.用户添加
饿了吗:Dialog 对话框(自定义内容) 传送门http://element-cn.eleme.io/#/zh-CN/component/dialog

NO. Dialog对话框
1 和面包屑同级,新增html用户添加的对话框代码
1 在form上添加:rules="rules"属性,增加表单数据验证
2 在form上添加:ref="userForm"属性,并将userForm传给提交按钮,增加表单提交验证
3 表单验证是前端验证可以被绕过,主要防止普通用户的误操作
4 技术用户可以绕过前端验证,比如用postman直接发送请求,添加用户,就不需要受到前端的限制
5 所以后端服务器一定会再验证一次
//template
 <!-- 添加用户的对话框 -->
    <el-dialog title="添加用户" :visible.sync="visible">
      <!-- label-position控制label名的显示位置,注意要设置label-width才能生效 -->
      <!-- 表单数据验证要加form上添加:rules="rules"属性 -->
      <!-- 表单提交验证要加ref="userForm"属性,并将userForm传给提交按钮 -->
      <el-form :model="form" :rules="rules" ref="userForm" label-position="left" label-width="70px">
        <el-form-item label="用户名" prop="username">
          <el-input v-model="form.username" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <!-- 添加type="password"属性,让密码不明文显示 -->
          <el-input v-model="form.password" type="password" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="邮箱">
          <el-input v-model="form.email" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="手机号">
          <el-input v-model="form.mobile" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="visible = false">取 消</el-button>
        <!-- 记住这边的userForm要加单引号 -->
        <el-button type="primary" @click="submitForm('userForm')">确 定</el-button>
      </div>
    </el-dialog>

//css
<style lang="scss">
#user {
  .operate {
    background-color: #e8edf3;
  }
  .el-dialog {
    width:30%;
  }
}
</style>

//js
<script>
export default {
  //写了name方便在Vue Devtools谷歌插件应用内找到对应的组件
  name: "user",
  data() {
    return {
      level2: "用户管理",
      level3: "用户列表",
      //页码
      pageData: {
        pagenum: 1,
        pagesize: 10,
        //query是查询的字段
        query: ""
      },
      //总页数,默认为0
      total: 0,
      //用户的数据
      userList: [],
      //是否 显示对话框
      visible: false,
      form: {
        username: "",
        password: "",
        email: "",
        mobile: ""
      },
      //表单验证规则
       rules: {
          username: [
            { required: true, message: '请输入用户名', trigger: 'blur' },
            { min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' }
          ],
          password: [
            { required: true, message: '请输入密码', trigger: 'blur' },
            { min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' }
          ]
      }
    }
  },
  methods: {
    //查询用户方法
    async getUsers() {
      //get请求需要通过params属性来传对象
      //用async/await 同步执行异步代码
      let res = await this.$axios.get("users", {
        params: this.pageData
      });
      //赋值
      this.userList = res.data.data.users;
      this.total = res.data.data.total;
    },
    //提交增加用户方法
    //这边submitForm和validate都要加上async,内部的await才能生效
    async submitForm(formName) {
       this.$refs[formName].validate(async valid => {
         if (valid) {
           //验证成功
           //调用接口
           let res = await this.$axios.post("users",this.form);
           console.log(res);
           if(res.data.meta.status===201){
           //201表示成功请求并创建了新的资源,可以继续执行下一步
           //关闭弹框
           this.visible=false;
           //重新获取数据
           this.getUsers();
           }
         } else {
           //验证失败
           this.$message.error('请您输入正确的信息')
           return false;
         }
       });
     },
  },
  //生命周期函数,回调函数
  async created() {
    //get请求需要通过params属性来传对象
    // let res = await this.$axios.get("users", { params: this.pageData });
    // this.userList = res.data.data.users;
    // this.total = res.data.data.total;

    //直接调用封装后的代码
    this.getUsers();
  }
};
</script>

Ⅲ.用户状态(启用跟禁用该用户)

饿了吗组件 Switch 开关有change方法

//template中
 <!-- slot-scope 废弃,已经被v-slot代替,为插槽传入table中的userList -->
 <template slot-scope="scope">
    <el-switch
       v-model="scope.row.mg_state"
       active-color="#13ce66"
       inactive-color="#ff4949"
       @change="statusChange(scope.row)">
    </el-switch>
 </template>

//js的methods中增加如下方法
<script>
 async statusChange(data){
       console.log(data);
       let res = await this.$axios.put(`users/${data.id}/state/${data.mg.state}`);
     }
</script>

Ⅳ.用户删除:传入id即可

//在删除按钮增加delOne方法,写在methods内
<script>
     delOne(data){
       console.log(data);
       let id = data.id;
       //提示用户
       this.$confirm('此操作将永久删除用户,是否继续?',"提示",{
         confirmButtonText:"确定",
         cancelButtonText:"取消",
         type:"danger"
       })
       .then(async()=>{
         //确定
         let res = await this.$axios.delete(`users/${id}`);
         //console.log(res);
         //重新获取用户数据即可
         this.getUsers();
       })
       .catch(()=>{
         //取消
       })
     }
</script>

V.用户编辑:

NO. 用户编辑
1 进入编辑状态
2 保存编辑结果

进入编辑状态

//template

<!-- 修改用户的对话框 -->
    <el-dialog title="修改用户" :visible.sync="editVisible">
      <!-- label-position控制label名的显示位置,注意要设置label-width才能生效 -->
      <!-- 表单提交验证要加ref="userForm"属性,并将userForm传给提交按钮 -->
      <el-form :model="editForm" ref="editForm" label-position="left" label-width="70px">
        <el-form-item label="用户名" prop="username">
          <!-- 用户名不可改,可以再input内加disabled属性,就能实现禁止修改 -->
          <!-- 对于利用vue浏览器插件进行修改的用户,只能说牛逼,暂时没有想到解决方法 -->
          <el-input v-model="editForm.username" disabled autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="邮箱">
          <el-input v-model="editForm.email" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="手机号">
          <el-input v-model="editForm.mobile" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="editVisible = false">取 消</el-button>
        <!-- 记住这边的userForm要加单引号 -->
        <el-button type="primary" @click="submitEdit('editForm')">确 定</el-button>
      </div>
    </el-dialog>


//js:
<script>
//1.data数据里增加
      //编辑框是否可见
      editVisible:false,
      //编辑框的表单数据
      editForm:{
        username:'',
        email:'',
        mobile:''
        //增加用户的id,方便后续编辑使用
        id:''
      }

//2.methods里增加方法
     //显示编辑框
     showEditDialog(data){
       //打印data
       console.log(data);
       //显示编辑框
       this.editVisible = true;
       //js的for in方法,遍历editForm的key,将data对应的key赋值给editForm的key
       for (const key in this.editForm) {
          this.editForm[key] = data[key];
         }
       //这种方法可能会在vue插件界面被篡改数据,保险点是用id再请求一个接口获取数据
       //如果id也被修改了呢?一般不会这么无聊
     }
</script>

保存编辑结果

//1.template:增加确定保存按钮
<div slot="footer" class="dialog-footer">
     <el-button @click="editVisible = false">取 消</el-button>
     <!-- 记住这边的userForm要加单引号 -->
     <el-button type="primary" @click="submitEdit()">确 定</el-button>
</div>

//2.js:methods里增加方法
<script>
async submitEdit(){
       let res = await this.$axios.put(
         `users/${this.editForm.id}`,
         this.editForm
       );
       console.log(res);
       if(res.data.meta.status===200){
         //关闭编辑框
         this.editVisible = false;
         //重新获取数据即可
         this.getUsers();
       }
     }
</script>

VI.分配角色

NO. 分配角色
1 弹出角色框,分配角色
2 保存分配结果

饿了吗组件 Select 选择器
传送门http://element-cn.eleme.io/#/zh-CN/component/select

//template
<!-- 分配角色的对话框 -->
    <el-dialog title="分配角色" :visible.sync="roleVisible">
      <!-- 就一个下拉框,不需要绑定表单数据:model="editForm",绑定角色数据就行 -->
      <el-form  label-position="left" label-width="100px">
        <el-form-item label="当前用户">
          {{selectUser.username}}
        </el-form-item>
        <el-form-item label="请选择角色">
           <el-select v-model="selectUser.role_name" placeholder="请选择">
              <el-option
                v-for="item in roles"
                :key="item.id"
                :label="item.roleName"
                :value="item.id">
              </el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="roleVisible = false">取 消</el-button>
        <!-- 记住这边的userForm要加单引号 -->
        <el-button type="primary" @click="submitRole">确 定</el-button>
      </div>
    </el-dialog>

//js
<script>
// data里增加下面数据
    //分配角色框是否显示
    roleVisible:false,
    //当前选中的用户数据
    selectUser:'',
    //所有的角色数据
    roles:''


//methods里增加下面的方法
    //显示角色对话框
    async showRoleDialog(data){
       this.roleVisible = true;
       //通过data获取用户的名字,用户的角色
       //console.log(data);
       //为了方便编码,直接保存当前选择的用户数据
       this.selectUser = data;
       //获取所有的角色,去数据库获取(角色列表接口)
        let res = await this.$axios.get('roles');
        console.log(res);
        this.roles = res.data.data;
        console.log(this.roles);
    },
    //保存分配结果
    async submitRole(){
      // 获取用户id,获取角色id
      // 调用接口
      let res = this.$axios.put(`users/${this.selectUser.id}/role`,{
         rid:this.selectUser.role_name
       });
       console.log(res);
       //关闭对话框
       this.roleVisible = false;
       //提示用户,之前已经有axios拦截器了
    }
</script>

V.分页功能实现
饿了吗组件 Pagination 分页的一些属性和方法

属性/方法 作用
1.@size-change="handleSizeChange" pageSize (每页条数) 改变时会触发,回调参数是新的pageSize
2.@current-change="handleCurrentChange" currentPage(当前页)改变时会触发,回调参数是新的currentPage
3.:page-sizes="[2, 4, 6, 8, 10]" 这是下拉框可以选择的,每选择一行,要展示多少内容
4.:page-size="pageSize" 显示当前行的条数
5.:total="userList.length" 总共有多少数据
6.:data="userList.slice((currentPage-1)pagesize,currentPagepagesize) userList取第几页的数据,最为重要的一句话

//html
<!-- 用户数据 -->
    <el-row>
      <el-col :sapn="24">
        <!-- 如下对数据请求的处理,最为重要的一句话,表示,userList取第几页的数据 -->
        <!-- :data="userList.slice((currentPage-1)*pagesize,currentPage*pagesize)"   -->
        <!-- arrayObject.slice(start,end)方法,参数是指数组对应的下标元素,start参数必选,end参数可选 -->
        <el-table style="width: 100%" border
         :data="userList.slice((pageData.pagenum-1)*pageData.pagesize,pageData.pagenum*pageData.pagesize)" >
          <!-- 返回的数据没有对应的属性名,把prop删掉 -->
          <!-- 增加type="index",会设置排序 -->
          <el-table-column label="#" width="30" type="index"></el-table-column>
          <el-table-column prop="username" label="姓名" width="180"></el-table-column>
          <el-table-column prop="email" label="邮箱" width="300"></el-table-column>
          <el-table-column prop="mobile" label="电话" width="300"></el-table-column>
          <el-table-column prop="mg_state" label="用户状态" width="80">
            <!-- slot-scope 废弃,已经被v-slot代替,为插槽传入table中的userList -->
            <template slot-scope="scope">
              <el-switch
                v-model="scope.row.mg_state"
                active-color="#13ce66"
                inactive-color="#ff4949"
                @change="statusChange(scope.row)"
              ></el-switch>
            </template>
          </el-table-column>
          <el-table-column label="操作">
            <template slot-scope="scope">
              <el-button type="primary" plain size="mini" @click="showEditDialog(scope.row)" icon="el-icon-edit"></el-button>
              <el-button type="danger" plain size="mini" @click="delOne(scope.row)" icon="el-icon-delete"></el-button>
              <el-button type="warning" plain size="mini"  @click="showRoleDialog(scope.row)" icon="el-icon-check"></el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-col>
    </el-row>
<!-- 底部的分页 -->
    <el-row>
      <!-- size-change pageSize(每页条数)改变时会触发的事件 -->
      <!-- current-change currentPage(当前页)改变时会触发 -->
      <!-- :page-sizes="[2, 4, 6, 8, 10]" 这是下拉框可以选择的,每选择一行,要展示多少内容 -->
      <!-- :page-size="pageData.pagesize"显示当前行的条数 -->
      <!-- :total="userList.length" 这是总共有多少数据 -->
      <el-col :span="24">
        <!-- 删掉el-pagination如下的默认事件 -->
        <!-- @size-change="handleSizeChange"
        @current-change="handleCurrentChange"-->
        <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="pageData.pagenum"
          :page-sizes="[2, 4, 6, 8, 10]"
          :page-size="pageData.pagesize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="userList.length"
        ></el-pagination>
      </el-col>
    </el-row>


//js 在methods中加如下方法
<script>
handleSizeChange(size){
      this.pageData.pagesize = size;//每页下拉显示数据
      // console.log(this.pageData.pagesize);
    },
handleCurrentChange(currentPage){
      this.pageData.pagenum = currentPage;//点击第几页
      // console.log(this.pageData.pagenum);
    }
</script>

本文同步发表在我的个人博客:https://www.lubaojun.com/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容