电商项目开发

1.搭建项目工程

 vue2基本目录结构:

element.js(引入使用element组件)、main.js(设置后端路径前缀和引入一些文件)、index.js(路由)的代码

element.js:

import Vue from 'vue'
import { Button,Form,FormItem,Input,Message,Container,Header,Aside,Main,Menu,
    Submenu,
    MenuItem,
    Breadcrumb,
    BreadcrumbItem,
    Card,
    Row,
    Col,
    Table,
    TableColumn,
    Switch,
    Tooltip,
    Pagination,
    Tag,
    Dialog,
    Tree,
    MessageBox
    } from 'element-ui'

Vue.use(Button)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Input)
Vue.use(Container)
Vue.use(Header)
Vue.use(Aside)
Vue.use(Main)
Vue.use(Menu)
Vue.use(Submenu)
Vue.use(MenuItem)
Vue.use(Breadcrumb)
Vue.use(BreadcrumbItem)
Vue.use(Card)
Vue.use(Row)
Vue.use(Col)
Vue.use(Table)
Vue.use(TableColumn)
Vue.use(Switch)
Vue.use(Tooltip)
Vue.use(Pagination)
Vue.use(Tag)
Vue.use(Dialog)
Vue.use(Tree)
Vue.prototype.$message = Message
Vue.prototype.$confirm = MessageBox.confirm

main.js代码:

import Vue from 'vue'
import ElementUI from 'element-ui'; 
import App from './App.vue'
import router from './router'
import store from './store'
import './plugins/element.js'
//导入全局的css样式
import './assets/login.css'
//导入第三方样式
import './assets/fonts/iconfont.css'
Vue.config.productionTip = false
//导入axios,进行axios请求
import axios from 'axios'

axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/' //设置URL请求路径的前缀
/**
 * 实现每次请求服务器都携带着token信息,服务器识别无误后进行数据的传递
 * 通过拦截器来实现每次请求都携带token
 */
axios.interceptors.request.use(config => {
  //将token信息添加在请求信息header中
  config.headers.Authorization = window.sessionStorage.getItem("token")
  console.log(config);
  return config
})

Vue.prototype.$http = axios

new Vue({
  router,
  store,
  render: function (h) { return h(App) }
}).$mount('#app')

index.js:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../components/login.vue' //导入login.vue
import Home from '../components/home.vue'
import Users from '../components/users.vue'
import Welcome from '../components/welcome.vue'
import Privileges from '../components/Privileges.vue'
import Roles from '../components/Roles.vue'

Vue.use(VueRouter)

const routes = [
  //配置路径,使访问根组件时直接访问login.vue页面
  {path:'/',redirect:'/login'},
  {path:'/login',component:Login},
  {path:'/home',component:Home,
          redirect:'/welcome',
          children:[
            {path:'/welcome',component:Welcome},
            {path:'/users',component:Users},  //users的路径访问
            {path:'/rights',component:Privileges},  //Privileges的路径访问
            {path:'/roles',component:Roles} 
          ]
  }
]

const router = new VueRouter({
  routes
})
/**
   * 挂载路由导航守卫
   * 实现在没有登录的情况下不能访问下一个页面
   */
  router.beforeEach((to,form,next) => {
    /**
     * to:要访问的页面,比如这里是shopping页面
     * form:从哪个路径跳转过来的,比如这里是从login页面
     * next:该函数控制本次访问是否可以正常执行
     */
    console.log(to.path);
    if(to.path == '/login') return next() //可以访问(放开)
    const current_token = window.sessionStorage.getItem('token');  //取出token信息
    console.log(current_token); //token信息
    if(!current_token) return next('/login') //!current_token表示不存在token信息,说明没有登录,那就直接跳转到登录页面
    //否则(登录了,有token信息),就放行
    next()
  })

export default router //导出router

通过VUE UI来搭建项目(黑窗口输入vue ui回车在浏览器中打开 Vue CLI)

  • 添加插件:安装element UI(在)
  • 添加依赖:安装axios依赖,less依赖,less-loader依赖
  • 在此平台里再次启动看是否有问题(第一次是在node后端里进行启动)

2.启动服务端程序

  • 配置MySQL数据:通过phpstudy的MySQL管理器的MySQL导入导出功能将数据导入到数据库中

  • 启动服务端Node程序:之前启动之前需要通过 npm install 安装依赖,然后通过 node ./app.js 启动服务端程序。

  • 测试服务端接口是否可以正常访问

3.登陆界面的开发

界面原型:

改造APP.vue

删除APP.vue里面初始化(template、script、style中的代码)

login.vue组件添加
  • 在components中删除helloword.vue并且删除引用到helloword.vue的地方

  • 再在components中新建login.vue组件,并完成页面的布局,再将此组件添加到根组件(App.vue)中

