项目实战第十六记
- 写在前面
- 1 第一个bug
- 1.1 完整的Role.vue
- 2 第二个bug
- 2.1 修改路由router下面的index.js
- 总结
- 写在最后
写在前面
- 发现bug,修复bug
1 第一个bug
分配菜单时未加入父id,导致分配菜单失效
<!--
:check-strictly="true" 默认是false,父子关联;true 是不关联
需手动勾选父选择框
-->
<el-tree
:props="props"
:data="menuData"
show-checkbox
node-key="id"
ref="tree"
:check-strictly="true"
:default-expanded-keys="expends"
:default-checked-keys="checks">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span><i :class="data.icon"></i> {{ data.name }}</span>
</span>
</el-tree>
1.1 完整的Role.vue
<template>
<div>
<!-- 设计的查询 -->
<div style="margin: 10px 0">
<el-input
style="width: 200px"
placeholder="请输入名称"
suffix-icon="el-icon-search"
v-model="name"
/>
<el-button type="primary" icon="el-icon-search" class="ml-5" @click="getList"
>搜索</el-button>
<el-button type="warning" icon="el-icon-reset" @click="resetQuery"
>重置</el-button>
</div>
<div style="margin: 10px 0">
<el-button type="primary" @click="handleAdd">新增 <i class="el-icon-circle-plus-outline"></i></el-button>
<el-button type="warning" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate">修改</el-button>
<el-button type="danger" :disabled="multiple" @click="handleDelete">删除 <i class="el-icon-remove-outline"></i></el-button>
</div>
<el-table :data="tableData" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="角色ID" width="80"></el-table-column>
<el-table-column prop="roleKey" label="唯一标识"></el-table-column>
<el-table-column prop="name" label="角色名称"></el-table-column>
<el-table-column prop="description" label="角色描述"></el-table-column>
<el-table-column label="操作">
<template v-slot="scope">
<el-button
type="info"
icon="el-icon-menu"
@click="openMenuAllocDialog(scope.row.id)"
>分配菜单</el-button>
<el-button type="success" @click="handleUpdate(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
<el-button type="danger" @click="handleDelete(scope.row)">删除 <i class="el-icon-remove-outline"></i></el-button>
</template>
</el-table-column>
</el-table>
<div style="padding: 10px 0">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[5, 10, 15]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
>
</el-pagination>
</div>
<!-- 角色添加对话框 -->
<el-dialog title="角色信息" :visible.sync="dialogFormVisible" width="30%">
<el-form :model="form">
<el-form-item label="唯一标识" :label-width="formLabelWidth">
<el-input v-model="form.roleKey" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="角色名称" :label-width="formLabelWidth">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="描述" :label-width="formLabelWidth">
<el-input v-model="form.description" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
<!-- 分配菜单 -->
<el-dialog title="菜单分配" :visible.sync="menuDialogVis" width="30%">
<el-tree
:props="props"
:data="menuData"
show-checkbox
node-key="id"
ref="tree"
:check-strictly="true"
:default-expanded-keys="expends"
:default-checked-keys="checks">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span><i :class="data.icon"></i> {{ data.name }}</span>
</span>
</el-tree>
<div slot="footer" class="dialog-footer">
<el-button @click="menuDialogVis = false">取 消</el-button>
<el-button type="primary" @click="saveRoleMenu">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: "Role",
data() {
return {
name: "",
tableData: [],
total: 0,
pageSize: 5,
pageNum: 1,
dialogFormVisible: false,
menuDialogVis: false,
formLabelWidth: "80px",
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
form: {
id: "",
name: "",
description: "",
},
menuData: [],
props: {
label: 'name',
},
expends: [],
checks: [],
roleId: undefined,
};
},
//页面一创建成功
created() {
//请求分页查询数据
this.getList();
},
methods: {
getList() {
this.request
.get("/role/page", {
params: {
pageNum: this.pageNum,
pageSize: this.pageSize,
name: this.name,
},
})
.then((res) => {
if(res.code === "200"){
this.tableData = res.data.records;
this.total = res.data.total;
}else{
this.$message.error(res.msg);
}
});
},
//分配菜单
openMenuAllocDialog(id){
this.menuDialogVis = true;
// 角色id赋值
this.roleId = id;
//请求菜单数据
this.request.get("/menu",{
params: {
name: ""
}
}).then(res => {
this.menuData = res.data;
//展开菜单数据
this.expends = this.menuData.map(v => v.id);
})
// 展开已拥有的菜单
this.request.get("/role/roleMenu/"+id).then(res => {
this.checks = res.data;
})
},
//保存角色下的菜单
saveRoleMenu(){
console.log('======',this.$refs.tree.getCheckedKeys());
this.request.post("/role/roleMenu/"+ this.roleId, this.$refs.tree.getCheckedKeys()).then(res => {
if(res.code === "200"){
this.$message.success("保存成功");
this.menuDialogVis = false;
}else {
this.$message.error("保存失败");
}
})
},
// 重置按钮
resetQuery(){
this.username = "";
this.pageNum = 1;
this.pageSize = 5;
this.getList();
},
handleSizeChange(val) {
this.pageSize = val;
},
handleCurrentChange(val) {
this.pageNum = val;
this.getList();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id);
this.single = selection.length != 1;
this.multiple = !selection.length;
},
// 新增
handleAdd(){
this.dialogFormVisible = true;
this.form = {};
},
save(){
this.request.post("/role",this.form).then(res => {
if(res.code === "200" || res.code === 200){
this.$message.success("操作成功")
}else {
this.$message.error("操作失败")
}
this.dialogFormVisible = false;
this.getList();
})
},
// 修改
handleUpdate(row){
// 表单置空
this.reset();
// 重新查询数据
const roleId = row.id || this.ids;
this.request.get('/role/'+roleId).then(response => {
this.form = response.data;
this.dialogFormVisible = true;
});
},
reset(){
this.form.roleKey = undefined;
this.form.name = undefined;
this.form.description = undefined;
},
// 删除
handleDelete(row){
let _this = this;
const roleIds = row.id || this.ids;
this.$confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?', '删除角色', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
_this.request.delete("/role/"+roleIds).then(res=>{
if(res.code === "200" || res.code === 200){
_this.$message.success("删除成功")
}else {
_this.$message.error("删除失败")
}
this.getList();
})
}).catch(() => {
});
}
},
};
</script>
2 第二个bug
启动成功前端访问地址,弹出的是404页面不是登录页面
2.1 修改路由router下面的index.js
修改的地方
// 第一处
{
path: '/404',
name: '404',
component: () => import('../views/404.vue')
}
// 第二处
// 路由守卫
router.beforeEach((to, from, next) => {
// localStorage.setItem('currentPathName',to.name); // 设置当前的路由名称,为了在Header组件中去使用
// store.commit('setPath') // 触发store的数据更新
// 未找到路由情况
if(!to.matched.length){
const storeMenus = localStorage.getItem("menus");
if(storeMenus){ // 有菜单没有找到路由,跳转至 404页面
next("/404")
}else { // // 没有菜单,直接跳转至登录页
next("/login")
}
}
next() // 放行路由
})
完整的代码
import Vue from 'vue'
import VueRouter from 'vue-router'
import Manage from '../views/Manage.vue'
import store from "@/store";
Vue.use(VueRouter)
//定义一个路由对象数组
const routes = [
{
path: '/login',
name: '登录',
component: () => import('../views/Login.vue')
},
{
path: '/register',
name: '注册',
component: () => import('../views/Register.vue')
},
{
path: '/404',
name: '404',
component: () => import('../views/404.vue')
}
]
//使用路由对象数组创建路由实例,供main.js引用
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
// 注意:刷新页面会导致页面路由重置
export const setRoutes = () => {
const storeMenus = localStorage.getItem("menus");
if (storeMenus) {
// 获取当前的路由对象名称数组
const currentRouteNames = router.getRoutes().map(v => v.name)
if (!currentRouteNames.includes('Manage')) {
// 拼装动态路由
const manageRoute = { path: '/', name: 'Manage', component: () => import('../views/Manage.vue'), redirect: "/home", children: [
{ path: 'person', name: '个人信息', component: () => import('../views/Person.vue')},
// { path: 'password', name: '修改密码', component: () => import('../views/Password.vue')}
] }
const menus = JSON.parse(storeMenus)
menus.forEach(item => {
if (item.path) { // 当且仅当path不为空的时候才去设置路由
let itemMenu = { path: item.path.replace("/", ""), name: item.name, component: () => import('../views/' + item.pagePath + '.vue'),meta: { title: item.name }}
manageRoute.children.push(itemMenu)
} else if(item.children.length) {
item.children.forEach(item => {
if (item.path) {
let itemMenu = { path: item.path.replace("/", ""), name: item.name, component: () => import('../views/' + item.pagePath + '.vue'),meta: { title: item.name }}
manageRoute.children.push(itemMenu)
}
})
}
})
// 动态添加到现在的路由对象中去
router.addRoute(manageRoute)
}
}
}
// 重置我就再set一次路由
setRoutes()
// 路由守卫
router.beforeEach((to, from, next) => {
// localStorage.setItem('currentPathName',to.name); // 设置当前的路由名称,为了在Header组件中去使用
// store.commit('setPath') // 触发store的数据更新
// 未找到路由情况
if(!to.matched.length){
const storeMenus = localStorage.getItem("menus");
if(storeMenus){ // 有菜单没有找到路由,跳转至 404页面
next("/404")
}else { // // 没有菜单,直接跳转至登录页
next("/login")
}
}
// 其他情况
next() // 放行路由
})
export default router
总结
- 动态菜单完结,基本项目也快接近尾声。
写在最后
如果此文对您有所帮助,请帅戈靓女们务必不要吝啬你们的Zan,感谢!!不懂的可以在评论区评论,有空会及时回复。
文章会一直更新