代码拉取完成,页面将自动刷新
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI)
node-sass sass-loader
并导入默认样式文件// 1. 安装解析scss文件的加载器
npm i node-sass sass-loader --save-dev
// 2. 将reset.scss/index.scss复制到项目文件中,并新建element.scss
// 3. 在main.js中导入全局样式文件
import '@/styles/index.scss'
HelloWord.vue
以及router
文件夹index.js
中的组件导入和路由规则src
目录下创建views
文件夹,并创建login.vue
组件
在router
文件夹下的index.js
中配置路由规则
// 导入登录组件
import login from '../views/login.vue'
// 在routes数组中配置路由对象
export default new Router({
routes: [
{
path:'/login',
name:'Login',
component:login
}
]
})
http://localhost:1234/#/login
显示登录组件内容<div class="login">
<el-form ref="form" :model="form" class="container" :rules="rules">
<el-form-item>
<div class="avatar">
<img src="../assets/avatar.jpg" alt="">
</div>
</el-form-item>
<el-form-item prop="username">
<el-input v-model="form.username" placeholder="账户" prefix-icon="myicon myicon-user"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="form.password" placeholder="密码" prefix-icon="myicon myicon-key"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" class="login-btn">登录</el-button>
</el-form-item>
</el-form>
</div>
.login {
position: fixed;
width: 100%;
height: 100%;
background-color: #2f4050;
.container {
position: absolute;
left: 0;
right: 0;
width: 400px;
padding: 0px 40px 15px 40px;
margin: 200px auto;
background: white;
.avatar {
position: relative;
left: 50%;
width: 120px;
height: 120px;
margin-left: -60px;
margin-top: -60px;
box-sizing: border-box;
border-radius: 50%;
border: 10px solid #fff;
box-shadow: 0 1px 5px #ccc;
overflow: hidden;
}
.login-btn {
width: 100%;
}
}
}
export default {
data () {
return {
form: {
username: '',
password: ''
},
rules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' }
]
}
}
}
}
npm i axios -S
api/index.js
文件,封装登录请求// 导入axios
import axios from 'axios'
// 设置请求的根路径
const baseURL = 'http://www.lovegf.cn:8888/api/private/v1/'
axios.defaults.baseURL = baseURL
// 登录验证
export const checkUser = params => {
return axios.post('login', params).then(res => res.data)
}
login.vue
中的登录按钮上绑定点击事件,发送登录请求// 导入封装的登录请求接口
import {checkUser} from '../api/index.js'
// 定义登录方法
methods: {
loginSubmit (formName) {
// 校验表单
this.$refs[formName].validate(valide => {
if (valide) {
// 发送登录请求
checkUser(this.form).then(res => {
if (res.meta.status === 200) {
// 如果成功要跳转至首页
this.$router.push({name: 'Home'})
} else {
// 如果失败,展示提示信息
this.$message({
type: 'error',
message: res.meta.msg
})
}
})
} else {
console.log('校验不通过')
}
})
}
}
Home.vue
文件,并配置好路由规则import home from '../views/Home.vue'
routes: [
{
path:'/login',
name:'Login',
component:login
},
{
path:'/home',
name:'Home',
component:home
}
]
除登录请求外,其他所有请求发送都必须保证请求头中有登录成功返回的token值,所以需要使用拦截器给请求添加
Authorization
// 存储后台返回的登录成功凭证token
localStorage.setItem('mytoken', res.data.token)
// 请求拦截器,给所有的请求加上token
axios.interceptors.request.use(function (config) {
// 取出localStorage中存储的token值
let token = localStorage.getItem('mytoken')
// 设置到请求头中 Authorization这个名字是后台规定的
config.headers['Authorization'] = token
return config
}, function (error) {
return Promise.reject(error)
})
// 获取用户列表
export const getUserList = params => {
return axios.get('users', params).then(res => res.data)
}
Home.vue
的生命周期函数created
中发送获取数据列表请求created(){
let params = {params: {query: '', pagenum: 1, pagesize: 1}}
getUserList(params).then(res => {
console.log(res)
})
}
对于需要登录的页面访问前需要判断是否已经登录,使用路由导航钩子进行拦截
router/index.js
中使用路由全局守卫拦截所有的路由跳转// 注册一个全局守卫,作用是在路由跳转前,对路由进行判断,防止未登录的用户跳转到其他需要登录的页面去
router.beforeEach((to, from, next) => {
let token = localStorage.getItem('mytoken')
// 如果已经登录,放行
if (token) {
next()
} else {
// 如果没有登录,访问非登录页面,则跳转到登录页面
if (to.path !== '/login') {
next({path: '/login'})
} else {
// 如果没有登录,但访问的是登录页面,直接进入
next()
}
}
})
<div class="home">
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-container>
<el-header>Header</el-header>
<el-main>Main</el-main>
</el-container>
</el-container>
</div>
.home {
height: 100%;
.el-menu-admin:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
.el-container {
height: 100%;
}
.el-aside {
background-color: #545c64;
}
.el-header {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #545c64;
}
.logo {
height:60px;
background: url(../assets/logo.png);
background-size: cover;
background-color: #989898;
}
.toggle-btn {
font-size: 36px;
color: #989898;
cursor: pointer;
line-height: 60px;
}
.system-title {
font-size: 28px;
color: white;
}
.logout-btn {
color: orange;
}
}
<!-- 侧边栏 -->
<el-aside width="200px">
<div class="logo"></div>
<el-menu
default-active="2"
class="el-menu-admin"
@open="handleOpen"
@close="handleClose"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b">
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span>用户管理</span>
</template>
<el-menu-item index="2">
<i class="el-icon-menu"></i>
<span slot="title">用户列表</span>
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
methods:{
handleOpen (key, keyPath) {
console.log(key, keyPath)
},
handleClose (key, keyPath) {
console.log(key, keyPath)
}
}
<!-- header部分 -->
<el-header>
<i class="myicon myicon-menu toggle-btn" @click="toggleCollapse"></i>
<div class="system-title">电商后台管理系统</div>
<div>
<span class="welcome">
您好,xxx
</span>
<el-button type="text" @click="logout">退出</el-button>
</div>
</el-header>
<!-- 中间内容部分 -->
<el-main>
<router-view></router-view>
</el-main>
isCollapse
属性控制左侧导航的切换// 1. el-menu上绑定collapse属性
// 2. 定义isCollapse:false
data() {
return {
isCollapse:false
}
}
/// 3. 切换事件
toggleCollapse(){
this.isCollapse = !this.isCollapse
}
logout () {
// 1. 清除登录状态,即删除保存在localStorage中的token
localStorage.removeItem('mytoken')
// 2. 跳转到登录页面
this.$router.push({name: 'Login'})
}
由于每次点击左侧导航都是中间区域变化,而整体页面的左侧和头部不变,所以中间区域应该设置成子路由
// 1. 创建welcome组件并导入
import welcome from '../views/welcome/Welcome.vue'
// 2. 配置子路由规则用于显示welcome组件
{
path: '/',
name: 'Home',
component: home,
redirect: {
path: 'welcome'
},
children: [{
name: 'Welcome',
path: 'welcome',
component: welcome
}]
}
// 3. 子路由的组件需要显示到父路由对应的组件中,所以Home.vue中需要放一个router-view
<el-main>
<router-view></router-view>
</el-main>
store/index.js
文件,定义store实例import Vue from 'vue'
// 1. 导入并绑定Vuex
import Vuex from 'vuex'
Vue.use(Vuex)
// 2. 定义数据存储仓库state
const state = {
username: ''
}
// 3. 定义用于修改数据的方法
const mutations = {
setUsername: (state, username) => {
state.username = username
localStorage.setItem('username', username)
}
}
// 4. 异步修改数据
const actions = {}
// 5. 计算属性
const getters = {
username: (state) => localStorage.getItem('username')
}
// 6. 导出store实例
export default new Vuex.Store({
state,
getters,
actions,
mutations
})
main.js
中导入并集成store// 导入
import store from './store/index.js'
// 挂载到vue实例
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
// 2. 使用vuex存储用户名
this.$store.commit('setUsername', res.data.username)
$store.getters.username
显示数据<span class="welcome">
您好,{{$store.getters.username}}
</span>
启用element-ui路由跳转功能,Home.vue
组件中的el-menu
标签上添加:router = "true"
el-menu-item
标签的index属性设置需要跳转的路由路径
<el-menu-item index="/user">
<i class="el-icon-menu"></i>
<span slot="title">用户列表</span>
</el-menu-item>
User.vue
组件,并配置好路由规则// 导入组件
import user from '../views/user/User.vue'
// 创建路由规则对象
{
name: 'User',
path: 'user',
component: user
}
<div class="user">
<el-row>
<el-col :span="24">
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>用户管理</el-breadcrumb-item>
<el-breadcrumb-item>用户列表</el-breadcrumb-item>
</el-breadcrumb>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<!-- 给组件绑定原生事件的话,需要一个.native的修饰符 -->
<el-input placeholder="请输入内容" class="search-input">
<el-button slot="append" icon="el-icon-search"></el-button>
</el-input>
<el-button type="success" plain>添加用户</el-button>
</el-col>
</el-row>
<el-table
:data="tableData"
border
style="width: 100%">
<el-table-column
prop="date"
label="日期"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址">
</el-table-column>
</el-table>
<div class="page">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="1"
:page-sizes="[10, 20, 30, 40]"
:page-size="10"
layout="total, sizes, prev, pager, next, jumper"
:total="40">
</el-pagination>
</div>
</div>
/*element.scss中书写面包屑组件样式*/
.el-breadcrumb {
background-color: #D3DCE6;
height: 45px;
font-size: 15px;
padding-left: 10px;
line-height: 45px;
margin-bottom: 15px;
}
/*组件内部style标签中书写以下样式*/
.user {
.margin-20 {
margin: 20px 0;
}
.search-input {
width: 300px;
}
.page {
padding: 5px 0;
background-color: #D3DCE6;
}
}
// 1. data中定义存储数据的数组userList
// 2. 在methods中定义数据请求方法
initList () {
getUserList({params: {query: '', pagenum: 1, pagesize: 3}}).then(res => {
console.log(res)
this.userList = res.data.users
})
}
// 3. 在生命周期函数created中发送请求
created(){
this.initList()
}
<el-table
:data="userList"
border
style="width: 100%">
<el-table-column
type="index"
width="50">
</el-table-column>
<el-table-column
prop="username"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="email"
label="邮箱"
width="180">
</el-table-column>
<el-table-column
prop="mobile"
label="电话">
</el-table-column>
<el-table-column label="用户状态">
<template slot-scope="scope">
<el-switch v-model="value"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" type="primary" plain icon="el-icon-edit"></el-button>
<el-button size="mini" type="danger" plain icon="el-icon-delete"></el-button>
<el-button size="mini" type="warning" plain icon="el-icon-check"></el-button>
</template>
</el-table-column>
</el-table>
// 由于搜索接口和获取用户列表是同一个接口,所以只需要加入搜索条件即可
initList () {
getUserList({params: {query: this.query, pagenum: 1, pagesize: 3}}).then(res => {
console.log(res)
this.userList = res.data.users
})
}
<el-button slot="append" icon="el-icon-search" @click="initList"></el-button>
<!-- 组件绑定原生DOM事件需要绑定native事件修饰符 -->
<el-input placeholder="请输入内容" class="search-input" v-model="query" @keydown.native.enter="initList">
在data中定义total
,pagesize
,pagenum
三个属性分别存储数据总条数、每页显示多少条、页码
数据请求方法中给total
赋值
// 初始化表格数据
initList () {
getUserList({params: {query: this.query, pagenum: this.pagenum, pagesize: this.pagesize}}).then(res => {
console.log(res)
this.userList = res.data.users
this.total = res.data.total
})
}
handleSizeChange (val) {
console.log(`每页 ${val} 条`)
this.pagesize = val
this.initList()
},
handleCurrentChange (val) {
console.log(`当前页: ${val}`)
this.pagenum = val
this.initList()
}
<el-switch v-model="scope.row.mg_state" @change="changeUserState(scope.row)"></el-switch>
// 更改用户状态
export const changeUserState = params => {
return axios.put(`users/${params.uid}/state/${params.type}`).then(res => res.data)
}
// 改变用户状态
changeUserState (row) {
console.log(row)
changeUserState({uid: row.id, type: row.mg_state}).then(res => {
if (res.meta.status === 200) {
this.$message({
type: 'success',
message: '修改用户状态成功'
})
} else {
this.$message({
type: 'warning',
message: res.meta.msg
})
}
})
}
el-dialog
组件实现弹窗<!-- 1. 添加按钮绑定点击事件 -->
<el-button type="success" plain @click="addDialogFormVisible=true">添加用户</el-button>
<!-- 2. el-dialog布局 -->
<!-- 添加用户对话框 -->
<!--
:visible.sync属性控制弹窗显示隐藏
-->
<el-dialog title="添加用户" :visible.sync="addDialogFormVisible">
<el-form :model="addForm" label-width="80px" :rules="rules" ref="addUserForm">
<el-form-item label="用户名" prop="username">
<el-input v-model="addForm.username" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="addForm.password" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="addForm.email" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="电话" prop="mobile">
<el-input v-model="addForm.mobile" auto-complete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addDialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="addUserSubmit('addUserForm')">确 定</el-button>
</div>
</el-dialog>
addDialogFormVisible: false,
addForm: {
username: '',
password: '',
email: '',
mobile: ''
},
// 添加用户的表单验证
rules: {
username: [{
required: true, message: '请输入用户名', trigger: 'blur'
}],
password: [{
required: true, message: '请输入密码', trigger: 'blur'
}],
email: [{
required: true, message: '请输入邮箱地址', trigger: 'blur' },{
type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur,change'
}],
mobile: [{
required: true, message: '电话不能为空'
}]
}
// 添加用户
export const addUser = params => {
return axios.post('users', params).then(res => res.data)
}
// 添加用户
addUserSubmit (formName) {
this.$refs[formName].validate(valide => {
if (valide) {
// 执行添加用户方法
addUser(this.addForm).then(res => {
console.log(res)
if (res.meta.status === 201) {
this.$message({
type: 'success',
message: '创建用户成功!'
})
}
this.addDialogFormVisible = false
this.initList()
})
}
})
}
el-dialog
组件实现弹窗<!-- 编辑按钮点击事件 -->
<el-button size="mini" type="primary" plain icon="el-icon-edit" @click="showEditDialog(scope.row)"></el-button>
<!-- 编辑用户对话框 -->
<el-dialog title="编辑用户" :visible.sync="editDialogFormVisible">
<el-form :model="editForm" label-width="80px" :rules="rules" ref="editUserForm">
<el-form-item label="用户名" prop="username">
<el-input v-model="editForm.username" auto-complete="off" :disabled="true"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="editForm.email" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="电话" prop="mobile">
<el-input v-model="editForm.mobile" auto-complete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="editDialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="editUserSubmit('editUserForm')">确 定</el-button>
</div>
</el-dialog>
editDialogFormVisible: false,
editForm: {
username: '',
email: '',
mobile: '',
id: 0
}
// 根据id获取用户信息
export const getUserById = params => {
return axios.get(`users/${params}`).then(res => res.data)
}
// 编辑用户信息
export const editUser = params => {
return axios.put(`users/${params.id}`, params).then(res => res.data)
}
// 显示编辑用户对话框
showEditDialog (row) {
this.editDialogFormVisible = true
// 获取用户信息
getUserById(row.id).then(res => {
if (res.meta.status === 200) {
this.editForm.username = res.data.username
this.editForm.email = res.data.email
this.editForm.mobile = res.data.mobile
this.editForm.id = res.data.id
}
})
},
// 编辑用户提交
editUserSubmit (formName) {
this.$refs[formName].validate(valide => {
if (valide) {
editUser(this.editForm).then(res => {
if (res.meta.status === 200) {
this.$message({
type: 'success',
message: '编辑成功'
})
this.editDialogFormVisible = false
this.initList()
}
})
}
})
}
<el-button size="mini" type="danger" plain icon="el-icon-delete" @click="showDeleteDialog(scope.row)"></el-button>
// 删除用户信息
export const deleteUser = params => {
return axios.delete(`users/${params}`).then(res => res.data)
}
// 显示删除对话框
showDeleteDialog (row) {
this.$confirm('此操作将永久删除该用户, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 执行删除用户操作
deleteUser(row.id).then(res => {
if (res.meta.status === 200) {
this.$message({
type: 'success',
message: '删除成功!'
})
this.initList()
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
}
<el-button size="mini" type="warning" plain icon="el-icon-check" @click="showGrantDialog(scope.row)"></el-button>
<!-- 分配角色对话框 -->
<el-dialog title="分配角色" :visible.sync="grantDialogFormVisible">
<el-form :model="grantForm" label-width="120px">
<el-form-item label="当前的用户:" prop="username">
<el-tag type="info">{{grantForm.username}}</el-tag>
</el-form-item>
<el-form-item label="请选择角色:">
<el-select v-model="roleId" placeholder="请选择角色">
<el-option
v-for="(role, index) in roleList"
:key="index"
:label="role.roleName"
:value="role.id">
</el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="grantDialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="grantUserSubmit()">确 定</el-button>
</div>
</el-dialog>
// 控制分配用户角色对话框显示隐藏
grantDialogFormVisible: false,
// 存储分配角色时获取的用户信息
grantForm: {},
// 角色列表
roleList: [],
// 角色ID
roleId: ''
// 获取角色列表
export const getRoleList = params => {
return axios.get('roles').then(res => res.data)
}
// 分配角色
export const grantUserRole = params => {
return axios.put(`users/${params.id}/role`, {id: params.id, rid: params.rid}).then(res => res.data)
}
// 显示分配角色对话框
showGrantDialog (row) {
this.grantForm = row
this.grantDialogFormVisible = true
getRoleList().then(res => {
console.log(res)
if (res.meta.status === 200) {
this.roleList = res.data
}
})
}
// 分配角色
grantUserSubmit () {
// 当没有选择角色时,不发送网络请求
if (!this.roleId) {
this.$message({
type: 'warning',
message: '角色不能为空,请选择!'
})
} else {
grantUserRole({id: this.grantForm.id, rid: this.roleId}).then(res => {
if (res.meta.status === 200) {
this.$message({
type: 'success',
message: '设置角色成功'
})
this.grantDialogFormVisible = false
} else {
this.$message({
type: 'error',
message: res.meta.msg
})
}
})
}
}
<el-submenu index = "2">
<template slot="title">
<i class="el-icon-location"></i>
<span>权限管理</span>
</template>
<el-menu-item index="/roles">
<i class="el-icon-menu"></i>
<span slot="title">角色列表</span>
</el-menu-item>
<el-menu-item index="/rights">
<i class="el-icon-menu"></i>
<span slot="title">权限列表</span>
</el-menu-item>
</el-submenu>
Roles.vue
和Rights.vue
组件,并配置路由规则import rights from '../views/right/Rights.vue'
import roles from '../views/right/Roles.vue'
{
name: 'Rights',
path: 'rights',
component: rights
}, {
name: 'Roles',
path: 'roles',
component: roles
}
<div class="rights">
<el-row>
<el-col :span="24">
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>权限管理</el-breadcrumb-item>
<el-breadcrumb-item>权限列表</el-breadcrumb-item>
</el-breadcrumb>
</el-col>
</el-row>
<el-table
v-loading="isLoading"
:data="rightList"
border
style="width: 100%">
<el-table-column
type="index"
width="50">
</el-table-column>
<el-table-column
prop="authName"
label="权限名称"
width="180">
</el-table-column>
<el-table-column
prop="path"
label="路径">
</el-table-column>
<el-table-column label="层级">
<template slot-scope="scope">
<span>{{scope.row.level | fmtLevel}}</span>
</template>
</el-table-column>
</el-table>
</div>
// 获取权限列表
export const getRightList = params => {
return axios.get(`rights/${params.type}`).then(res => res.data)
}
created
钩子函数中发送网络请求created () {
this.isLoading = true
getRightList({type: 'list'}).then(res => {
if (res.meta.status === 200) {
this.rightList = res.data
this.isLoading = false
}
})
}
filters: {
fmtLevel (level) {
if (level === '0') {
return '一级'
} else if (level === '1') {
return '二级'
} else {
return '三级'
}
}
}
<div class="roles">
<el-row>
<el-col :span="24">
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>权限管理</el-breadcrumb-item>
<el-breadcrumb-item>角色列表</el-breadcrumb-item>
</el-breadcrumb>
</el-col>
</el-row>
<el-button type="primary" plain>添加角色</el-button>
<el-table
border
class="mt-15"
:data="roleList"
style="width: 100%">
<el-table-column type="expand">
<template slot-scope="scope">
<div>tag</div>
</template>
</el-table-column>
<el-table-column
label="角色名称"
prop="roleName"
width="165px">
</el-table-column>
<el-table-column
label="描述"
prop="roleDesc"
width="130px">
</el-table-column>
<el-table-column
label="操作">
<template slot-scope="scope">
<el-button size="mini" type="primary" plain icon="el-icon-edit"></el-button>
<el-button size="mini" type="danger" plain icon="el-icon-delete"></el-button>
<el-button size="mini" type="warning" plain icon="el-icon-check" title="授权角色"></el-button>
</template>
</el-table-column>
</el-table>
</div>
.roles {
.el-tag {
margin-right: 5px;
margin-bottom: 5px;
}
.tree-container {
height: 300px;
overflow: auto;
}
}
data(){
return {
roleList: []
}
},
created () {
this.initList()
},
methods: {
initList () {
getRoleList().then(res => {
if (res.meta.status === 200) {
console.log(res)
this.roleList = res.data
}
})
}
}
<template slot-scope="scope">
<el-row v-for="firstChildren in scope.row.children" :key="firstChildren.id">
<el-col :span="4">
<el-tag closable>{{firstChildren.authName}}</el-tag>
<i class="el-icon-arrow-right" v-if="firstChildren.children.length !== 0"></i>
</el-col>
<el-col :span="20">
<el-row v-for="secondChildren in firstChildren.children" :key="secondChildren.id">
<el-col :span="4">
<el-tag closable type="success">{{secondChildren.authName}}</el-tag>
<i class="el-icon-arrow-right" v-if="secondChildren.children.length !== 0"></i>
</el-col>
<el-col :span="20">
<el-tag closable type="warning" v-for="thirdChildren in secondChildren.children" :key="thirdChildren.id">
{{thirdChildren.authName}}
</el-tag>
</el-col>
</el-row>
</el-col>
</el-row>
<el-row v-if="scope.row.children.length === 0">
<el-col :span="24">该角色没有分配权限,请前往分配!</el-col>
</el-row>
</template>
el-tag
标签绑定删除事件<el-tag closable @close="deleteRight(scope.row, firstChildren.id)">{{firstChildren.authName}}</el-tag>
<el-tag closable type="success" @close="deleteRight(scope.row, secondChildren.id)">{{secondChildren.authName}}</el-tag>
<el-tag closable type="warning" @close="deleteRight(scope.row, thirdChildren.id)" v-for="thirdChildren in secondChildren.children" :key="thirdChildren.id">
// 删除角色指定权限
export const deleteRoleRight = params => {
return axios.delete(`roles/${params.roleId}/rights/${params.rightId}`).then(res => res.data)
}
deleteRight (row, rightId) {
deleteRoleRight({roleId: row.id, rightId: rightId}).then(res => {
if (res.meta.status === 200) {
row.children = res.data
} else {
this.$message({
type: 'error',
message: res.meta.msg
})
}
})
}
}
<el-dialog title="授权角色" :visible.sync="dialogFormVisible">
<div class="tree-container">
<el-tree
:data="rightList"
show-checkbox
ref="tree"
node-key="id"
:default-expand-all="true"
:default-checked-keys="selectedRights"
:props="defaultProps">
</el-tree>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary">确 定</el-button>
</div>
</el-dialog>
// 1. 定义组件需要用到的数据
dialogFormVisible: false, // 控制弹窗显示隐藏
rightList: [], // 存放权限列表
defaultProps: {
children: 'children', // // 树形组件展示的数据源
label: 'authName' // 树形组件显示的标题字段
}
// 2. 发送数据请求
showDialog (row) {
this.dialogFormVisible = true
this.currentRole = row
getRightList({type: 'tree'}).then(res => {
if (res.meta.status === 200) {
console.log(res.data)
this.rightList = res.data
} else {
this.$message({
type: 'error',
message: res.meta.msg
})
}
})
}
利用:default-checked-keys="selectedRights"
树形控制树形组件默认选中项
遍历所有权限,找到已授权的ID存放到selectedRights
中
// 遍历之前先让数组清空
this.selectedRights.length = 0
// 取出当前点击角色的所有权限, 然后遍历到它的第三个children,取出它里面的所有的项的id,存进selectedRights中
// 1. 遍历第一个children取出一级权限
this.currentRole.children.forEach(first => {
if (first.children && first.children.length !== 0) {
// 2. 遍历第二个children取出二级权限
first.children.forEach(second => {
if (second.children && second.children.length !== 0) {
// 3. 遍历第三个children取出三级权限
second.children.forEach(third => {
this.selectedRights.push(third.id)
})
}
})
}
})
// 角色授权
export const grantRoleRight = (roleId, rids) => {
return axios.post(`roles/${roleId}/rights`, rids).then(res => res.data)
}
// 提交授权
submitGrant () {
// 获取到所有选中的权限ID
let rids = this.$refs.tree.getCheckedKeys().join(',')
grantRoleRight(this.currentRole.id, {rids: rids}).then(res => {
if (res.meta.status === 200) {
this.$message({
type: 'success',
message: res.meta.msg
})
this.dialogFormVisible = false
this.initList()
}
})
}
// 左侧菜单权限
export const getMenus = () => {
return axios.get('menus').then(res => res.data)
}
created() {
getMenus().then(res => {
if (res.meta.status === 200) {
this.menuData = res.data;
}
})
}
v-for
循环渲染界面<el-menu
:router="true"
:unique-opened="true"
:collapse="isCollapse"
class="el-menu-admin"
@open="handleOpen"
@close="handleClose"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b">
<el-submenu :index="item.path" v-for="item in menuData" :key="item.id">
<template slot="title">
<i class="el-icon-location"></i>
<span>{{item.authName}}</span>
</template>
<el-menu-item :index="tag.path" v-for="tag in item.children" :key="tag.id">
<i class="el-icon-menu"></i>
<span slot="title">{{tag.authName}}</span>
</el-menu-item>
</el-submenu>
</el-menu>
category/Category.vue
组件,配置路由规则实现跳转{
name: 'Category',
path: 'categories',
component: category
}
componets
文件夹中放入TreeGrid
组件,并在Category.vue
组件中进行集成// 1. 在category.vue中导入组件
import TreeGrid from '@/components/TreeGrid/TreeGrid'
// 2. 注册组件
data() {
return {
addDialogFormVisible: false,
columns: [
{
text: "分类名称",
dataIndex: "cat_name",
width: ""
},
{
text: "是否有效",
dataIndex: "cat_deleted",
width: ""
},
{
text: "排序",
dataIndex: "cat_level",
width: ""
}
],
dataSource: [],
total: 10
}
},
components: {
TreeGrid
}
TreeGrid.vue
组件<div class="category">
<el-row>
<el-col :span="24">
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>商品管理</el-breadcrumb-item>
<el-breadcrumb-item>商品分类</el-breadcrumb-item>
</el-breadcrumb>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-button type="success" plain>添加分类</el-button>
</el-col>
</el-row>
<tree-grid
:treeStructure="true"
:columns="columns"
:data-source="dataSource"
@deleteCate="deleteCategory"
@editCate="editCategory"
>
</tree-grid>
<div class="page">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="1"
:page-sizes="[10, 20, 30, 40]"
:page-size="10"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</div>
// 获取商品分类信息
export const getCategories = (params) => {
return axios.get('categories', {params: params}).then(res => res.data)
}
initList() {
getCategories({
type: "3",
pagenum: this.pagenum,
pagesize: this.pagesize
}).then(res => {
console.log(res);
if (res.meta.status === 200) {
this.total = res.data.total;
this.dataSource = res.data.result;
}
});
}
<!-- 添加分类对话框 -->
<el-dialog title="添加分类" :visible.sync="addDialogFormVisible">
<el-form :model="addForm" label-width="80px" :rules="rules" ref="addCateForm">
<el-form-item label="分类名称" prop="cat_name">
<el-input v-model="addForm.cat_name" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="父级名称">
<el-cascader
:options="options"
v-model="selectedOptions"
:props="props"
@change="handleChange">
</el-cascader>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addDialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="addCateSubmit('addCateForm')">确 定</el-button>
</div>
</el-dialog>
addForm: {
cat_name: "",
cat_pid: 0,
cat_level: 0
},
// 级联选择器的数据源
options: [],
// 级联选择器选中后的数据
selectedOptions: [],
// props表示配置级联选择器展示的数据字段
props: {
value: "cat_id",
label: "cat_name"
}
addCategory() {
this.addDialogFormVisible = true;
getCategories({ type: "2" }).then(res => {
console.log(res);
if (res.meta.status === 200) {
this.options = res.data;
}
});
}
addCateSubmit(formName) {
this.$refs[formName].validate(valide => {
if (valide) {
// 添加一级分类
if (this.selectedOptions.length === 0) {
this.addForm.cat_pid = 0;
this.addForm.cat_level = 0;
} else if (this.selectedOptions.length === 1) {
// 添加二级分类
this.addForm.cat_pid = this.selectedOptions[
this.selectedOptions.length - 1
];
this.addForm.cat_level = 1;
} else {
// 添加三级分类
this.addForm.cat_pid = this.selectedOptions[
this.selectedOptions.length - 1
];
this.addForm.cat_level = 2;
}
addCategories(this.addForm).then(res => {
if (res.meta.status === 201) {
this.addDialogFormVisible = false;
this.initList();
this.$message({
type: "success",
message: res.meta.msg
});
}
});
}
});
}
{
name: 'Goods',
path: 'goods',
component: goods
}, {
name: 'AddGoods',
path: 'toadd',
component: addGoods
}
<template>
<div class="goods">
<el-row>
<el-col :span="24">
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>商品管理</el-breadcrumb-item>
<el-breadcrumb-item>商品列表</el-breadcrumb-item>
</el-breadcrumb>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-button type="success" plain @click="addGoods">添加商品</el-button>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
methods: {
addGoods () {
this.$router.push({name: 'AddGoods'})
}
}
}
</script>
<style lang="scss" scoped>
</style>
<div class="add-goods">
<el-row>
<el-col :span="24">
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>商品管理</el-breadcrumb-item>
<el-breadcrumb-item>商品列表</el-breadcrumb-item>
</el-breadcrumb>
</el-col>
</el-row>
<el-steps :active="active" finish-status="success">
<el-step title="步骤 1"></el-step>
<el-step title="步骤 2"></el-step>
<el-step title="步骤 3"></el-step>
<el-step title="步骤 4"></el-step>
<el-step title="步骤 5"></el-step>
</el-steps>
<el-tabs v-model="activeName" @tab-click="handleClick" tab-position="left" class="mt-20">
<el-tab-pane label="基本信息" name="first">
<el-form label-width="80px">
<el-form-item label="活动名称">
<el-input></el-input>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="商品参数" name="second">配置管理</el-tab-pane>
<el-tab-pane label="商品属性" name="third">角色管理</el-tab-pane>
<el-tab-pane label="商品图片" name="fourth">图片上传</el-tab-pane>
<el-tab-pane label="商品内容" name="fifth">定时任务补偿</el-tab-pane>
</el-tabs>
</div>
data () {
return {
active: 0,
activeName: 'first'
}
},
methods: {
handleClick (tab, event) {
switch (tab.name) {
case 'first':
this.active = 0
break
case 'second':
this.active = 1
break
case 'third':
this.active = 2
break
case 'fourth':
this.active = 3
break
case 'fifth':
this.active = 4
break
default:
this.active = 0
break
}
}
}
el-upload
组件上传图片<el-upload
action="http://www.lovegf.cn:8888/api/private/v1/upload"
:on-preview="handlePreview"
:on-success="handleSuccess"
:headers="setHeader()"
:on-remove="handleRemove"
list-type="picture">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
},
// 成功后回调函数
handleSuccess(response, file, fileList) {
if (response.meta.status === 200) {
this.$message({
type: "success",
message: response.meta.msg
});
}
},
// 设置请求头
setHeader() {
let token = localStorage.getItem("mytoken");
return { Authorization: token };
}
<input name="file" type="file" accept="image/png,image/gif,image/jpeg" @change="update($event)"/>
update(e) {
let file = e.target.files[0];// 获取文件数据
let param = new FormData(); // 创建form对象
param.append("file", file); // 通过append向form对象添加数据
console.log(param.get("file")); // FormData私有类对象,访问不到,可以通过get判断值是否传进去
let config = {
headers: {
"Content-Type": "multipart/form-data",
}
};
axios
.post("http://www.lovegf.cn:8888/api/private/v1/upload", param, config)
.then(response => {
console.log(response.data);
});
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。