先将login.vue添加到根组件中,使其能够正常显示
App.vue:
<template>
  <!-- 视图查看 此标签即可使login.vue正常显示-->
  <router-view></router-view> 
</template>

<script>
export default {
  
}
</script>

<style>

</style>

在router目录下的index.js中将根路径的访问目标改为login组件
    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import login from '../components/login.vue' //导入login.vue

    Vue.use(VueRouter)

    const routes = [
      //配置路径,使访问根组件时直接访问login.vue页面
      {path:'/',redirect:'/login'},
      {path:'/login',component:login}
    ]

    const router = new VueRouter({
      routes
    })

    export default router //导出router


login.vue:
<template>
  <div class="login_continer">
    <div class="login_box">
      <!-- 显示logo图标 -->
      <div class="avatar_box">
        <img src="../assets/logo.png">
      </div>
      <!-- 显示表单 用到了element UI组件-->
      <el-form label-width="0px" class = "login_form"> 
            <!-- 输入用户名 -->
            <el-form-item>
                <el-input></el-input>
            </el-form-item>
            <!-- 输入密码 -->
            <el-form-item>
                <el-input></el-input>
            </el-form-item>
      </el-form>
    </div>
  </div>
</template>
<script>
export default {
  name: "app"
};
</script>

<style lang="less" scoped> //less是为了用来打包处理css代码
    						//scoped是使这个css样式只在此组件有效,防止样式的冲突
.login_continer {
  background-color: cadetblue;
  height: 100%;
}
.login_box {
  width: 450px;
  height: 300px;
  background-color: #ffffff;
  border-radius: 10px;
  position: absolute;
  left: 50%;
  top: 50%;
  //配合上面两个使其居中显示
  transform: translate(-50%, -50%);

  .avatar_box {
    height: 130px;
    width: 130px;
    border: 1px solid #eee;
    border-radius: 50%;
    padding: 10px;
    box-shadow: 0 0 10px #ddd; //加上阴影
    position: absolute;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: #fff;
    img {
      width: 100%;
      height: 100%;
      border-radius: 50%;
      background-color: #eee;
    }
  }
}
.login_form{
    position: absolute;
    bottom: 10px;
    width: 100%;
    box-sizing: border-box;
    padding: 0 30px;
}
.btns{
  display: flex;
  justify-content: flex-end;
}
</style>

因为这里用到了element组件,要引入elementui的相应elementui样式 
element.js:
import Vue from 'vue'
import { Button,Form,FormItem,Input} from 'element-ui' //引入
//使用
Vue.use(Button)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Input)


对于session的理解
  • 用户登录成功之后,需要将用户的token信息保存到Session当中去。

    • token:服务端随机生成后返回给客户端的信息

    • 作用:客户端用来保持跟服务端的会话(连接)

    • token的有效范围:只在一次会话当中,也就是在session中有效。

  • session可以表示为一次会话,例如:从通话开始到通话结束,也可以理解为从打开浏览器到关闭浏览器的一次行为。

    • token在会话结束后,也会被浏览器自动删除掉。

控制项目页面的访问权限
  • 企业级的应用系统在没有登录的情况下是不能有访问权限的。

  • 类似于教务管理系统,在没有登录的情况下是没法查询学生信息的。

  • 实现方式:挂载路由导航守卫

//index.js:
import home from '../components/home.vue' //导入home.vue
{path:'/home',component:home} //home的路径访问

/*
挂载路由导航守卫:
实现在没有登录的情况下不能访问下一个页面
*/
 router.beforeEach((to,form,next) => {
    /**
     * to:要访问的页面,比如这里是shopping页面
     * form:从哪个路径跳转过来的,比如这里是从login页面
     * next:该函数控制本次访问是否可以正常执行
     */
    console.log(to.path);
    if(to.path == '/login') return next() //可以访问(放开)
    const current_token = window.sessionStorage.getItem('token');  //取出token信息
    console.log(current_token); //token信息
    if(!current_token) return next('/login') //!current_token表示不存在token信息,说明没有	   //登录,那就直接跳转到登录页面,意思是让他先登录
     
    //否则(登录了,有token信息),就放行
    next()
  })
  • 涉及到的知识或新点(个人觉得):

    1.组件实现页面的展示:要将组件引入到根组件App.vue中,而且要在router/index.js中进行路由

    2.用到了elementUI的组件,特别方便 网址:Element - The world's most popular Vue UI framework

    3.要引入elementUI中用到的组件:例如button,input,form.....

    4.token的理解,在类似于电商的项目中对于访问页面中是必须携带的

登录界面到此完成!即将进入到主页的开发

4.主界面

其中涉及到知识点和注意的点都在代码中写了注释

Home界面格式和菜单数据展示

界面原型:

整体布局
<el-container>
        <!-- 头部区域 -->
        <el-header>
            <div>
                <img src = "../assets/images/logo.png">
                <span>电商后台管理系统</span>
            </div>
            <!--在右侧加一个退出按钮-->
            <el-button type = "info" @click = ”loginOut“>退出</el-button>
        </el-header>
        <!-- 主体区域 -->
        <el-container>
            <!-- 左侧菜单栏 -->
            <el-aside width="200px">  <!--动态显示宽度-->
                <h5>
                    Aside
                </h5>
            </el-aside>
            <!-- 右侧内容展示区域 -->
            <el-main>
               <h5>Main</h5>
            </el-main>
        </el-container>
    </el-container>   

界面元素:

右侧菜单:
要去找一个两级菜单的element组件然后进行嵌套实现想要的效果
1.还有各个一级菜单的icon图标找一个合适的 2.二级菜单的选中高亮显示,要根据path来进行判断是否显示 3.菜单的展开折叠功能 4.刷新页面让他继续停住选中的二级菜单
左侧的数据展示:
 1.头部面包屑 2.下面是一整个el-container组件
 <template>
 <!-- 主体区域 -->
        <el-container>
            <!-- 左侧菜单栏 -->
            <el-aside :width="IsCollapse ? '50px': '200px'">  <!--动态显示宽度-->
                <div class = "collapse-button" @click = "collapseButton">菜单</div>
                <!-- 菜单栏 -->
                <el-menu background-color="#545c64" text-color="#fff" unique-opened :collapse = "IsCollapse"
                :collapse-transition = "false" :default-active = "HighlightValue" router
                >
                    <!-- 一级菜单 -->
                    <el-submenu :index="item.id+''" v-for = "item in menulist" :key = "item.id">      
                        
<!--这里的index中item.id时整数,所以要加一个''变成字符串
用来实现一个子菜单的下拉 配合unique-opened实现
router:刷新页面时照样是选中的那一页
:collapse = "IsCollapse" 展开折叠
:collapse-transition = "false" :去除展开折叠的动画效果
:default-active = "HighlightValue" 高亮的显示控制
-->
                        
                        <!-- 一级菜单的模板模型 -->
                        <template slot="title">
                            <!-- 一级菜单的icon -->
                            <i :class="menuIcons[item.id]"></i>
                            <!-- 一级菜单的菜单名 
								通过:class来进行属性的动态绑定return里面的数据
                                根据id进行动态显示icon
                            -->
                            <span>{{item.authName}}</span>
                        </template>

                        <!-- 二级菜单 -->
                        <el-menu-item :index="'/'+subItem.path" v-for = "subItem in item.children" :key = "subItem.id"
                        @click = "Highlight('/'+subItem.path)">
                            <!--这里的:index实现只高亮显示一个二级菜单-->
                            <template slot = "title">
                                <!-- 二级菜单icon -->
                                <i class="el-icon-menu"></i>
                                <!-- 二级菜单的菜单名 -->
                                <span>{{subItem.authName}}</span>
                            </template>
                        </el-menu-item>
                    </el-submenu>
                </el-menu>
            </el-aside>
            <!-- 右侧内容展示区域 -->
            <el-main>
                <!-- 在右侧展示数据内容 -->
                <router-view></router-view>
            </el-main>
        </el-container>
</template>

<script>
export default {
    /**
     * 从服务器菜单栏数据
     * 当页面加载的时候去获取数据
     */
    data(){
        return{
            //菜单栏数据
            menulist:[],
            menuIcons:{
                //给每个一级菜单栏设置icon
                '125':"el-icon-s-custom",
                '103':"el-icon-setting",
                '101':"el-icon-s-goods",
                '102':"el-icon-s-order",
                '145':"el-icon-s-data",
            },
            IsCollapse:false, //首先默认false,不进行折叠
            HighlightValue:"" //高亮显示,刚开始是无高亮显示的菜单
        }
    },
    //created:在页面加载时去获取数据
    created(){
        //调用服务端接口获取数据
        this.getMenuList()
        //取出存放在session中的HighlightValue进行相应路径的菜单进行高亮显示
        this.HighlightValue = window.sessionStorage.getItem("HighlightValue"); 
    },
    methods:{
        //async:异步请求  await:处理async
        async getMenuList(){
            // 用于从返回的 Promise 对象中提取 data 属性,并将其赋值给变量 res
            const {data : res} = await this.$http.get("menus")
            console.log(res)
            if(res.meta.status !== 200) return this.$message.error(res.meta.msg)
            this.menulist = res.data //将数据赋值
        },
        collapseButton(){
            //给IsCollapse取反,实现展开折叠的效果
            this.IsCollapse = !this.IsCollapse
        },
        Highlight(path){
            //将当前选中的路径保存放在session中,当页面初始化时,取出进行赋值实现高亮显示效果
            window.sessionStorage.setItem("HighlightValue",path)
            this.HighlightValue = path;
        }
    }
}
</script>

<style lang="less" scoped>
.el-container{
    height: 100%;
}
.el-header{
    background-color: #c2c8cc;
    display: flex;
    justify-content: space-between; //两边对齐
    align-items: center; //整体水平居中对齐 
    padding-left: 0px; //logo与左边边距为0
    color: #fff;
    font-size: 22px;
    > div{
        display: flex;
        align-items: center;
        span{
            margin-left: 16px;
        }
    }
}
.el-aside{
    background-color: #395cce;
}
.el-main{
    background-color: #dee3eb;
}
.el-menu{
    //清除菜单栏右侧的1px线
    border-right: none;
}
.collapse-button{
    text-align: center;
    font-size: 18px;
    line-height: 25px;
    color: #fff;
    cursor: pointer;
    letter-spacing: 0.3em; //字与字之间的间距
}
</style>

用户菜单对应的数据展示(前面这里只是图形编写)

这里主要是左侧的数据展示

搜索框和添加按钮:

搜索框的功能实现:利用v-model来进行对请求数据时的query参数进行双向绑定就好了,这样在输入姓名查询时,在搜索icon上绑定一个请求数据的事件,再次请求时就会携带着输入的姓名参数去进行请求服务端,然后显示查询到的数据

添加功能的实现:需要一个对话框,控制对话框的显示和关闭,然后在对话框中添加一个有四行输入框的form表单(用element组件),在关闭的时候要将所有输入框的数据清空,还有就是校验:

姓名和密码可以简单校验,邮箱和手机号要进行严格的数据校验,在确定按钮绑上一个去请求添加用户的事件

<template>
    <el-card>
            <el-row :gutter="25">
                <!-- 搜索框 
                    实现搜索功能:v-model:双向绑定
                    clearable:点击小叉子清空功能
                    @clear = "getUsersList():当输入框被清空时触发该事件,显示全部数据
                    :gutter="25" 输入框和添加按钮之间间隔25px
                -->
                <el-col :span="8">
                    <el-input placeholder="请输入内容" v-model = "params.query" clearable @clear = "getUsersList()">
                        <el-button slot="append" icon="el-icon-search" @click = "getUsersList()" ></el-button>
                    </el-input>
                </el-col>
                <!-- 添加用户的按钮 -->
                <el-col :span="4" >
                       <el-button type="primary" @click = "dialogVisible=true">添加用户</el-button> 
                </el-col>
            </el-row>
    </el-card>
</template>

数据表格+分页

这里的点主要有:

1.数据表的请求,然后显示

2.状态字段的显示:用后端传来的true和false来完成switch开关的显示,并且在进行改变的时候要请求服务端将数据库中的状态值改变,然后再次请求数据库来显示状态值,来实现永久性的改变(指的就是刷新后改变的switch不会是原始的)

3.编辑功能的实现:和后端逻辑一样,先回显,然后姓名字段不可更改,然后进行put请求进行修改

4.删除功能:根据id来进行删除

5,权限分配的鼠标悬浮消息提示:

effect="dark" content="分配角色" placement="top-end" 实现顶部显示

:enterable = "false" 鼠标不可进入到提示框中

<!-- 数据表格区域: -->
<template>
 <div>
    <el-card>
            </el-row>
            <el-table :data = "userList" border>
                <el-table-column type="index"></el-table-column>
                <el-table-column prop = "username" label="姓名"></el-table-column>
                <el-table-column prop = "email" label="邮箱"></el-table-column>
                <el-table-column prop = "mobile" label="电话"></el-table-column>
                <el-table-column prop = "role_name" label="角色"></el-table-column>
                <el-table-column label="状态">
                    <!-- 根据状态字段的值来进行动态显示
                        mg_state:true就打开
                        mg_state:false就关闭
                        基于作用域插槽实现,为了获取状态的值(true or false)
                     -->
                    <template slot-scope = "scope">
                        <!-- change:状态值的永久改变(请求后端改变数据库的内容)
                            scope.row:将当前行的数据传递给该事件
                            change	switch 状态发生变化时的回调函数	新状态的值
                         -->
                        <el-switch v-model="scope.row.mg_state" @change = "mg_state_change(scope.row)"></el-switch>
                    </template>
                </el-table-column>
                <el-table-column width = "200" label="操作">
                    <!-- 也是基于作用域插槽的方法实现:方便后面的按钮功能的实现时获取数据 
                        size	用于控制该表单内组件的尺寸	string	medium / small / mini
                        effect	默认提供的主题	String	dark/light	dark
                        enterable	鼠标是否可进入到 tooltip 中	Boolean	—	true
                    -->
                    <template v-slot:default="scope">
                        <!-- 编辑按钮 -->
                        <el-button type = "primary" icon = "el-icon-edit" size = "mini" @click = "echoEditDialog(scope.row.id)"></el-button>
                        <!-- 删除按钮 -->
                        <el-button type = "danger" icon = "el-icon-delete" size = "mini" @click = "deleteUserById(scope.row.id)"></el-button>
                        <!-- 指定(分配角色按钮) -->
                        <el-tooltip class="item" effect="dark" content="分配角色" placement="top-end" :enterable = "false">
                            <el-button type = "warning" icon = "el-icon-s-tools" size = "mini"></el-button>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </el-table>
            <!-- 分页显示 
                :total 当前页面总共有多少条数据,这个值来自后端
                :page-size 每页显示多少条,根据请求的参数来进行显示
                :current-page 当前页码
                @size-change:改变每页显示的数据
                @current-change:数据跟着页码进行改变
            -->
            <el-pagination
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="params.pagenum"
                :page-sizes="[5, 10, 15, 20]"
                :page-size="params.pagesize" 
                layout="total, sizes, prev, pager, next, jumper"
                :total="total">
            </el-pagination>
    </el-card>
	        <!-- 添加用户对话框 
            close	Dialog 关闭的回调
            :visible.sync="dialogVisible" 对话框的显示控制
        -->
        <el-dialog
            title="添加用户"
            :visible.sync="dialogVisible" 
            width="50%"
            @close="user_addform_close">
                <!-- 内容区域 -->
                <el-form :model="addForm" label-width="70px" ref = "addFormRef" :rules = "addFormRules">
                    <el-form-item  label="用户名" prop = "username">
                        <el-input v-model="addForm.username"></el-input>
                    </el-form-item>
                    <el-form-item  label="密码" prop = "password">
                        <el-input v-model="addForm.password" type = "password"></el-input>
                    </el-form-item>
                    <el-form-item  label="邮箱" prop = "email">
                        <el-input v-model="addForm.email"></el-input>
                    </el-form-item>
                    <el-form-item  label="手机" prop = "mobile">
                        <el-input v-model="addForm.mobile"></el-input>
                    </el-form-item>
                </el-form>
                <!-- 底部 取消和确定按钮 -->
            <span slot="footer" class="dialog-footer">
                <el-button @click="dialogVisible = false">取 消</el-button>
                <el-button type="primary" @click = "addUser">确 定</el-button>
            </span>
        </el-dialog>
        <!-- 修改用户信息的对话框 -->
        <el-dialog title="修改用户信息" :visible.sync="editDialogVisible"  width="50%" @close="user_editForm_close">
            <el-form :model="editForm" label-width="70px" ref = "editFormRef" :ruler = "editFormRules"> 
                <!-- 显示需要修改的用户信息 -->
                    <el-form-item  label="用户名" prop = "username">
                        <el-input v-model="editForm.username" disabled></el-input>
                    </el-form-item>
                    <el-form-item  label="邮箱" prop = "email">
                        <el-input v-model="editForm.email"></el-input>
                    </el-form-item>
                    <el-form-item  label="手机" prop = "mobile">
                        <el-input v-model="editForm.mobile"></el-input>
                    </el-form-item>
                </el-form>
                    <!-- 底部 取消和确定按钮 -->
                <span slot="footer" class="dialog-footer">
                    <el-button @click="dialogVisible = false">取 消</el-button>
                    <el-button type="primary" @click = "editUser">保 存</el-button>
                </span>
        </el-dialog>
  </div>
</template>

<script>
	export default {
    data(){
        /**
         * rule:路径
         * value:校验值(true/false)
         * callback:返回信息
         */
        const checkEmail = (rule, value, callback) => {
            const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
            if(regEmail.test(value)){
                return callback()
            }
            return callback("邮箱的输入格式不正确!")
        }
        const checkMobile = (rule, value, callback) => {
            const regMobile = /^(86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/
            if(regMobile.test(value)){
                return callback()
            }
            return callback("手机号码的输入格式不正确!")
        }
        return{
            //调用后端数据需要的参数
            params:{
                //查询条件,显示条件
                query:'',
                //页码
                pagenum:'1',
                //每页显示多少条数据
                pagesize:'5'
            },
            //用户数据数组
            userList:[],
            //总页数
            total:0,
            //对话框的控制
            dialogVisible:false,
            addForm:{
                username:'',
                password:'',
                email:'',
                mobile:''
            },
            addFormRules:{
                username:[
                    {required: true, message:"请输入用户名",trigger:"blur"},
                    {min: 6, max: 16, message:"用户名的长度为6~15个字符",trigger:"blur"}
                ],
                password:[
                    {required: true, message:"请输入密码",trigger:"blur"},
                    {min: 6, max: 16, message:"密码的长度为6~15个字符",trigger:"blur"}
                ],
                email: [
                    {required: true, message:"请输入邮箱",trigger:"blur"},
                    { validator: checkEmail, trigger: 'blur' }
                ],
                mobile:[
                    {required: true, message:"请输入手机号码",trigger:"blur"},
                    { validator: checkMobile, trigger: 'blur' }
                ]
            },
            //控制修改用户对话框的显示
            editDialogVisible: false,
            editForm: {},
            editFormRules:{
                 email: [
                    {required: true, message:"请输入邮箱",trigger:"blur"},
                    { validator: checkEmail, trigger: 'blur' }
                ],
                mobile:[
                    {required: true, message:"请输入手机号码",trigger:"blur"},
                    { validator: checkMobile, trigger: 'blur' }
                ]
            }
        }
    },
    created(){
        //调用后端接口获取用户数据进行显示
        this.getUsersList()
    },
    methods:{
        //获取后端的数据库数据
        async getUsersList(){
            const {data:res} = await this.$http.get('users',{params:this.params}) //{params:请求的参数}
            // console.log(res)
            if(res.meta.status !== 200) return this.$message.error("获取用户列表失败")
            this.userList = res.data.users
            //给total赋值
            this.total = res.data.total
        },
        //实现每页显示几条数据
        handleSizeChange(s_size){
            this.params.pagesize = s_size //将每页显示的数据改为选择的数字
            this.getUsersList() //在改变条数成功后,重新去后端加载数据显示
        },
        //实现数据跟着页码变化
        handleCurrentChange(s_sise){
            this.params.pagenum = s_sise
            this.getUsersList()
        },
        //row代表当前的这条数据
        async mg_state_change(row){
            console.log(row)
            //发送修改请求到后端
            const {data:res} = await this.$http.put(`users/${row.id}/state/${row.mg_state}`)
            if(res.meta.status !== 200){ 
                return this.$message.error("用户状态更新失败")
                //更新失败了取反改回来
                row.mg_state = !row.mg_state
            }
            return this.$message.success("用户状态更新成功")
        },
        //关闭添加对话框时触发
        user_addform_close(){
            //清空输入框
            this.$refs.addFormRef.resetFields()
        },
        /**
         * 实现添加(保存)用户信息
         *     前提条件:前面的校验都通过了
         */
        addUser(){
            this.$refs.addFormRef.validate(async valid => {
                if(!valid) return 
                //发起请求后端
                const {data:res} = await this.$http.post('users',this.addForm)
                // console.log(res)
                if(res.meta.status !== 201)  return this.$message.error("添加用户数据失败") //直接return掉
                this.$message.success("添加用户成功")
                //添加成功后将对话框隐藏
                this.dialogVisible = false
                //重新进行向后端数据请求获取
                this.getUsersList()
            })
        },
        //关闭对话框时把文本进行重置清空
        user_editForm_close(){
            this.$refs.addFormRef.resetFields()
        },
        //回显数据在对话框中
        async echoEditDialog(id){
            //查询
            const {data:res} = await this.$http.get('users/'+id)
            if(res.meta.status !== 200){
                return this.$message.error("查询用户信息失败!")
            }
            // console.log(res.data)
            //将查询到的数据给到editForm对象进行显示
            this.editForm = res.data
            //并显示对话框
            this.editDialogVisible = true
        },
        //保存修改后的数据
        editUser(){
            this.$refs.editFormRef.validate(async valid => {
                if(!valid) return 
                //发起修改信息请求
                /**
                 * 第二个参数表示修改的属性,需要的是一个json格式的数据
                 */
                const {data:res} = await this.$http.put('users/'+this.editForm.id,
                {
                    email:this.editForm.email,
                    mobile:this.editForm.mobile
                })
                //对发送修改请求的结果进行判断(成功/失败)
                if(res.meta.status !== 200)  return this.$message.error("修改用户信息失败!") //直接return掉
                this.$message.success("修改用户信息成功")
                //添加成功后将对话框隐藏
                this.editDialogVisible = false
                //重新进行向后端数据请求获取
                this.getUsersList()
            })
        },
        //根据用户id删除用户信息
        async deleteUserById(id){
            //首先弹窗询问用户是否确定删除
            const confirmResult = await this.$confirm(
                    '此操作将永久删除该文件, 是否继续?', 
                    '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                    }
                ).catch((err) => err)
                //如果用户确认删除,则返回值字符串confirmResult为confirm
                //如果用户确认删除,则返回值字符串confirmResult为cancel
                console.log(confirmResult)          
                if(confirmResult !== 'confirm'){
                    return this.$message.info("已取消删除")
                }
                const {data:res} = await this.$http.delete('users/'+id)
                if(res.meta.status !== 200){
                    return this.$message.error("删除用户失败!")
                }
                this.$message.success("删除用户成功!")
                this.getUsersList()
        }
    }
}
</script>

权限菜单对应的数据展示

首先也是一个面包屑导航栏

首页>权限管理>权限列表

<template>
	<div>
<!-- 面包屑导航栏区域 -->
        <el-breadcrumb separator-class="el-icon-arrow-right">
            <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
            <el-breadcrumb-item>权限管理</el-breadcrumb-item>
            <el-breadcrumb-item>角色列表</el-breadcrumb-item>
        </el-breadcrumb>
    </div>
</template>

数据显示:

1.在布局好数据显示的表格样式后加上一个斑马线的属性

stripe属性可以创建带斑马纹的表格。它接受一个Boolean,默认为false,设置为true即为启用。

2.权限等级的标签样式显示

   <el-tag>标签一</el-tag> <el-tag type="success">标签二</el-tag> <el-tag                type="info">标签三</el-tag> <el-tag type="warning">标签四</el-tag> <el-tag type="danger">标签五</el-tag>

对应上面的标签效果

通过type属性来渲染权限的等级

其他的就很简单,和user的一样的做法(获取数据展示啥的)

<template>
	<div>
        <!-- 数据展示区域 -->
        <el-card>
            <el-table :data = "privilegesList" border>
                <el-table-column type="index"></el-table-column>
                <el-table-column prop = "authName" label="权限名称"></el-table-column>
                <el-table-column prop = "path" label="路径"></el-table-column>
                <el-table-column prop = "level" label="权限等级">
                    <!-- 作用域插槽的方式来进行 -->
                    <template v-slot:default="scope">
                        <el-tag v-if = "scope.row.level === '0'">一级</el-tag>
                        <el-tag type="success" v-else-if = "scope.row.level === '1'">二级</el-tag>
                        <el-tag type="warning" v-else>三级</el-tag>
                    </template>
                </el-table-column>
            </el-table>
        </el-card>
    </div>
</template>

<script>
export default {
    data(){
        return{
            privilegesList:[]
        }
    },
    created(){
        //获取所有的权限列表
        this.getPrivilegesList()
    },
    methods:{
        async getPrivilegesList(){
            const {data:res} = await this.$http.get('rights/list')
            console.log(res)
            if(res.meta.status !== 200) return this.$message.error("获取权限列表失败!")
            
            this.privilegesList = res.data
        }
    }
}
</script>


<style lang="less" scoped>
.el-card{
    margin-top: 20px;
}
</style>

角色菜单对应的数据显示

涉及到的元素:

面包屑

添加角色按钮+表格+最左列的展开折叠效果,来查看角色对应的权限

新鲜点:

主要就是查看各个角色对应的权限有哪些

这里要将展示权限的表格进行分割为24列

进行数据的规格化展示

水平居中

小箭头:

<i class="el-icon-caret-right"></i>  icon图标

拥有的所有的功能权限的小叉叉删除

closable @close="dleteRightById(scope.row, item3.id)" 
    <!--为close绑上删除的功能-->
<template>
    <div>
        <!-- 面包屑导航栏区域 -->
        <el-breadcrumb separator-class="el-icon-arrow-right">
            <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
            <el-breadcrumb-item>权限管理</el-breadcrumb-item>
            <el-breadcrumb-item>角色列表</el-breadcrumb-item>
        </el-breadcrumb>
        <!-- 数据展示的卡片区域 -->
        <el-card>
            <el-row>
                <el-col>
                    <el-button type="primary">添加角色</el-button>
                </el-col>
            </el-row>
            <el-table :data = "rolesList" border stripe>
                <!-- type="expand":>的icon -->
                <el-table-column type="expand">
                    <!-- 通过插槽的方法来实现渲染权限级别 -->
                    <template v-slot:default = "scope">
                        <el-row :class = "['role-bdbottom-line',il === 0 ? 'role-top-line' : '','role-content-center']" v-for = "(item,il) in scope.row.children" :key = "item.id">
                            <!-- 渲染一级权限 -->
                            <el-col :span = "5">
                                <el-tag>
                                    {{item.authName}}
                                </el-tag>
                                <i class="el-icon-caret-right"></i>
                            </el-col>
                            <!-- 渲染二级和三级权限 -->
                            <el-col :span = "19">
                                    <el-row :class = "[i2 === 0 ? '': 'role-top-line','role-content-center']" v-for = "(item2,i2) in scope.row.children" :key = "item2.id">
                                        <!-- 二级渲染 -->
                                        <el-col :span = "6">
                                            <el-tag type = "success">
                                                {{item2.authName}}
                                            </el-tag>
                                            <i class="el-icon-caret-right"></i>
                                        </el-col>
                                        <!-- 三级渲染 -->
                                        <el-col :span = "18">
                                            <el-tag type = "warning" closable @close="dleteRightById(scope.row, item3.id)" v-for = "(item3) in item2.children" :key = "item3.id">
                                                {{item3.authName}}
                                            </el-tag>
                                        </el-col>
                                    </el-row>
                            </el-col>
                        </el-row>
                    </template>
                </el-table-column>
                <el-table-column type = "index"></el-table-column>
                <el-table-column prop = "roleName" label="角色名称"></el-table-column>
                <el-table-column prop = "roleDesc" label="角色描述"></el-table-column>
                <el-table-column width = "300" label="操作">
                    <template v-slot:default="scope">
                        <!-- 编辑按钮 -->
                        <el-button type = "primary" icon = "el-icon-edit" size = "mini" @click = "echoEditDialog(scope.row.id)">编辑</el-button>
                        <!-- 删除按钮 -->
                        <el-button type = "danger" icon = "el-icon-delete" size = "mini" @click = "deleteRolesById(scope.row.id)">删除</el-button>
                        <!-- 指定(分配角色按钮) -->
                        <el-button type = "warning" icon = "el-icon-setting" size = "mini" @click = "showSetRolePrivilegeDialog(scope.row)">分配权限</el-button>
                    </template>
                </el-table-column>
            </el-table>
        </el-card>

        <!-- 显示编辑对话框 -->
        <el-dialog title="分配权限" :visible.sync="setRolePrivilegeDialogVisible" width="50%" >
            <!-- 树形控件 -->
            <el-tree :data="privilegeList" :props="treeProps" ></el-tree>
            <span slot="footer" class="dialog-footer">
                <el-button @click="setRolePrivilegeDialogVisible = false">取 消</el-button>
                <el-button type="primary" >确 定</el-button>
            </span>
        </el-dialog>
    </div>
</template>

<script>
export default {
    data(){
        return{
            //角色列表
            rolesList:[],
            //分配权限对话框的显示和隐藏控制
            setRolePrivilegeDialogVisible: false,
            //权限列表
            privilegeList:[],
            treeProps:{
                label: 'authName',
                children: 'children'
            }
        }
    },
    created(){
        //权限列表数据数组
        this.getRolesList()
    },
    methods:{
        async getRolesList(){
            const {data:res} = await this.$http.get('roles')
            console.log(res.data)

            if(res.meta.status !== 200) return this.$message.error("获取角色列表失败")
            this.rolesList = res.data
        },
        async dleteRightById(role,privilege_id){
            //根据id删除相应的权限
            const confirmResult = await this.$confirm(
                    '此操作将永久删除该文件, 是否继续?', 
                    '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                    }
                ).catch((err) => err)
                //如果用户确认删除,则返回值字符串confirmResult为confirm
                //如果用户确认删除,则返回值字符串confirmResult为cancel
                console.log(confirmResult)          
                if(confirmResult !== 'confirm'){
                    return this.$message.info("已取消删除")
                }
                const {data:res} = await this.$http.delete( `roles/${role.id}/rights/${privilege_id}`)
                if(res.meta.status !== 200){
                    return this.$message.error("删除权限失败!")
                }
                role.children = res.data //重新赋值展示权限
        },
        //权限分配
        async showSetRolePrivilegeDialog(row){
            //向服务端获取全部权限数据
            const {data:res} = await this.$http.get('rights/tree')
            if(res.meta.status !== 200){
                return this.$message.error("获取权限数据失败!")
            }
            this.privilegeList = res.data
            //打开对话框
            this.setRolePrivilegeDialogVisible = true 
        },
        deleteRolesById(id){

        }
    }
}
</script>


<style lang="less" scoped>
.el-card{
    margin-top: 20px;
}
.el-table{
    font-size: 15px;
    margin-top: 18px;
}
.el-tag{
    //调整一个个标签tag之间的距离
    margin: 8px
}
//上边框
.role-top-line{
    border-top: 1px solid #eee;
}
//下边框
.role-bdbottom-line{
    border-bottom: 1px solid #eee;
}
//居中显示
.role-content-center{
    display: flex;
    align-items: center;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值