第24讲 菜单管理列表制作
1、api下新建menu.js
import http from '@/utils/http'
export const getMenuListApi = async() =>{
return await http.get("/api/menu/list",null)
}
2、sysMenuList.vue
<template>
<el-main>
<el-form size="small">
<el-form-item>
<el-button type="primary" icon="el-icon-plus">新增</el-button>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table
:height="tableHeight"
:data="tableData"
border
stripe
row-key="id"
default-expand-all
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column prop="date" label="日期" sortable width="180">
</el-table-column>
<el-table-column prop="name" label="姓名" sortable width="180">
</el-table-column>
<el-table-column prop="address" label="地址"> </el-table-column>
</el-table>
</el-main>
</template>
<script>
import {
getMenuListApi} from '@/api/menu'
export default {
data() {
return {
//表格高度
tableHeight: 0,
//表格数据
tableData: [
{
id: 1,
date: "2016-05-02",
name: "王小虎",
address: "上海市普陀区金沙江路 1518 弄",
},
{
id: 2,
date: "2016-05-04",
name: "王小虎",
address: "上海市普陀区金沙江路 1517 弄",
},
{
id: 3,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
children: [
{
id: 31,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
},
{
id: 32,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
},
],
},
{
id: 4,
date: "2016-05-03",
name: "王小虎",
address: "上海市普陀区金沙江路 1516 弄",
},
],
};
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
created(){
this.getList()
},
methods:{
async getList(){
let res = await getMenuListApi()
if(res && res.code == 200){
console.log(res)
// this.tableData = res.data
}
}
}
};
</script>
<style lang="scss" scoped>
</style>
第25讲 新增菜单制作
<template>
<el-main>
<el-form size="small">
<el-form-item>
<el-button @click="addBtn" type="primary" icon="el-icon-plus"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table
:height="tableHeight"
:data="tableData"
border
stripe
row-key="id"
default-expand-all
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column prop="date" label="日期" sortable width="180">
</el-table-column>
<el-table-column prop="name" label="姓名" sortable width="180">
</el-table-column>
<el-table-column prop="address" label="地址"> </el-table-column>
</el-table>
<!-- 新增、编辑 -->
<sys-dialog
:title="dialog.title"
:height="dialog.height"
:width="dialog.width"
:visible="dialog.visible"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addRef"
:rules="rules"
label-width="80px"
size="small"
style="margin-right:8px;"
>
<el-row>
<el-col :span="24" :offset="0">
<el-form-item label="菜单类型">
<el-radio-group v-model="addModel.type">
<el-radio :label="'0'">目录</el-radio>
<el-radio :label="'1'">菜单</el-radio>
<el-radio :label="'2'">按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="上级菜单">
<!-- <el-input type="hidden" v-model="addModel.parentId"></el-input> -->
<el-input v-model="addModel.parentName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="菜单名称">
<el-input v-model="addModel.title"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col v-if="addModel.type != '2'" :span="12" :offset="0">
<el-form-item label="菜单图标">
<el-input v-model="addModel.icon"></el-input>
</el-form-item>
</el-col>
<el-col v-if="addModel.type == '1'" :span="12" :offset="0">
<el-form-item label="路由名称">
<el-input v-model="addModel.name"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="addModel.type == '1'">
<el-col :span="12" :offset="0">
<el-form-item label="路由地址">
<el-input v-model="addModel.path"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="组件路径">
<el-input v-model="addModel.url"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="权限字段">
<el-input v-model="addModel.code"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="菜单序号">
<el-input v-model="addModel.orderNum"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import SysDialog from "@/components/dialog/SysDialog.vue";
import {
getMenuListApi } from "@/api/menu";
export default {
// 注册组件
components: {
SysDialog,
},
data() {
return {
//表单验证规则
rules: {
},
//表单数据
addModel: {
editType: "", // 0:新增 1:编辑
menuId: "",
type: "",
parentId: "",
title: "",
code: "",
name: "",
path: "",
url: "",
icon: "",
parentName: "",
orderNum: "",
},
//弹框属性
dialog: {
width:650,
title: "",
height: 280,
visible: false,
},
//表格高度
tableHeight: 0,
//表格数据
tableData: [
{
id: 1,
date: "2016-05-02",
name: "王小虎",
address: "上海市普陀区金沙江路 1518 弄",
},
{
id: 2,
date: "2016-05-04",
name: "王小虎",
address: "上海市普陀区金沙江路 1517 弄",
},
{
id: 3,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
children: [
{
id: 31,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
},
{
id: 32,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
},
],
},
{
id: 4,
date: "2016-05-03",
name: "王小虎",
address: "上海市普陀区金沙江路 1516 弄",
},
],
};
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
created() {
this.getList();
},
methods: {
//新增按钮
addBtn() {
//设置弹框属性
this.dialog.title = "新增菜单";
this.dialog.visible = true;
},
//弹框确定
onConfirm() {
this.dialog.visible = false;
},
//弹框关闭
onClose() {
this.dialog.visible = false;
},
async getList() {
let res = await getMenuListApi();
if (res && res.code == 200) {
console.log(res);
// this.tableData = res.data
}
},
},
};
</script>
<style lang="scss" scoped>
</style>
第26讲选择上级菜单
1、SysMenuService接口添加如下方法
List<SysMenu> parentList();
实现类
@Override
public List<SysMenu> parentList() {
String[] types = {
"0","1"};
QueryWrapper<SysMenu> query = new QueryWrapper<>();
query.lambda().in(SysMenu::getType, Arrays.asList(types)).orderByAsc(SysMenu::getOrderNum);
List<SysMenu> menuList = this.baseMapper.selectList(query);
//组装顶级菜单,防止无数据的时候,没有菜单
SysMenu menu = new SysMenu();
menu.setMenuId(0L);
menu.setParentId(-1L);
menu.setTitle("顶级菜单");
menuList.add(menu);
List<SysMenu> list = MakeTree.makeMenuTree(menuList, -1L);
return list;
}
2、控制器
//上级菜单列表
@GetMapping("/parent")
public ResultVo getParentList(){
List<SysMenu> list = sysMenuService.parentList();
return ResultUtils.success("查询成功",list);
}
3、api/menu.js
//上级菜单树
export const getParentMenuListApi = async() =>{
return await http.get("/api/menu/parent",null)
}
4、上级菜单弹框
<template>
<el-main>
<el-form size="small">
<el-form-item>
<el-button @click="addBtn" type="primary" icon="el-icon-plus"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table
:height="tableHeight"
:data="tableData"
border
stripe
row-key="id"
default-expand-all
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column prop="date" label="日期" sortable width="180">
</el-table-column>
<el-table-column prop="name" label="姓名" sortable width="180">
</el-table-column>
<el-table-column prop="address" label="地址"> </el-table-column>
</el-table>
<!-- 新增、编辑 -->
<sys-dialog
:title="dialog.title"
:height="dialog.height"
:width="dialog.width"
:visible="dialog.visible"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addRef"
:rules="rules"
label-width="80px"
size="small"
style="margin-right: 8px"
>
<el-row>
<el-col :span="24" :offset="0">
<el-form-item label="菜单类型">
<el-radio-group v-model="addModel.type">
<el-radio :label="'0'">目录</el-radio>
<el-radio :label="'1'">菜单</el-radio>
<el-radio :label="'2'">按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="上级菜单">
<!-- <el-input type="hidden" v-model="addModel.parentId"></el-input> -->
<el-input
@click.native="selectParent"
readonly
v-model="addModel.parentName"
></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="菜单名称">
<el-input v-model="addModel.title"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col v-if="addModel.type != '2'" :span="12" :offset="0">
<el-form-item label="菜单图标">
<el-input v-model="addModel.icon"></el-input>
</el-form-item>
</el-col>
<el-col v-if="addModel.type == '1'" :span="12" :offset="0">
<el-form-item label="路由名称">
<el-input v-model="addModel.name"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="addModel.type == '1'">
<el-col :span="12" :offset="0">
<el-form-item label="路由地址">
<el-input v-model="addModel.path"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="组件路径">
<el-input v-model="addModel.url"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="权限字段">
<el-input v-model="addModel.code"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="菜单序号">
<el-input v-model="addModel.orderNum"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</sys-dialog>
<!-- 上级部门弹框 -->
<sys-dialog
:title="parentDialog.title"
:width="parentDialog.width"
:height="parentDialog.height"
:visible="parentDialog.visible"
@onClose="parentClose"
@onConfirm="parentConfirm"
>
<div slot="content">
<el-tree
ref="parentTree"
:data="parentData"
node-key="menuId"
:props="defaultProps"
empty-text="暂无数据"
:show-checkbox="false"
:highlight-current="true"
default-expand-all
:expand-on-click-node="false"
@node-click="handleNodeClick"
></el-tree>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import SysDialog from "@/components/dialog/SysDialog.vue";
import {
getMenuListApi, getParentMenuListApi } from "@/api/menu";
export default {
// 注册组件
components: {
SysDialog,
},
data() {
return {
defaultProps: {
children: "children",
label: "title",
},
//上级菜单树数据
parentData: [],
//上级弹框属性
parentDialog: {
width: 300,
title: "选择上级菜单",
height: 450,
visible: false,
},
//表单验证规则
rules: {
},
//表单数据
addModel: {
editType: "", // 0:新增 1:编辑
menuId: "",
type: "",
parentId: "",
title: "",
code: "",
name: "",
path: "",
url: "",
icon: "",
parentName: "",
orderNum: "",
},
//弹框属性
dialog: {
width: 650,
title: "",
height: 280,
visible: false,
},
//表格高度
tableHeight: 0,
//表格数据
tableData: [
{
id: 1,
date: "2016-05-02",
name: "王小虎",
address: "上海市普陀区金沙江路 1518 弄",
},
{
id: 2,
date: "2016-05-04",
name: "王小虎",
address: "上海市普陀区金沙江路 1517 弄",
},
{
id: 3,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
children: [
{
id: 31,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
},
{
id: 32,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
},
],
},
{
id: 4,
date: "2016-05-03",
name: "王小虎",
address: "上海市普陀区金沙江路 1516 弄",
},
],
selectNode: {
id: "",
title: "",
},
};
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
created() {
this.getList();
},
methods: {
//上级树节点点击事件
handleNodeClick(node) {
console.log(node);
this.selectNode.id = node.menuId
this.selectNode.title = node.title
},
parentConfirm() {
this.addModel.parentId = this.selectNode.id
this.addModel.parentName = this.selectNode.title
this.parentDialog.visible = false;
},
parentClose() {
this.parentDialog.visible = false;
},
//选择上级菜单
async selectParent() {
let res = await getParentMenuListApi();
if (res && res.code == 200) {
console.log(res);
this.parentData = res.data;
}
console.log(this.parentData);
this.parentDialog.visible = true;
},
//新增按钮
addBtn() {
//设置弹框属性
this.dialog.title = "新增菜单";
this.dialog.visible = true;
},
//弹框确定
onConfirm() {
this.dialog.visible = false;
},
//弹框关闭
onClose() {
this.dialog.visible = false;
},
async getList() {
let res = await getMenuListApi();
if (res && res.code == 200) {
console.log(res);
// this.tableData = res.data
}
},
},
};
</script>
<style lang="scss" scoped>
</style>
第27讲 菜单新增对接
1、api/menu.js添加如下方法
export const addMenuApi = async(parm) =>{
return await http.post("/api/menu",parm)
}
//编辑
export const editMenuApi = async(parm) =>{
return await http.put(parm)
}
2、sysMenuList.vue
<template>
<el-main>
<el-form size="small">
<el-form-item>
<el-button @click="addBtn" type="primary" icon="el-icon-plus"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table
:height="tableHeight"
:data="tableData"
border
stripe
row-key="menuId"
default-expand-all
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column prop="title" label="菜单名称"> </el-table-column>
<el-table-column prop="title" label="菜单图标">
<template slot-scope="scope">
<i :class="scope.row.icon"></i>
</template>
</el-table-column>
<el-table-column prop="name" label="菜单类型">
<template slot-scope="scope">
<el-tag v-if="scope.row.type == '0'">目录</el-tag>
<el-tag type="success" v-if="scope.row.type == '1'">菜单</el-tag>
<el-tag type="danger" v-if="scope.row.type == '2'">按钮</el-tag>
</template>
</el-table-column>
<el-table-column prop="name" label="路由名称"> </el-table-column>
<el-table-column prop="path" label="路由地址"> </el-table-column>
</el-table>
<!-- 新增、编辑 -->
<sys-dialog
:title="dialog.title"
:height="dialog.height"
:width="dialog.width"
:visible="dialog.visible"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addRef"
:rules="rules"
label-width="80px"
size="small"
style="margin-right: 8px"
>
<el-row>
<el-col :span="24" :offset="0">
<el-form-item prop="type" label="菜单类型">
<el-radio-group v-model="addModel.type">
<el-radio :label="'0'">目录</el-radio>
<el-radio :label="'1'">菜单</el-radio>
<el-radio :label="'2'">按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item prop="parentName" label="上级菜单">
<!-- <el-input type="hidden" v-model="addModel.parentId"></el-input> -->
<el-input
@click.native="selectParent"
v-model="addModel.parentName"
></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="title" label="菜单名称">
<el-input v-model="addModel.title"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col v-if="addModel.type != '2'" :span="12" :offset="0">
<el-form-item label="菜单图标">
<el-input v-model="addModel.icon"></el-input>
</el-form-item>
</el-col>
<el-col v-if="addModel.type == '1'" :span="12" :offset="0">
<el-form-item prop="name" label="路由名称">
<el-input v-model="addModel.name"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="addModel.type == '1'">
<el-col :span="12" :offset="0">
<el-form-item prop="path" label="路由地址">
<el-input v-model="addModel.path"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="url" label="组件路径">
<el-input v-model="addModel.url"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="权限字段">
<el-input v-model="addModel.code"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="菜单序号">
<el-input v-model="addModel.orderNum"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</sys-dialog>
<!-- 上级菜单 -->
<sys-dialog
:title="parentDialog.title"
:width="parentDialog.width"
:height="parentDialog.height"
:visible="parentDialog.visible"
@onClose="parentClose"
@onConfirm="parentConfirm"
>
<div slot="content">
<el-tree
:data="treeData"
:props="defaultProps"
@node-click="handleNodeClick"
></el-tree>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import SysDialog from "@/components/dialog/SysDialog.vue";
import {
getMenuListApi,
getParentMenuListApi,
addMenuApi,
editMenuApi,
} from "@/api/menu";
export default {
// 注册组件
components: {
SysDialog,
},
data() {
return {
defaultProps: {
children: "children",
label: "title",
},
//上级菜单数据
treeData: [],
//上级弹框属性
parentDialog: {
width: 300,
title: "选择上级菜单",
height: 450,
visible: false,
},
//表单验证规则
rules: {
type: [
{
trigger: "blur",
required: true,
message: "请选择菜单类型",
},
],
parentName: [
{
trigger: "blur",
required: true,
message: "请选择上级菜单",
},
],
title: [
{
trigger: "blur",
required: true,
message: "请填写菜单名称",
},
],
name: [
{
trigger: "blur",
required: true,
message: "请填写路由名称",
},
],
path: [
{
trigger: "blur",
required: true,
message: "请填写路由地址",
},
],
url: [
{
trigger: "blur",
required: true,
message: "请填写组件路径",
},
],
},
//表单数据
addModel: {
editType: "", // 0:新增 1:编辑
menuId: "",
type: "",
parentId: "",
title: "",
code: "",
name: "",
path: "",
url: "",
icon: "",
parentName: "",
orderNum: "",
},
//弹框属性
dialog: {
width: 650,
title: "",
height: 280,
visible: false,
},
//表格高度
tableHeight: 0,
//表格数据
tableData: [],
//树选择的数据
selectNode: {
id: "",
title: "",
},
};
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
created() {
this.getList();
},
methods: {
//上级菜单树点击事件
handleNodeClick(node) {
console.log(node);
this.selectNode.id = node.menuId;
this.selectNode.title = node.title;
},
//上级菜单确定事件
parentConfirm() {
this.addModel.parentId = this.selectNode.id;
this.addModel.parentName = this.selectNode.title;
this.parentDialog.visible = false;
console.log(this.addModel);
},
//上级菜单关闭事件
parentClose() {
this.parentDialog.visible = false;
},
//选择上级菜单事件
async selectParent() {
//查询上级菜单树数据
let res = await getParentMenuListApi();
if (res && res.code == 200) {
this.treeData = res.data;
}
this.parentDialog.visible = true;
},
//新增按钮
addBtn() {
//设置弹框属性
this.dialog.title = "新增菜单";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
this.addModel.editType = "0";
},
//弹框确定
onConfirm() {
this.$refs.addRef.validate(async (valid) => {
if (valid) {
let res = null;
if (this.addModel.editType == "0") {
res = await addMenuApi(this.addModel);
} else {
res = await editMenuApi(this.addModel);
}
if (res && res.code == 200) {
this.getList();
this.dialog.visible = false;
}
}
});
},
//弹框关闭
onClose() {
this.dialog.visible = false;
},
async getList() {
let res = await getMenuListApi();
if (res && res.code == 200) {
console.log(res);
this.tableData = res.data;
}
},
},
};
</script>
<style lang="scss" scoped>
</style>
第28讲 菜单删除接口对接
1、api/menu.js添加如下方法
import http from '@/utils/http'
//列表
export const getMenuListApi = async() =>{
return await http.get("/api/menu/list",null)
}
//上级列表
export const getParentMenuListApi = async() =>{
return await http.get("/api/menu/parent",null)
}
//新增
export const addMenuApi = async(parm) =>{
return await http.post("/api/menu",parm)
}
//编辑
export const editMenuApi = async(parm) =>{
return await http.put("/api/menu",parm)
}
//删除
export const deleteMenuApi = async(parm) =>{
return await http.delete("/api/menu",parm)
}
2、sysMenuList.vue
<template>
<el-main>
<el-form size="small">
<el-form-item>
<el-button @click="addBtn" type="primary" icon="el-icon-plus"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table
:height="tableHeight"
:data="tableData"
border
stripe
row-key="menuId"
default-expand-all
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column prop="title" label="菜单名称"> </el-table-column>
<el-table-column prop="title" label="菜单图标">
<template slot-scope="scope">
<i :class="scope.row.icon"></i>
</template>
</el-table-column>
<el-table-column prop="name" label="菜单类型">
<template slot-scope="scope">
<el-tag v-if="scope.row.type == '0'">目录</el-tag>
<el-tag type="success" v-if="scope.row.type == '1'">菜单</el-tag>
<el-tag type="danger" v-if="scope.row.type == '2'">按钮</el-tag>
</template>
</el-table-column>
<el-table-column prop="name" label="路由名称"> </el-table-column>
<el-table-column prop="path" label="路由地址"> </el-table-column>
<el-table-column label="操作" align="center" width="180">
<template slot-scope="scope">
<el-button
type="primary"
icon="el-icon-edit"
size="small"
@click="editBtn(scope.row)"
>编辑</el-button
>
<el-button
type="danger"
icon="el-icon-delete"
size="small"
@click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 新增、编辑 -->
<sys-dialog
:title="dialog.title"
:height="dialog.height"
:width="dialog.width"
:visible="dialog.visible"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addRef"
:rules="rules"
label-width="80px"
size="small"
style="margin-right: 8px"
>
<el-row>
<el-col :span="24" :offset="0">
<el-form-item prop="type" label="菜单类型">
<el-radio-group v-model="addModel.type">
<el-radio :label="'0'">目录</el-radio>
<el-radio :label="'1'">菜单</el-radio>
<el-radio :label="'2'">按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item prop="parentName" label="上级菜单">
<!-- <el-input type="hidden" v-model="addModel.parentId"></el-input> -->
<el-input
@click.native="selectParent"
v-model="addModel.parentName"
></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="title" label="菜单名称">
<el-input v-model="addModel.title"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col v-if="addModel.type != '2'" :span="12" :offset="0">
<el-form-item label="菜单图标">
<el-input v-model="addModel.icon"></el-input>
</el-form-item>
</el-col>
<el-col v-if="addModel.type == '1'" :span="12" :offset="0">
<el-form-item prop="name" label="路由名称">
<el-input v-model="addModel.name"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="addModel.type == '1'">
<el-col :span="12" :offset="0">
<el-form-item prop="path" label="路由地址">
<el-input v-model="addModel.path"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="url" label="组件路径">
<el-input v-model="addModel.url"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="权限字段">
<el-input v-model="addModel.code"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="菜单序号">
<el-input v-model="addModel.orderNum"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</sys-dialog>
<!-- 上级菜单 -->
<sys-dialog
:title="parentDialog.title"
:width="parentDialog.width"
:height="parentDialog.height"
:visible="parentDialog.visible"
@onClose="parentClose"
@onConfirm="parentConfirm"
>
<div slot="content">
<el-tree
ref="parentTree"
:data="treeData"
node-key="menuId"
:props="defaultProps"
empty-text="暂无数据"
:show-checkbox="false"
:highlight-current="true"
default-expand-all
:expand-on-click-node="false"
@node-click="handleNodeClick"
>
<div slot-scope="{ node, data }">
<!-- 如果没有下级,显示文档图标 -->
<span v-if="data.children.length == 0">
<i style="margin-left: 3px" class="el-icon-document"></i>
</span>
<!-- 有下级,判断是否展开 -->
<span v-else @click.stop="openBtn(data)">
<i
v-if="data.open"
style="margin-left: 3px"
class="el-icon-plus"
></i>
<i v-else style="margin-left: 3px" class="el-icon-minus"></i>
</span>
<span style="margin-left: 3px">{
{
node.label }}</span>
</div>
</el-tree>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import SysDialog from "@/components/dialog/SysDialog.vue";
import {
getMenuListApi,
getParentMenuListApi,
addMenuApi,
editMenuApi,
deleteMenuApi,
} from "@/api/menu";
export default {
// 注册组件
components: {
SysDialog,
},
data() {
return {
defaultProps: {
children: "children",
label: "title",
},
//上级菜单数据
treeData: [],
//上级弹框属性
parentDialog: {
width: 300,
title: "选择上级菜单",
height: 450,
visible: false,
},
//表单验证规则
rules: {
type: [
{
trigger: "blur",
required: true,
message: "请选择菜单类型",
},
],
parentName: [
{
trigger: "blur",
required: true,
message: "请选择上级菜单",
},
],
title: [
{
trigger: "blur",
required: true,
message: "请填写菜单名称",
},
],
name: [
{
trigger: "blur",
required: true,
message: "请填写路由名称",
},
],
path: [
{
trigger: "blur",
required: true,
message: "请填写路由地址",
},
],
url: [
{
trigger: "blur",
required: true,
message: "请填写组件路径",
},
],
},
//表单数据
addModel: {
editType: "", // 0:新增 1:编辑
menuId: "",
type: "",
parentId: "",
title: "",
code: "",
name: "",
path: "",
url: "",
icon: "",
parentName: "",
orderNum: "",
},
//弹框属性
dialog: {
width: 650,
title: "",
height: 280,
visible: false,
},
//表格高度
tableHeight: 0,
//表格数据
tableData: [],
//树选择的数据
selectNode: {
id: "",
title: "",
},
};
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
created() {
this.getList();
},
methods: {
//编辑
editBtn(row) {
//设置弹框属性
this.dialog.title = "编辑菜单";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
//把要编辑的数据放到表单绑定的数据里面,回显
this.$objCoppy(row, this.addModel);
this.addModel.editType = "1";
},
//删除按钮
async deleteBtn(row) {
const confirm = await this.$myconfirm("确定删除该数据吗?");
if (confirm) {
let res = await deleteMenuApi({
menuId: row.menuId });
if (res && res.code == 200) {
this.$message({
type: "success", message: res.msg });
this.getList();
}
}
},
//上级部门节点加号和减号点击事件
openBtn(data) {
data.open = !data.open;
this.$refs.parentTree.store.nodesMap[data.menuId].expanded = !data.open;
},
//上级菜单树点击事件
handleNodeClick(node) {
console.log(node);
this.selectNode.id = node.menuId;
this.selectNode.title = node.title;
},
//上级菜单确定事件
parentConfirm() {
this.addModel.parentId = this.selectNode.id;
this.addModel.parentName = this.selectNode.title;
this.parentDialog.visible = false;
console.log(this.addModel);
},
//上级菜单关闭事件
parentClose() {
this.parentDialog.visible = false;
},
//选择上级菜单事件
async selectParent() {
//查询上级菜单树数据
let res = await getParentMenuListApi();
if (res && res.code == 200) {
this.treeData = res.data;
}
this.parentDialog.visible = true;
},
//新增按钮
addBtn() {
//设置弹框属性
this.dialog.title = "新增菜单";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
this.addModel.editType = "0";
},
//弹框确定
onConfirm() {
this.$refs.addRef.validate(async (valid) => {
if (valid) {
let res = null;
if (this.addModel.editType == "0") {
res = await addMenuApi(this.addModel);
} else {
res = await editMenuApi(this.addModel);
}
if (res && res.code == 200) {
this.$message({
type: "success", message: res.msg });
this.getList();
this.dialog.visible = false;
}
}
});
},
//弹框关闭
onClose() {
this.dialog.visible = false;
},
async getList() {
let res = await getMenuListApi();
if (res && res.code == 200) {
console.log(res);
this.tableData = res.data;
}
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .el-tree {
// 将每一行的设置为相对定位 方便后面before after 使用绝对定位来固定位置
.el-tree-node {
position: relative;
padding-left: 10px;
}
// 子集像右偏移 给数线留出距离
.el-tree-node__children {
padding-left: 20px;
}
//这是竖线
.el-tree-node :last-child:before {
height: 40px;
}
.el-tree > .el-tree-node:before {
border-left: none;
}
.el-tree > .el-tree-node:after {
border-top: none;
}
//这自定义的线 的公共部分
.el-tree-node:before,
.el-tree-node:after {
content: "";
left: -4px;
position: absolute;
right: auto;
border-width: 1px;
}
.tree :first-child .el-tree-node:before {
border-left: none;
}
// 竖线
.el-tree-node:before {
border-left: 1px dotted #d9d9d9;
bottom: 0px;
height: 100%;
top: -25px;
width: 1px;
}
//横线
.el-tree-node:after {
border-top: 1px dotted #d9d9d9;
height: 20px;
top: 14px;
width: 24px;
}
.el-tree-node__expand-icon.is-leaf {
width: 8px;
}
//去掉elementui自带的展开按钮 一个向下的按钮,打开时向右
.el-tree-node__content > .el-tree-node__expand-icon {
display: none;
}
//每一行的高度
.el-tree-node__content {
line-height: 30px;
height: 30px;
padding-left: 10px !important;
}
}
//去掉最上级的before after 即是去电最上层的连接线
::v-deep .el-tree > div {
&::before {
display: none;
}
&::after {
display: none;
}
}
</style>
第29讲 用户分配角色
1、api/user.js添加getRoleListApi 和 getRoleByUserIdApi()和方法
//角色列表
export const getRoleListApi = async()=>{
return await http.get("/api/user/roleList")
}
//根据用户Id查询角色
export const getRoleByUserIdApi = async(parm)=>{
return await http.get("/api/user/getRoleByUserId",parm)
}
2、新建SysRoleMenu实体类
package com.itmk.web.sys_role_menu.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Data
@TableName("sys_role_menu")
public class SysRoleMenu {
@TableId(type = IdType.AUTO)
private Long roleMenuId;
private Long roleId;
private Long menuId;
}
3、新建SysRoleMenuMapper接口
package com.itmk.web.sys_role_menu.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itmk.web.sys_role_menu.entity.SysRoleMenu;
/**
* @Author java实战基地
* @Version 3501754007
*/
public interface SysRoleMenuMapper extends BaseMapper<SysRoleMenu> {
}
映射文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itmk.web.sys_role_menu.mapper.SysRoleMenuMapper">
</mapper>
4、新建SysRoleMenuService接口
package com.itmk.web.sys_role_menu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itmk.web.sys_role_menu.entity.SysRoleMenu;
/**
* @Author java实战基地
* @Version 3501754007
*/
public interface SysRoleMenuService extends IService<SysRoleMenu> {
}
实现类
package com.itmk.web.sys_role_menu.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itmk.web.sys_role_menu.entity.SysRoleMenu;
import com.itmk.web.sys_role_menu.mapper.SysRoleMenuMapper;
import com.itmk.web.sys_role_menu.service.SysRoleMenuService;
import org.springframework.stereotype.Service;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Service
public class SysRoleMenuServiceImpl extends ServiceImpl<SysRoleMenuMapper, SysRoleMenu> implements SysRoleMenuService {
}
5、新建SysUserRole实体类
package com.itmk.web.sys_user_role.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Data
@TableName("sys_user_role")
public class SysUserRole {
@TableId(type = IdType.AUTO)
private Long userRoleId;
private Long userId;
private Long roleId;
}
6、SysUserRoleMapper接口
package com.itmk.web.sys_user_role.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itmk.web.sys_user_role.entity.SysUserRole;
/**
* @Author java实战基地
* @Version 3501754007
*/
public interface SysUserRoleMapper extends BaseMapper<SysUserRole> {
}
映射文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itmk.web.sys_user_role.mapper.SysUserRoleMapper">
</mapper>
7、新建SysUserRoleService接口
package com.itmk.web.sys_user_role.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itmk.web.sys_user_role.entity.SysUserRole;
/**
* @Author java实战基地
* @Version 3501754007
*/
public interface SysUserRoleService extends IService<SysUserRole> {
}
实现类
package com.itmk.web.sys_user_role.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itmk.web.sys_user_role.entity.SysUserRole;
import com.itmk.web.sys_user_role.mapper.SysUserRoleMapper;
import com.itmk.web.sys_user_role.service.SysUserRoleService;
import org.springframework.stereotype.Service;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Service
public class SysUserRoleServiceImpl extends ServiceImpl<SysUserRoleMapper, SysUserRole> implements SysUserRoleService {
}
8、SysUserService新增add和edit方法
package com.itmk.web.sys_user.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itmk.web.sys_user.entity.PageParm;
import com.itmk.web.sys_user.entity.SysUser;
public interface SysUserService extends IService<SysUser> {
IPage<SysUser> list(PageParm parm);
//新增
void add(SysUser user);
//编辑
void edit(SysUser user);
}
实现类
package com.itmk.web.sys_user.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itmk.web.sys_user.entity.PageParm;
import com.itmk.web.sys_user.entity.SysUser;
import com.itmk.web.sys_user.mapper.SysUserMapper;
import com.itmk.web.sys_user.service.SysUserService;
import com.itmk.web.sys_user_role.entity.SysUserRole;
import com.itmk.web.sys_user_role.service.SysUserRoleService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
@Autowired
private SysUserRoleService sysUserRoleService;
@Override
public IPage<SysUser> list(PageParm parm) {
//构造分页对象
IPage<SysUser> page = new Page<>();
page.setCurrent(parm.getCurrentPage());
page.setSize(parm.getPageSize());
//构造查询条件
QueryWrapper<SysUser> query = new QueryWrapper<>();
if(StringUtils.isNotEmpty(parm.getNickName())){
query.lambda().like(SysUser::getNickName,parm.getNickName());
}
if(StringUtils.isNotEmpty(parm.getPhone())){
query.lambda().like(SysUser::getPhone,parm.getPhone());
}
return this.baseMapper.selectPage(page,query);
}
@Override
@Transactional
public void add(SysUser user) {
//新增用户
int insert = this.baseMapper.insert(user);
//保存角色
if(insert > 0){
SysUserRole role = new SysUserRole();
role.setRoleId(user.getRoleId());
role.setUserId(user.getUserId());
sysUserRoleService.save(role);
}
}
@Override
@Transactional
public void edit(SysUser user) {
//编辑
int i = this.baseMapper.updateById(user);
//角色 :先删除,再插入
if(i > 0){
//先删除原来的角色
QueryWrapper<SysUserRole> query = new QueryWrapper<>();
query.lambda().eq(SysUserRole::getUserId,user.getUserId());
sysUserRoleService.remove(query);
//保存
SysUserRole role = new SysUserRole();
role.setUserId(user.getUserId());
role.setRoleId(user.getRoleId());
sysUserRoleService.save(role);
}
}
}
9、SysUserController控制器
package com.itmk.web.sys_user.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.itmk.utils.ResultUtils;
import com.itmk.utils.ResultVo;
import com.itmk.web.sys_role.entity.SysRole;
import com.itmk.web.sys_role.service.SysRoleService;
import com.itmk.web.sys_user.entity.PageParm;
import com.itmk.web.sys_user.entity.SysUser;
import com.itmk.web.sys_user.service.SysUserService;
import com.itmk.web.sys_user_role.entity.SysUserRole;
import com.itmk.web.sys_user_role.service.SysUserRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping("/api/user")
public class SysUserController {
@Autowired
private SysUserService sysUserService;
@Autowired
private SysRoleService sysRoleService;
@Autowired
private SysUserRoleService sysUserRoleService;
//新增用户
@PostMapping
public ResultVo addUser(@RequestBody SysUser user) {
//判断账户是否被占用
QueryWrapper<SysUser> query = new QueryWrapper<>();
query.lambda().eq(SysUser::getUsername, user.getUsername());
SysUser one = sysUserService.getOne(query);
if (one != null) {
return ResultUtils.error("账户被占用!");
}
user.setIsAdmin("0");
user.setCreateTime(new Date());
//入库处理
sysUserService.add(user);
return ResultUtils.success("新增用户成功!");
}
//编辑用户
@PutMapping
public ResultVo editUser(@RequestBody SysUser user) {
//判断账户是否被占用
QueryWrapper<SysUser> query = new QueryWrapper<>();
query.lambda().eq(SysUser::getUsername, user.getUsername());
SysUser one = sysUserService.getOne(query);
if (one != null && one.getUserId() != user.getUserId()) {
return ResultUtils.error("账户被占用!");
}
user.setUpdateTime(new Date());
//更新处理
sysUserService.edit(user);
return ResultUtils.success("编辑用户成功!");
}
//删除用户
@DeleteMapping("/{userId}")
public ResultVo deleteUser(@PathVariable("userId") Long userId) {
boolean remove = sysUserService.removeById(userId);
if (remove) {
return ResultUtils.success("删除成功!");
}
return ResultUtils.error("删除失败!");
}
//列表查询
@GetMapping("/list")
public ResultVo getList(PageParm parm) {
IPage<SysUser> list = sysUserService.list(parm);
//密码不显示
list.getRecords().stream().forEach(item -> {
item.setPassword("");
});
return ResultUtils.success("查询成功", list);
}
//查询角色列表
@GetMapping("/roleList")
public ResultVo getRoleList(){
List<SysRole> list = sysRoleService.list();
return ResultUtils.success("查询成功",list);
}
//查询用户对应的角色
@GetMapping("/getRoleByUserId")
public ResultVo getRoleByUserId(Long userId){
QueryWrapper<SysUserRole> query = new QueryWrapper<>();
query.lambda().eq(SysUserRole::getUserId,userId);
SysUserRole one = sysUserRoleService.getOne(query);
return ResultUtils.success("查询成功",one);
}
}
第30讲 登录页面制作
<template>
<div class="logincontainer">
<el-form
class="loginform"
:model="addModel"
ref="loginForm"
:rules="rules"
:inline="false"
size="medium"
>
<el-form-item>
<span class="loginTitle">高校宿舍管理系统</span>
</el-form-item>
<el-form-item prop="username">
<el-input
v-model="addModel.username"
placeholder="请输入账户"
></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="addModel.password"
placeholder="请输入密码"
></el-input>
</el-form-item>
<el-form-item prop="userType">
<el-radio-group v-model="addModel.userType">
<el-radio :label="0">学生</el-radio>
<el-radio :label="1">管理</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-row :gutter="20">
<el-col :span="12" :offset="0">
<el-button class="loginbtn" type="primary" @click="onSubmit"
>登录</el-button
>
</el-col>
<el-col :span="12" :offset="0">
<el-button class="loginbtn">取消</el-button>
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
//表单数据
addModel: {
username: "",
password: "",
userType: "",
},
//表单验证规则
rules: {
username: [
{
trigger: "change",
required: true,
message: "请输入账户",
},
],
password: [
{
trigger: "change",
required: true,
message: "请输入密码",
},
],
userType: [
{
trigger: "change",
required: true,
message: "请选择用户类型",
},
],
},
};
},
methods: {
onSubmit() {
this.$refs.loginForm.validate((valid) => {
if (valid) {
console.log("验证通过");
console.log(this.addModel)
}
});
},
},
};
</script>
<style lang="scss" scoped>
.logincontainer {
height: 100%;
background: #fff;
background-image: url("../../assets/images/login_bg.png");
display: flex;
align-items: center;
justify-content: center;
background-size: 100% 100%;
.loginform {
height: 350px;
width: 450px;
background: #fff;
padding: 35px 20px;
border-radius: 10px;
.loginTitle {
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: #409eff;
font-weight: 600;
margin-bottom: 10px;
}
.loginbtn {
width: 100%;
}
}
}
</style>
第31讲 用户登录接口开发
依赖
<jwt.version>3.10.3</jwt.version>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${
jwt.version}</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
</dependency>
1、jwt工具类讲解
1.1、jwt配置文件
#jwt配置
jwt:
#颁发者
issuer: itmk
#秘钥
secret: com.itmk
#30分钟过期
expiration: 30
1.2、JwtUtils工具
package com.itmk.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Component
@Data
@ConfigurationProperties(prefix = "jwt")
public class JwtUtils {
//颁发者
private String issuer;
//密钥
private String secret;
// 过期时间 分钟
private int expiration;
/**
* @param map 自定义参数
*/
public String generateToken(Map<String, String> map) {
//设置令牌的过期时间
Calendar instance = Calendar.getInstance();
//设置失效时间
instance.add(Calendar.MINUTE, expiration);
//创建JWT builder
JWTCreator.Builder builder = JWT.create();
//payload
map.forEach((k, v) -> {
builder.withClaim(k, v);
});
String token = builder.withIssuer(issuer).withIssuedAt(new Date()).withExpiresAt(instance.getTime()) //指定令牌过期时间
.sign(Algorithm.HMAC256(secret));
return token;
}
/**
* 验证令牌是否合法
*
* @param token
*/
public boolean verify(String token) {
try {
JWT.require(Algorithm.HMAC256(secret)).build().verify(token);
} catch (JWTVerificationException e) {
return false;
}
return true;
}
/**
* 解析token
*
* @param token
* @return
*/
public DecodedJWT jwtDecode(String token) {
try {
return JWT.require(Algorithm.HMAC256(secret)).build().verify(token);
} catch (SignatureVerificationException e) {
throw new RuntimeException("token签名错误!");
} catch (AlgorithmMismatchException e) {
throw new RuntimeException("token算法不匹配!");
} catch (TokenExpiredException e) {
throw new RuntimeException("token过期!");
} catch (Exception e) {
throw new RuntimeException("token解析失败!");
}
}
}
2、登录接口
package com.itmk.web.login.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itmk.jwt.JwtUtils;
import com.itmk.utils.ResultUtils;
import com.itmk.utils.ResultVo;
import com.itmk.web.login.entity.LoginParm;
import com.itmk.web.login.entity.LoginResult;
import com.itmk.web.user.entity.User;
import com.itmk.web.user.service.UserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* @Author java实战基地
* @Version 3501754007
*/
@RestController
@RequestMapping("/api/login")
public class LoginController {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private SysUserService userService;
@PostMapping("/login")
public ResultVo login(@RequestBody LoginParm loginParm) {
if (StringUtils.isEmpty(loginParm.getUsername()) || StringUtils.isEmpty(loginParm.getPassword())) {
return ResultUtils.error("用户名或密码不能为空!");
}
//查询用户
QueryWrapper<User> query = new QueryWrapper<>();
query.lambda().eq(User::getUsername, loginParm.getUsername()).eq(User::getPassword,
DigestUtils.md5DigestAsHex(loginParm.getPassword().getBytes()));
User user = userService.getOne(query);
if (user == null) {
return ResultUtils.error("用户名或密码错误!");
}
//生成token
Map<String, String> map = new HashMap<>();
map.put("username", user.getUsername());
map.put("userId", Long.toString(user.getUserId()));
String token = jwtUtils.generateToken(map);
//构造返回值
LoginResult result = new LoginResult();
result.setUserId(user.getUserId());
result.setToken(token);
result.setUsername(user.getUsername());
return ResultUtils.success("登录成功", result);
}
}
package com.itmk.web.login.entity;
import lombok.Data;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Data
public class LoginParm {
private String username;
private String password;
private String userType;
}
package com.itmk.web.login.entity;
import lombok.Data;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Data
public class LoginResult {
private Long userId;
private String username;
private String token;
}
第32讲 登录接口对接
登录流程图
1、api/user.js添加loginApi()方法
import request from '@/utils/request'
import http from '@/utils/http'
export function login(data) {
return request({
url: '/vue-admin-template/user/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
url: '/vue-admin-template/user/info',
method: 'get',
params: {
token }
})
}
export function logout() {
return request({
url: '/vue-admin-template/user/logout',
method: 'post'
})
}
//获取用户列表
export const getListApi = async(parm) =>{
return await http.get("/api/user/list",parm)
}
//新增
export const addUserApi = async(parm) =>{
return await http.post("/api/user",parm)
}
//编辑
export const editUserApi = async(parm) =>{
return await http.put("/api/user",parm)
}
//删除
export const deleteUserApi = async(parm) =>{
return await http.delete("/api/user",parm)
}
//角色列表
export const getRoleListApi = async()=>{
return await http.get("/api/user/roleList")
}
//获取角色
export const getRoleApi = async(parm)=>{
return await http.get("/api/user/role",parm)
}
//登录对接
export const loginApi = async(parm)=>{
return await http.post("/api/login/login",parm)
}
2、utils下的auth.js添加存储用户id的方法
import Cookies from 'js-cookie'
const TokenKey = 'vue_admin_template_token'
const userIdKey = 'userId'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
//存储用户id
export function setUserId(userId) {
return sessionStorage.setItem(userIdKey, userId)
}
export function getUserId() {
return sessionStorage.getItem(userIdKey)
}
export function removeUserId() {
return sessionStorage.remove(userIdKey);
}
//sessionStorage清空
export function clearSession() {
return sessionStorage.clear()
}
3、store/user.js中的login修改为如下
// user login
login({
commit }, userInfo) {
const {
username, password,userType } = userInfo
return new Promise((resolve, reject) => {
loginApi({
username: username.trim(), password: password ,userType:userType}).then(response => {
console.log(response)
const {
data } = response
// commit('SET_TOKEN', data.token)
commit('SET_TOKEN', 'admin-token')
setToken(data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
4、登录页面
<template>
<div class="logincontainer">
<el-form
class="loginForm"
:model="addModel"
ref="loginForm"
:rules="rules"
:inline="false"
size="normal"
>
<el-form-item>
<span class="loginTitle">高校宿舍管理系统</span>
</el-form-item>
<el-form-item prop="username">
<el-input
placeholder="请输入账户"
v-model="addModel.username"
></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
placeholder="请输入密码"
v-model="addModel.password"
></el-input>
</el-form-item>
<el-form-item prop="userType">
<el-radio-group v-model="addModel.userType">
<el-radio :label="0">学生</el-radio>
<el-radio :label="1">管理员</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-row :gutter="20">
<el-col :span="12" :offset="0">
<el-button class="mybtn" type="primary" @click="onSubmit"
>登录</el-button
>
</el-col>
<el-col :span="12" :offset="0">
<el-button class="mybtn">取消</el-button>
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
addModel: {
username: "",
password: "",
userType: "",
},
rules: {
username: [
{
trigger: "change",
required: true,
message: "请输入账户",
},
],
password: [
{
trigger: "change",
required: true,
message: "请输入密码",
},
],
userType: [
{
trigger: "change",
required: true,
message: "请选择用户类型",
},
],
},
};
},
methods: {
onSubmit() {
this.$refs.loginForm.validate((valid) => {
if (valid) {
this.$store.dispatch("user/login", this.addModel).then(() => {
this.$router.push({
path: this.redirect || "/" });
});
}
});
},
},
};
</script>
<style lang="scss" scoped>
.logincontainer {
height: 100%;
background: #fff;
background-image: url("../../assets/images/login_bg.png");
display: flex;
align-items: center;
justify-content: center;
background-size: 100% 100%;
.loginForm {
height: 350px;
width: 450px;
background: #fff;
padding: 35px 20px;
border-radius: 10px;
.loginTitle {
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
font-weight: 600;
color: #409eff;
}
.mybtn {
width: 100%;
}
}
}
</style>
第33讲 分配权限树回显接口开发
1、SysMenuService接口新增getMenuByUserId()方法和getMenuByRoleId()方法
//根据用户id查询权限
List<SysMenu> getMenuByUserId(Long userId);
//根据角色id查询权限
List<SysMenu> getMenuByRoleId(Long roleId);
SysMenuServiceImpl实现类
@Override
public List<SysMenu> getMenuByUserId(Long userId) {
return this.baseMapper.getMenuByUserId(userId);
}
@Override
public List<SysMenu> getMenuByRoleId(Long roleId) {
return this.baseMapper.getMenuByRoleId(roleId);
}
2、SysMenuMapper接口新增getMenuByUserId()方法和getMenuByRoleId()方法
//根据用户id查询权限
List<SysMenu> getMenuByUserId(@Param("userId") Long userId);
//根据角色id查询权限
List<SysMenu> getMenuByRoleId(@Param("roleId") Long roleId);
3、SysMenuMapper.xml映射文件
<select id="getMenuByUserId" resultType="com.itmk.web.sys_menu.entity.SysMenu">
select m.* from sys_user_role as ur
left join sys_role as r on ur.role_id = r.role_id
left join sys_role_menu as rm on r.role_id = rm.role_id
left join sys_menu as m on rm.menu_id = m.menu_id
where ur.user_id =#{
userId}
order by m.order_num asc
</select>
<select id="getMenuByRoleId" resultType="com.itmk.web.sys_menu.entity.SysMenu">
select m.* from sys_role_menu as rm , sys_menu as m
where rm.menu_id = m.menu_id and rm.role_id =#{
roleId}
</select>
4、新建AssignVo实体类
package com.itmk.web.sys_role.entiy;
import com.itmk.web.sys_menu.entity.SysMenu;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class AssignVo {
//当前用户拥有的菜单
private List<SysMenu> menuList = new ArrayList<>();
//被分配的角色拥有的菜单id
private Object[] checkList;
}
5、SysRoleService接口新增getAssignShow()方法
参数实体类
package com.itmk.web.sys_role.entiy;
import lombok.Data;
@Data
public class AssignParm {
private Long userId;
private Long roleId;
}
//角色权限的回显
AssignVo getAssignShow(AssignParm parm);
实现类
@Override
public AssignVo getAssignShow(AssignParm parm) {
//查询当前用户的信息
SysUser user = sysUserService.getById(parm.getUserId());
//菜单数据
List<SysMenu> list = null;
if(user.getIsAdmin().equals("1")){
//如果是超级管理员,拥有所有的权限
QueryWrapper<SysMenu> query = new QueryWrapper<>();
query.lambda().orderByAsc(SysMenu::getOrderNum);
list = sysMenuService.list(query);
}else{
list = sysMenuService.getMenuByUserId(user.getUserId());
}
//组装树
List<SysMenu> menuList = MakeTree.makeMenuTree(list, 0L);
//查询角色原来的菜单
List<SysMenu> roleList = sysMenuService.getMenuByRoleId(parm.getRoleId());
List<Long> ids = new ArrayList<>();
Optional.ofNullable(roleList).orElse(new ArrayList<>()).stream().filter(item -> item != null).forEach(item ->{
ids.add(item.getMenuId());
});
//组装数据
AssignVo vo = new AssignVo();
vo.setMenuList(menuList);
vo.setCheckList(ids.toArray());
return vo;
}
6、SysRoleController控制器添加getAssingShow()方法
//查询角色权限树的回显
@GetMapping("/getAssingShow")
public ResultVo getAssingShow(AssignParm parm) {
AssignVo show = sysRoleService.getAssignShow(parm);
return ResultUtils.success("查询成功", show);
}
第34讲 分配权限回显对接
1、api/role.js添加assignRoleApi()方法
import http from '@/utils/http'
//列表
export const getListApi = async(parm) =>{
return await http.get("/api/role/list",parm)
}
//新增
export const addRoleApi = async(parm) =>{
return await http.post("/api/role",parm)
}
//编辑
export const editRoleApi = async(parm) =>{
return await http.put("/api/role",parm)
}
//删除
export const deleteRoleApi = async(parm) =>{
return await http.delete("/api/role",parm)
}
//分配权限回显
export const assignRoleApi = async(parm)=>{
return await http.get("/api/role/getAssingShow",parm)
}
2、sysRoleList.vue页面
<template>
<el-main>
<!-- 搜索栏 -->
<el-form
:model="listParm"
ref="searchRef"
label-width="80px"
:inline="true"
size="small"
>
<el-form-item>
<el-input
placeholder="请输入角色名称"
v-model="listParm.roleName"
></el-input>
</el-form-item>
<el-form-item>
<el-button @click="searchBtn" icon="el-icon-search">搜索</el-button>
<el-button @click="resetBtn" style="color: #ff7670" icon="el-icon-close"
>重置</el-button
>
<el-button type="primary" @click="addBtn" icon="el-icon-plus"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table
:height="tableHeight"
size="small"
:data="tableData"
border
stripe
>
<el-table-column prop="roleName" label="角色名称"></el-table-column>
<el-table-column prop="remark" label="角色备注"></el-table-column>
<el-table-column label="操作" align="center" width="300">
<template slot-scope="scope">
<el-button
type="primary"
size="small"
icon="el-icon-edit"
@click="editBtn(scope.row)"
>编辑</el-button
>
<el-button
type="primary"
size="small"
icon="el-icon-edit"
@click="assignBtn(scope.row)"
>分配权限</el-button
>
<el-button
type="danger"
size="small"
icon="el-icon-delete"
@click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="listParm.currentPage"
:page-sizes="[10, 20, 40, 80, 100]"
:page-size="listParm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="listParm.total"
background
>
</el-pagination>
<!-- 新增编辑弹框 -->
<sys-dialog
:title="dialog.title"
:visible="dialog.visible"
:height="dialog.height"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addRef"
:rules="rules"
label-width="80px"
size="small"
>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item prop="roleName" label="角色名称">
<el-input v-model="addModel.roleName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="roleType" label="角色类型">
<el-select v-model="addModel.roleType" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="角色备注">
<el-input v-model="addModel.remark"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</sys-dialog>
<!-- 分配权限弹框 -->
<sys-dialog
:title="assignDialog.title"
:height="assignDialog.height"
:width="assignDialog.width"
:visible="assignDialog.visible"
@confirm="assignConfirm"
@onClose="assingClose"
>
<div slot="content">
<el-tree
ref="assignTree"
:data="assignTreeData"
node-key="menuId"
:props="defaultProps"
empty-text="暂无数据"
:show-checkbox="true"
default-expand-all
:default-checked-keys="assignTreeChecked"
></el-tree>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import SysDialog from "@/components/dialog/SysDialog.vue";
import {
getListApi,
addRoleApi,
editRoleApi,
deleteRoleApi,
assignRoleApi,
} from "@/api/role";
import {
getUserId } from "@/utils/auth";
export default {
// 注册组件
components: {
SysDialog,
},
data() {
return {
defaultProps: {
children: "children",
label: "title",
},
//树数据
assignTreeData: [],
//角色原来的权限
assignTreeChecked: [],
//分配权限弹框属性
assignDialog: {
title: "",
height: 450,
width: 300,
visible: false,
},
//角色类型
options: [
{
value: "1",
label: "系统用户",
},
{
value: "2",
label: "学生",
},
],
//表单验证规则
rules: {
roleName: [
{
trigger: "blur",
required: true,
message: "请填写角色名称",
},
],
roleType: [
{
trigger: "blur",
required: true,
message: "请选择角色类型",
},
],
},
//表单数据
addModel: {
type: "", // 0 新增 1: 编辑
roleId: "",
roleName: "",
roleType: "",
remark: "",
},
//弹框属性
dialog: {
height: 150,
visible: false,
title: "",
},
//表格的高度
tableHeight: 0,
//表格数据
tableData: [],
//列表参数
listParm: {
roleName: "",
currentPage: 1,
pageSize: 10,
total: 0,
},
};
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
created() {
this.getList();
},
methods: {
//分配权限确定
assignConfirm() {
this.assignDialog.visible = false;
},
//分配权限取消
assingClose() {
this.assignDialog.visible = false;
},
//分配权限按钮
async assignBtn(row) {
//清空数据
this.roleId = "";
this.assignTreeData = [];
this.assignTreeChecked = [];
this.roleId = row.roleId;
//设置弹框属性
this.assignDialog.title = "为【" + row.roleName + "】分配权限";
this.assignDialog.visible = true;
//获取权限数据
let parm = {
userId: getUserId(),
roleId: this.roleId,
};
let res = await assignRoleApi(parm);
console.log(res);
if (res && res.code == 200) {
this.assignTreeData = res.data.menuList;
this.assignTreeChecked = res.data.checkList;
}
//如果角色原来有权限
if (this.assignTreeChecked.length > 0) {
let newArr = [];
this.assignTreeChecked.forEach((item) => {
this.checked(item, this.assignTreeData, newArr);
});
this.assignTreeChecked = newArr;
}
},
//找出所有的回显数据
checked(id, data, newArr) {
data.forEach((item) => {
if (item.menuId == id) {
//是不是末级
if (item.children && item.children.length == 0) {
newArr.push(item.menuId);
}
} else {
if (item.children && item.children.length != 0) {
this.checked(id, item.children, newArr);
}
}
});
},
//弹框关闭
onClose() {
this.dialog.visible = false;
},
//弹框确定
onConfirm() {
this.$refs.addRef.validate(async (valid) => {
if (valid) {
let res = null;
if (this.addModel.type == "0") {
res = await addRoleApi(this.addModel);
} else {
res = await editRoleApi(this.addModel);
}
if (res && res.code == 200) {
//信息提示
this.$message({
type: "success", message: res.msg });
//刷新列表
this.getList();
this.dialog.visible = false;
}
}
});
},
//获取表格数据
async getList() {
let res = await getListApi(this.listParm);
if (res && res.code == 200) {
console.log(res);
//赋值给表格
this.tableData = res.data.records;
this.total = res.data.total;
}
},
//页数改变时触发
currentChange(val) {
},
//页容量改变时触发
sizeChange(val) {
},
//删除按钮
async deleteBtn(row) {
//提示
const confirm = await this.$myconfirm("确定删除该数据吗?");
if (confirm) {
let res = await deleteRoleApi({
roleId: row.roleId });
if (res && res.code == 200) {
//信息提示
this.$message({
type: "success", message: res.msg });
//刷新列表
this.getList();
}
}
},
//编辑按钮
editBtn(row) {
//设置弹框属性
this.dialog.title = "编辑角色";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
this.addModel.type = "1";
//把当前编辑的数据放到表单数据里面
this.$objCoppy(row, this.addModel);
},
//新增按钮
addBtn() {
//设置弹框属性
this.dialog.title = "新增角色";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
this.addModel.type = "0";
},
//重置按钮
resetBtn() {
//表单清空
this.listParm.roleName = "";
this.getList();
},
//搜索按钮
searchBtn() {
this.getList();
},
},
};
</script>
<style lang="scss" scoped>
</style>
第35讲 分配权限保存接口开发
1、SysRoleMenuMapper添加saveRoleMenu()方法
package com.itmk.web.sys_role_menu.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itmk.web.sys_role_menu.entity.SysRoleMenu;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @Author java实战基地
* @Version 3501754007
*/
public interface SysRoleMenuMapper extends BaseMapper<SysRoleMenu> {
boolean saveRoleMenu(@Param("roleId") Long roleId, @Param("menuIds")List<Long> menuIds);
}
映射文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itmk.web.sys_role_menu.mapper.SysRoleMenuMapper">
<insert id="saveRoleMenu">
insert into sys_role_menu(role_id,menu_id) values
<foreach collection="menuIds" item="item" index="index" separator=",">
(#{
roleId},#{
item})
</foreach>
</insert>
</mapper>
2、SysRoleMenuService接口添加saveRoleMenu方法
package com.itmk.web.sys_role_menu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itmk.web.sys_role_menu.entity.SysRoleMenu;
import java.util.List;
/**
* @Author java实战基地
* @Version 3501754007
*/
public interface SysRoleMenuService extends IService<SysRoleMenu> {
void saveRoleMenu(Long roleId, List<Long> menuIds);
}
实现类
package com.itmk.web.sys_role_menu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itmk.web.sys_role_menu.entity.SysRoleMenu;
import com.itmk.web.sys_role_menu.mapper.SysRoleMenuMapper;
import com.itmk.web.sys_role_menu.service.SysRoleMenuService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Service
public class SysRoleMenuServiceImpl extends ServiceImpl<SysRoleMenuMapper, SysRoleMenu> implements SysRoleMenuService {
@Override
@Transactional
public void saveRoleMenu(Long roleId, List<Long> menuIds) {
//先删除原来的,再插入
QueryWrapper<SysRoleMenu> query = new QueryWrapper<>();
query.lambda().eq(SysRoleMenu::getRoleId,roleId);
this.baseMapper.delete(query);
//插入新的
this.baseMapper.saveRoleMenu(roleId,menuIds);
}
}
3、SysRoleController控制器添加saveRoleMenu()方法
package com.itmk.web.sys_role.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.itmk.utils.ResultUtils;
import com.itmk.utils.ResultVo;
import com.itmk.web.sys_role.entity.*;
import com.itmk.web.sys_role.service.SysRoleService;
import com.itmk.web.sys_role_menu.service.SysRoleMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
@RestController
@RequestMapping("/api/role")
public class SysRoleController {
@Autowired
private SysRoleService sysRoleService;
@Autowired
private SysRoleMenuService sysRoleMenuService;
//新增
@PostMapping
public ResultVo addRole(@RequestBody SysRole role){
role.setCreateTime(new Date());
boolean save = sysRoleService.save(role);
if(save){
return ResultUtils.success("新增角色成功!");
}
return ResultUtils.error("新增角色失败!");
}
//编辑
@PutMapping
public ResultVo editRole(@RequestBody SysRole role){
role.setUpdateTime(new Date());
boolean save = sysRoleService.updateById(role);
if(save){
return ResultUtils.success("编辑角色成功!");
}
return ResultUtils.error("编辑角色失败!");
}
//删除
@DeleteMapping("/{roleId}")
public ResultVo deleteRole(@PathVariable("roleId") Long roleId){
boolean remove = sysRoleService.removeById(roleId);
if(remove){
return ResultUtils.success("删除成功");
}
return ResultUtils.error("删除失败!");
}
//角色列表
@GetMapping("/list")
public ResultVo getList(RoleParm parm){
IPage<SysRole> list = sysRoleService.list(parm);
return ResultUtils.success("查询成功",list);
}
//分配权限回显
@GetMapping("/getAssingShow")
public ResultVo getAssingShow(AssignParm parm){
AssignVo show = sysRoleService.getAssignShow(parm);
return ResultUtils.success("查询成功",show);
}
//分配权限保存
@PostMapping("/saveRoleMenu")
public ResultVo saveRoleMenu(@RequestBody SaveRoleParm parm){
sysRoleMenuService.saveRoleMenu(parm.getRoleId(),parm.getList());
return ResultUtils.success("分配权限成功!");
}
}
第36讲 角色分配权限保存对接
1、api/role.js添加saveAssignApi()方法
import http from '@/utils/http'
//获取列表
export const getListApi = async(parm) =>{
return await http.get("/api/role/list",parm)
}
//新增
export const addRoleApi = async(parm) =>{
return await http.post("/api/role",parm)
}
//编辑
export const editRoleApi = async(parm) =>{
return await http.put("/api/role",parm)
}
//删除
export const deleteRoleApi = async(parm) =>{
return await http.delete("/api/role",parm)
}
//获取分配权限的数据
export const assignRoleApi = async(parm)=>{
return await http.get("/api/role/getAssingShow",parm)
}
//分配权限保存
export const saveAssignApi = async(parm)=>{
return await http.post("/api/role/saveRoleMenu",parm)
}
2、sysRoleList.vue页面
<template>
<el-main>
<!-- 搜索栏 -->
<el-form :model="listParm" ref="searchRef" :inline="true" size="small">
<el-form-item>
<el-input
placeholder="请输入角色名称"
v-model="listParm.roleName"
></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search" @click="searchBrn">搜索</el-button>
<el-button icon="el-icon-close" style="color: #ff7670" @click="resetBtn"
>重置</el-button
>
<el-button type="primary" @click="addBtn" icon="el-icon-plus"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table :height="tableHeight" :data="tableData" border stripe>
<el-table-column prop="roleName" label="角色名称"></el-table-column>
<el-table-column prop="remark" label="备注"></el-table-column>
<el-table-column label="操作" align="center" width="300">
<template slot-scope="scope">
<el-button
type="primary"
icon="el-icon-edit"
size="small"
@click="editBtn(scope.row)"
>编辑</el-button
>
<el-button
type="primary"
icon="el-icon-edit"
size="small"
@click="assignBtn(scope.row)"
>分配权限</el-button
>
<el-button
type="danger"
icon="el-icon-delete"
size="small"
@click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="listParm.currentPage"
:page-sizes="[10, 20, 40, 80, 100]"
:page-size="listParm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="listParm.total"
background
>
</el-pagination>
<!-- 新增、编辑 -->
<sys-dialog
:title="dialog.title"
:visible="dialog.visible"
:height="dialog.height"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addRef"
:rules="rules"
label-width="80px"
size="small"
>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item prop="roleName" label="角色名称">
<el-input v-model="addModel.roleName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="roleType" label="角色类型">
<el-select v-model="addModel.roleType" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="角色备注">
<el-input v-model="addModel.remark"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</sys-dialog>
<!-- 分配权限弹框 -->
<sys-dialog
:title="assignDialog.title"
:width="assignDialog.width"
:height="assignDialog.height"
:visible="assignDialog.visible"
@onClose="assignClose"
@onConfirm="assignConfrim"
>
<div slot="content">
<el-tree
ref="assignTree"
:data="assignTreeData"
node-key="menuId"
:props="defaultProps"
empty-text="暂无数据"
:show-checkbox="true"
default-expand-all
:default-checked-keys="assignTreeChecked"
></el-tree>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import SysDialog from "@/components/dialog/SysDialog.vue";
import {
getListApi,
addRoleApi,
editRoleApi,
deleteRoleApi,
assignRoleApi,
saveAssignApi,
} from "@/api/role";
import {
getUserId } from "@/utils/auth";
export default {
// 注册组件
components: {
SysDialog,
},
data() {
return {
defaultProps: {
children: "children",
label: "title",
},
//角色id
roleId: "",
//树数据
assignTreeData: [],
//角色原来的权限
assignTreeChecked: [],
//定义弹框属性
assignDialog: {
title: "",
height: 450,
width: 300,
visible: false,
},
//角色类型
options: [
{
value: "1",
label: "系统用户",
},
{
value: "2",
label: "学生",
},
{
value: "3",
label: "教师",
},
],
//表单验证
rules: {
roleName: [
{
required: true,
message: "请输入角色名称",
trigger: "blur",
},
],
roleType: [
{
required: true,
message: "请选择角色类型",
trigger: "blur",
},
],
},
//新增表单绑定的数据
addModel: {
type: "", //0:新增 1:编辑
roleId: "",
roleName: "",
roleType: "",
remark: "",
},
//弹框属性
dialog: {
height: 150,
visible: false,
title: "",
},
//表格高度
tableHeight: 0,
//搜索栏数据
listParm: {
roleName: "",
currentPage: 1,
pageSize: 10,
total: 0,
},
//表格数据
tableData: [],
};
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
created() {
this.getList();
},
methods: {
//分配权限弹框确定
async assignConfrim() {
// this.$refs.assignTree.getCheckedKeys()
// console.log(this.$refs.assignTree.getCheckedKeys())
// console.log(this.$refs.assignTree.getHalfCheckedKeys())
// this.assignDialog.visible = false;
let ids = this.$refs.assignTree
.getCheckedKeys()
.concat(this.$refs.assignTree.getHalfCheckedKeys());
console.log(ids);
let parm = {
roleId: this.roleId,
list: ids,
};
let res = await saveAssignApi(parm);
if (res && res.code == 200) {
this.$message.success(res.msg);
this.assignDialog.visible = false;
}
},
//分配权限弹框关闭
assignClose() {
this.assignDialog.visible = false;
},
//分配权限按钮
async assignBtn(row) {
console.log(row);
this.roleId = row.roleId;
//设置弹框的属性
this.assignDialog.title = "为【" + row.roleName + "】分配权限";
this.assignDialog.visible = true;
//获取权限树数据
let parm = {
userId: getUserId(),
roleId: row.roleId,
};
const res = await assignRoleApi(parm);
if (res && res.code == 200) {
//设置树的数据
console.log(res);
this.assignTreeData = res.data.menuList;
this.assignTreeChecked = res.data.checkList;
}
//过滤回显的数据
if (this.assignTreeChecked.length > 0) {
let newArr = [];
this.assignTreeChecked.forEach((item) => {
this.checked(item, this.assignTreeData, newArr);
});
this.assignTreeChecked = newArr;
}
},
//过滤工具
checked(id, data, newArr) {
data.forEach((item) => {
if (item.menuId == id) {
if (item.children && item.children.length == 0) {
newArr.push(item.menuId);
}
} else {
//有下级的时候,继续查找
if (item.children && item.children.length != 0) {
//递归算法:自己调用自己
this.checked(id, item.children, newArr);
}
}
});
},
//重置按钮
resetBtn() {
this.listParm.roleName = "";
this.getList();
},
//搜索按钮
searchBrn() {
this.getList();
},
//新增按钮
addBtn() {
//设置弹框属性
this.dialog.title = "新增角色";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
//设置为新增
this.addModel.type = "0";
},
//弹框确定
onConfirm() {
//表单验证
this.$refs.addRef.validate(async (valid) => {
if (valid) {
let res = null;
if (this.addModel.type == "0") {
res = await addRoleApi(this.addModel);
} else {
res = await editRoleApi(this.addModel);
}
if (res && res.code == 200) {
//信息提示
this.$message({
type: "success", message: res.msg });
//刷新列表
this.getList();
}
}
});
this.dialog.visible = false;
},
//弹框关闭
onClose() {
this.dialog.visible = false;
},
//获取列表
async getList() {
let res = await getListApi(this.listParm);
if (res && res.code == 200) {
//设置表格数据
console.log(res);
this.tableData = res.data.records;
this.listParm.total = res.data.total;
}
},
//页数改变时触发
currentChange(val) {
this.listParm.currentPage = val;
this.getList();
},
//页容量改变时触发
sizeChange(val) {
this.listParm.pageSize = val;
this.getList();
},
//删除按钮
async deleteBtn(row) {
const confirm = await this.$myconfirm("确定删除该数据吗?");
if (confirm) {
let res = await deleteRoleApi({
roleId: row.roleId });
if (res && res.code == 200) {
//信息提示
this.$message({
type: "success", message: res.msg });
//刷新列表
this.getList();
}
}
},
//编辑按钮
editBtn(row) {
//设置弹框属性
this.dialog.title = "编辑角色";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
//设置为编辑
this.addModel.type = "1";
//把当前要编辑的数据设置到表单数据域
this.$objCoppy(row, this.addModel);
},
},
};
</script>
<style lang="scss" scoped>
</style>
第37讲 学院管理接口开发
1、数据库脚本
drop table if exists school_collage;
/*==============================================================*/
/* Table: school_collage */
/*==============================================================*/
create table school_collage
(
collage_id int not null auto_increment comment '学院id',
collage_name varchar(64) comment '学院名称',
order_num int comment '序号',
create_time datetime comment '创建时间',
primary key (collage_id)
);
2、新建实体类
package com.itmk.web.school_collage.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Data
@TableName("school_collage")
public class SchoolCollage {
@TableId(type = IdType.AUTO)
private Long collageId;
private String collageName;
private Integer orderNum;
private Date createTime;
}
package com.itmk.web.school_collage.entity;
import lombok.Data;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Data
public class ListParm {
private Long currentPage;
private Long pageSize;
private String collageName;
}
3、mapper接口
package com.itmk.web.school_collage.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itmk.web.school_collage.entity.SchoolCollage;
/**
* @Author java实战基地
* @Version 3501754007
*/
public interface SchoolCollageMapper extends BaseMapper<SchoolCollage> {
}
映射文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itmk.web.school_collage.mapper.SchoolCollageMapper">
</mapper>
4、service接口
package com.itmk.web.school_collage.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itmk.web.school_collage.entity.SchoolCollage;
/**
* @Author java实战基地
* @Version 3501754007
*/
public interface SchoolCollageService extends IService<SchoolCollage> {
}
实现类
package com.itmk.web.school_collage.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itmk.web.school_collage.entity.SchoolCollage;
import com.itmk.web.school_collage.mapper.SchoolCollageMapper;
import com.itmk.web.school_collage.service.SchoolCollageService;
import org.springframework.stereotype.Service;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Service
public class SchoolCollageServiceImpl extends ServiceImpl<SchoolCollageMapper, SchoolCollage> implements SchoolCollageService {
}
5、控制器
package com.itmk.web.school_collage.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itmk.utils.ResultUtils;
import com.itmk.utils.ResultVo;
import com.itmk.web.school_collage.entity.ListParm;
import com.itmk.web.school_collage.entity.SchoolCollage;
import com.itmk.web.school_collage.service.SchoolCollageService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
/**
* @Author java实战基地
* @Version 3501754007
*/
@RestController
@RequestMapping("/api/collage")
public class SchoolCollageController {
@Autowired
private SchoolCollageService schoolCollageService;
//新增
@PostMapping
public ResultVo add(@RequestBody SchoolCollage schoolCollage){
//设置创建时间
schoolCollage.setCreateTime(new Date());
boolean save = schoolCollageService.save(schoolCollage);
if(save){
return ResultUtils.success("新增学院成功!");
}
return ResultUtils.error("新增学院失败!");
}
//编辑
@PutMapping
public ResultVo edit(@RequestBody SchoolCollage schoolCollage){
boolean save = schoolCollageService.updateById(schoolCollage);
if(save){
return ResultUtils.success("编辑学院成功!");
}
return ResultUtils.error("编辑学院失败!");
}
//删除
@DeleteMapping("/{collageId}")
public ResultVo delete(@PathVariable("collageId") Long collageId){
boolean b = schoolCollageService.removeById(collageId);
if(b){
return ResultUtils.success("删除学院成功!");
}
return ResultUtils.error("删除学院失败!");
}
//列表
@GetMapping("/list")
public ResultVo getList(ListParm listParm){
//构造查询条件
QueryWrapper<SchoolCollage> query = new QueryWrapper<>();
if(StringUtils.isNotEmpty(listParm.getCollageName())){
query.lambda().like(SchoolCollage::getCollageName,listParm.getCollageName());
}
//构造分页对象
IPage<SchoolCollage> page = new Page<>(listParm.getCurrentPage(),listParm.getPageSize());
//查询
IPage<SchoolCollage> list = schoolCollageService.page(page, query);
return ResultUtils.success("查询成功",list);
}
}
第38讲 新增学院接口对接
1、api下新建college.js
import http from "@/utils/http";
//新增
export const addApi = async parm => {
return await http.post("/api/collage", parm);
};
2、sysCollogeList.vue页面
<template>
<el-main>
<!-- 搜索栏 -->
<el-form :model="searchForm" label-width="80px" :inline="true" size="small">
<el-form-item>
<el-input
v-model="searchForm.collageName"
placeholder="请输入学院的名称"
></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search" @click="searchBtn">搜索</el-button>
<el-button style="color: #ff7670" icon="el-icon-close" @click="resetBtn"
>重置</el-button
>
<el-button icon="el-icon-plus" type="primary" @click="addBtn"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 新增弹框 -->
<sys-dialog
:title="addDialog.title"
:height="addDialog.height"
:width="addDialog.width"
:visible="addDialog.visible"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addForm"
:rules="rules"
label-width="80px"
:inline="false"
size="small"
>
<el-form-item prop="collageName" label="学院名称">
<el-input
v-model="addModel.collageName"
placeholder="请输入学院名称"
></el-input>
</el-form-item>
<el-form-item label="序号">
<el-input
v-model="addModel.orderNum"
placeholder="请输入序号"
></el-input>
</el-form-item>
</el-form>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import {
addApi } from "@/api/college.js";
import SysDialog from "@/components/dialog/SysDialog.vue";
export default {
//注册组件
components: {
SysDialog,
},
data() {
return {
//表单验证规则
rules: {
collageName: [
{
trigger: "blur",
required: true,
message: "请输入学院名称",
},
],
},
//表单绑定对象
addModel: {
type: "", //区分是新增还是编辑 0:新增 1:编辑
collageId: "",
collageName: "",
orderNum: "",
},
//弹框属性
addDialog: {
title: "",
height: 150,
width: 650,
visible: false,
},
//搜索表单
searchForm: {
collageName: "",
currentPage: 1,
pageSize: 10,
},
};
},
methods: {
//弹框关闭
onClose() {
this.addDialog.visible = false;
},
//弹框确定
onConfirm() {
//表单验证
this.$refs.addForm.validate(async (valid) => {
if (valid) {
let res = null;
if (this.addModel.type == "0") {
res = await addApi(this.addModel);
}
if (res && res.code == 200) {
//信息提示
this.$message.success(res.msg);
this.addDialog.visible = false;
}
}
});
},
//新增
addBtn() {
//清空表单
this.$resetForm("addForm", this.addModel);
//设置弹框属性
this.addDialog.title = "新增学院";
this.addDialog.visible = true;
//设置编辑的属性
this.addModel.type = "0"; //新增
},
//重置按钮
resetBtn() {
},
//搜索按钮
searchBtn() {
},
},
};
</script>
<style lang="scss" scoped>
</style>
第39讲 学院列表页面对接
1、api/college.js添加listApi()方法
import http from "@/utils/http";
//新增
export const addApi = async (parm) => {
return await http.post("/api/collage", parm);
};
//列表
export const listApi = async(parm)=>{
return await http.get("/api/collage/list",parm)
}
2、collogeList.vue页面
<template>
<el-main>
<!-- 搜索栏 -->
<el-form :model="searchForm" label-width="80px" :inline="true" size="mini">
<el-form-item>
<el-input
v-model="searchForm.collageName"
placeholder="请输入学院的名称"
></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search" @click="searchBtn">搜索</el-button>
<el-button style="color: #ff7670" icon="el-icon-close" @click="resetBtn"
>重置</el-button
>
<el-button icon="el-icon-plus" type="primary" @click="addBtn"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 列表 -->
<el-table :height="tableHeight" :data="tableList" border stripe>
<el-table-column prop="collageName" label="学院名称"></el-table-column>
<el-table-column prop="orderNum" label="序号"></el-table-column>
<el-table-column label="操作" align="center" width="250">
<template slot-scope="scope">
<el-button
type="primary"
icon="el-icon-edit"
size="small"
@click="editBtn(scope.row)"
>编辑</el-button
>
<el-button
type="danger"
icon="el-icon-delete"
size="small"
@click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="searchForm.currentPage"
:page-sizes="[10, 20, 40, 80, 100]"
:page-size="searchForm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="searchForm.total"
background
>
</el-pagination>
<!-- 新增弹框 -->
<sys-dialog
:title="addDialog.title"
:height="addDialog.height"
:width="addDialog.width"
:visible="addDialog.visible"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addForm"
:rules="rules"
label-width="80px"
:inline="false"
size="small"
>
<el-form-item prop="collageName" label="学院名称">
<el-input
v-model="addModel.collageName"
placeholder="请输入学院名称"
></el-input>
</el-form-item>
<el-form-item label="序号">
<el-input
v-model="addModel.orderNum"
placeholder="请输入序号"
></el-input>
</el-form-item>
</el-form>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import {
addApi, listApi } from "@/api/college.js";
import SysDialog from "@/components/dialog/SysDialog.vue";
export default {
//注册组件
components: {
SysDialog,
},
data() {
return {
//表格高度
tableHeight: 0,
//表单验证规则
rules: {
collageName: [
{
trigger: "blur",
required: true,
message: "请输入学院名称",
},
],
},
//表单绑定对象
addModel: {
type: "", //区分是新增还是编辑 0:新增 1:编辑
collageId: "",
collageName: "",
orderNum: "",
},
//弹框属性
addDialog: {
title: "",
height: 150,
width: 650,
visible: false,
},
//搜索表单
searchForm: {
collageName: "",
currentPage: 1,
pageSize: 10,
total: 0,
},
tableList: [],
};
},
created() {
this.getList();
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
methods: {
//页数改变时触发
currentChange(page) {
this.searchForm.currentPage = page;
this.getList();
},
//页容量改变时触发
sizeChange(size) {
this.searchForm.pageSize = size;
this.getList();
},
//删除按钮
deleteBtn(row) {
},
//编辑按钮
editBtn(row) {
},
//获取列表
async getList() {
let res = await listApi(this.searchForm);
if (res && res.code == 200) {
console.log(res);
//设置表格数据
this.tableList = res.data.records;
//总条数
this.searchForm.total = res.data.total;
}
},
//弹框关闭
onClose() {
this.addDialog.visible = false;
},
//弹框确定
onConfirm() {
//表单验证
this.$refs.addForm.validate(async (valid) => {
if (valid) {
let res = null;
if (this.addModel.type == "0") {
res = await addApi(this.addModel);
}
if (res && res.code == 200) {
//信息提示
this.$message.success(res.msg);
this.addDialog.visible = false;
}
}
});
},
//新增
addBtn() {
//清空表单
this.$resetForm("addForm", this.addModel);
//设置弹框属性
this.addDialog.title = "新增学院";
this.addDialog.visible = true;
//设置编辑的属性
this.addModel.type = "0"; //新增
},
//重置按钮
resetBtn() {
this.searchForm.currentPage = 1;
this.searchForm.collageName = "";
this.getList();
},
//搜索按钮
searchBtn() {
this.getList();
},
},
};
</script>
<style lang="scss" scoped>
</style>
第40讲 学院编辑、删除接口对接
1、college.js添加editApi()和deleteApi()方法
import http from "@/utils/http";
//新增
export const addApi = async (parm) => {
return await http.post("/api/collage", parm);
};
//列表
export const listApi = async(parm)=>{
return await http.get("/api/collage/list",parm)
}
//编辑
export const editApi = async(parm)=>{
return await http.put("/api/collage", parm)
}
//删除
export const deleteApi = async(parm)=>{
return await http.delete("/api/collage", parm)
}
2、collogeList.vue页面
<template>
<el-main>
<!-- 搜索栏 -->
<el-form :model="searchForm" label-width="80px" :inline="true" size="mini">
<el-form-item>
<el-input
v-model="searchForm.collageName"
placeholder="请输入学院的名称"
></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search" @click="searchBtn">搜索</el-button>
<el-button style="color: #ff7670" icon="el-icon-close" @click="resetBtn"
>重置</el-button
>
<el-button icon="el-icon-plus" type="primary" @click="addBtn"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 列表 -->
<el-table :height="tableHeight" :data="tableList" border stripe>
<el-table-column prop="collageName" label="学院名称"></el-table-column>
<el-table-column prop="orderNum" label="序号"></el-table-column>
<el-table-column label="操作" align="center" width="250">
<template slot-scope="scope">
<el-button
type="primary"
icon="el-icon-edit"
size="small"
@click="editBtn(scope.row)"
>编辑</el-button
>
<el-button
type="danger"
icon="el-icon-delete"
size="small"
@click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="searchForm.currentPage"
:page-sizes="[10, 20, 40, 80, 100]"
:page-size="searchForm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="searchForm.total"
background
>
</el-pagination>
<!-- 新增弹框 -->
<sys-dialog
:title="addDialog.title"
:height="addDialog.height"
:width="addDialog.width"
:visible="addDialog.visible"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addForm"
:rules="rules"
label-width="80px"
:inline="false"
size="small"
>
<el-form-item prop="collageName" label="学院名称">
<el-input
v-model="addModel.collageName"
placeholder="请输入学院名称"
></el-input>
</el-form-item>
<el-form-item label="序号">
<el-input
v-model="addModel.orderNum"
placeholder="请输入序号"
></el-input>
</el-form-item>
</el-form>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import {
addApi, listApi, editApi, deleteApi } from "@/api/college.js";
import SysDialog from "@/components/dialog/SysDialog.vue";
export default {
//注册组件
components: {
SysDialog,
},
data() {
return {
//表格高度
tableHeight: 0,
//表单验证规则
rules: {
collageName: [
{
trigger: "blur",
required: true,
message: "请输入学院名称",
},
],
},
//表单绑定对象
addModel: {
type: "", //区分是新增还是编辑 0:新增 1:编辑
collageId: "",
collageName: "",
orderNum: "",
},
//弹框属性
addDialog: {
title: "",
height: 150,
width: 650,
visible: false,
},
//搜索表单
searchForm: {
collageName: "",
currentPage: 1,
pageSize: 10,
total: 0,
},
tableList: [],
};
},
created() {
this.getList();
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
methods: {
//页数改变时触发
currentChange(page) {
this.searchForm.currentPage = page;
this.getList();
},
//页容量改变时触发
sizeChange(size) {
this.searchForm.pageSize = size;
this.getList();
},
//删除按钮
async deleteBtn(row) {
//信息提示
let confirm = await this.$myconfirm("确定删除该数据吗?");
if (confirm) {
let res = await deleteApi({
collageId: row.collageId,
});
if (res && res.code == 200) {
//信息提示
this.$message.success(res.msg);
//刷新列表
this.getList();
}
}
},
//编辑按钮
editBtn(row) {
//清空表单
this.$resetForm("addForm", this.addModel);
//把要编辑的数据设置到表单绑定的对象
this.$objCoppy(row, this.addModel);
//设置编辑的属性
this.addModel.type = "1";
//设置弹框属性
this.addDialog.title = "编辑学院";
this.addDialog.visible = true;
},
//获取列表
async getList() {
let res = await listApi(this.searchForm);
if (res && res.code == 200) {
console.log(res);
//设置表格数据
this.tableList = res.data.records;
//总条数
this.searchForm.total = res.data.total;
}
},
//弹框关闭
onClose() {
this.addDialog.visible = false;
},
//弹框确定
onConfirm() {
//表单验证
this.$refs.addForm.validate(async (valid) => {
if (valid) {
let res = null;
if (this.addModel.type == "0") {
res = await addApi(this.addModel);
} else {
res = await editApi(this.addModel);
}
if (res && res.code == 200) {
//信息提示
this.$message.success(res.msg);
this.addDialog.visible = false;
//刷新列表
this.getList();
}
}
});
},
//新增
addBtn() {
//清空表单
this.$resetForm("addForm", this.addModel);
//设置弹框属性
this.addDialog.title = "新增学院";
this.addDialog.visible = true;
//设置编辑的属性
this.addModel.type = "0"; //新增
},
//重置按钮
resetBtn() {
this.searchForm.currentPage = 1;
this.searchForm.collageName = "";
this.getList();
},
//搜索按钮
searchBtn() {
this.getList();
},
},
};
</script>
<style lang="scss" scoped>
</style>
第41讲 专业管理模块接口开发
1、数据库脚本
drop table if exists school_major;
/*==============================================================*/
/* Table: school_major */
/*==============================================================*/
create table school_major
(
major_id int not null auto_increment comment '专业id',
collage_id int comment '学院id',
major_name varchar(64) comment '专业名称',
order_num int comment '序号',
primary key (major_id)
);
2、新建实体类
package com.itmk.web.school_major.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Data
@TableName("school_major")
public class SchoolMajor {
@TableId(type = IdType.AUTO)
private Long majorId;
private Long collageId;
private String majorName;
private Integer orderNum;
//学院名称,不属于专业表,需要排除
@TableField(exist = false)
private String collageName;
}
package com.itmk.web.school_major.entity;
import lombok.Data;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Data
public class MajorList {
private String majorName;
private String collageName;
private Long currentPage;
private Long pageSize;
}
3、新建mapper层
package com.itmk.web.school_major.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.itmk.web.school_major.entity.MajorList;
import com.itmk.web.school_major.entity.SchoolMajor;
import org.apache.ibatis.annotations.Param;
/**
* @Author java实战基地
* @Version 3501754007
*/
public interface SchoolMajorMapper extends BaseMapper<SchoolMajor> {
IPage<SchoolMajor> getList(IPage<SchoolMajor> page, @Param("parm")MajorList majorList);
}
映射文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itmk.web.school_major.mapper.SchoolMajorMapper">
<select id="getList">
select sm.*,sc.collage_name from school_major as sm
left join school_collage as sc
on sm.collage_id = sc.collage_id
where 1=1
<if test="parm.majorName !=null and parm.majorName !=''">
and sm.major_name like concat('%',#{
parm.majorName},'%')
</if>
<if test="parm.collageName !=null and parm.collageName !=''">
and sc.collage_name like concat('%',#{
parm.collageName},'%')
</if>
</select>
</mapper>
4、新建service层
package com.itmk.web.school_major.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itmk.web.school_major.entity.MajorList;
import com.itmk.web.school_major.entity.SchoolMajor;
/**
* @Author java实战基地
* @Version 3501754007
*/
public interface SchoolMajorService extends IService<SchoolMajor> {
IPage<SchoolMajor> getList(MajorList majorList);
}
实现类
package com.itmk.web.school_major.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itmk.web.school_major.entity.MajorList;
import com.itmk.web.school_major.entity.SchoolMajor;
import com.itmk.web.school_major.mapper.SchoolMajorMapper;
import com.itmk.web.school_major.service.SchoolMajorService;
import org.springframework.stereotype.Service;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Service
public class SchoolMajorServiceImpl extends ServiceImpl<SchoolMajorMapper, SchoolMajor> implements SchoolMajorService {
@Override
public IPage<SchoolMajor> getList(MajorList majorList) {
//构造分页对象
IPage<SchoolMajor> page = new Page<>(majorList.getCurrentPage(),majorList.getPageSize());
return this.baseMapper.getList(page,majorList);
}
}
5、新建控制器
package com.itmk.web.school_major.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.itmk.utils.ResultUtils;
import com.itmk.utils.ResultVo;
import com.itmk.web.school_major.entity.MajorList;
import com.itmk.web.school_major.entity.SchoolMajor;
import com.itmk.web.school_major.service.SchoolMajorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @Author java实战基地
* @Version 3501754007
*/
@RestController
@RequestMapping("/api/major")
public class SchoolMajorController {
@Autowired
private SchoolMajorService schoolMajorService;
//新增
@PostMapping
public ResultVo add(@RequestBody SchoolMajor schoolMajor){
boolean save = schoolMajorService.save(schoolMajor);
if(save){
return ResultUtils.success("新增成功");
}
return ResultUtils.error("新增失败!");
}
//编辑
@PutMapping
public ResultVo edit(@RequestBody SchoolMajor schoolMajor){
boolean save = schoolMajorService.updateById(schoolMajor);
if(save){
return ResultUtils.success("编辑成功");
}
return ResultUtils.error("编辑失败!");
}
//删除
@DeleteMapping("/{majorId}")
public ResultVo delete(@PathVariable("majorId") Long majorId){
boolean save = schoolMajorService.removeById(majorId);
if(save){
return ResultUtils.success("删除成功");
}
return ResultUtils.error("删除失败!");
}
//查询列表
@GetMapping("/list")
public ResultVo getList(MajorList majorList){
IPage<SchoolMajor> list = schoolMajorService.getList(majorList);
return ResultUtils.success("查询成功",list);
}
}
第42讲 新增专业页面制作与对接
1、api下新建major.js
import http from "@/utils/http";
//查询学院列表
export const getCollegeListApi = async()=>{
return await http.get("/api/major/getCollegeList")
}
//新增
export const addApi = async(parm)=>{
return await http.post("/api/major",parm)
}
2、新建majorList.vue页面
<template>
<el-main>
<!--搜索栏-->
<el-form :model="searchForm" :inline="true" size="small">
<el-form-item label="">
<el-input
v-model="searchForm.collageName"
placeholder="请输入学院名称"
></el-input>
</el-form-item>
<el-form-item label="">
<el-input
v-model="searchForm.majorName"
placeholder="请输入专业名称"
></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search" @click="searchBtn">搜索</el-button>
<el-button style="color: #ff7670" icon="el-icon-close" @click="resetBtn"
>重置</el-button
>
<el-button icon="el-icon-plus" type="primary" @click="addBtn"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 新增弹框 -->
<sys-dialog
:title="addDialog.title"
:height="addDialog.height"
:width="addDialog.width"
:visible="addDialog.visible"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addForm"
:rules="rules"
label-width="80px"
:inline="false"
size="small"
>
<el-form-item prop="collageId" label="所属学院">
<el-select
style="width: 100%"
v-model="addModel.collageId"
placeholder="请选择学院"
>
<el-option
v-for="item in collogeList"
:key="item.collageId"
:label="item.collageName"
:value="item.collageId"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="专业名称" prop="majorName">
<el-input v-model="addModel.majorName"></el-input>
</el-form-item>
<el-form-item label="序号">
<el-input v-model="addModel.orderNum"></el-input>
</el-form-item>
</el-form>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import SysDialog from "@/components/dialog/SysDialog.vue";
import {
getCollegeListApi, addApi } from "@/api/major.js";
export default {
components: {
SysDialog,
},
data() {
return {
//表单验证规则
rules: {
collageId: [
{
trigger: "blur",
required: true,
message: "请选择学院",
},
],
majorName: [
{
trigger: "blur",
required: true,
message: "请填写专业名称",
},
],
},
//新增表单属性
addModel: {
type: "",
majorId: "",
collageId: "",
majorName: "",
orderNum: "",
},
//弹框属性
addDialog: {
title: "",
height: 200,
width: 650,
visible: false,
},
searchForm: {
majorName: "",
collageName: "",
currentPage: "",
pageSize: "",
total: 0,
},
collogeList: [],
};
},
methods: {
//弹框关闭
onClose() {
this.addDialog.visible = false;
},
//弹框确定
onConfirm() {
this.$refs.addForm.validate(async(valid) => {
if (valid) {
let res = null;
if (this.addModel.type == "0") {
res = await addApi(this.addModel);
}
if(res && res.code == 200){
//信息提示
this.$message.success(res.msg)
//刷新列表
}
console.log(this.addModel);
this.addDialog.visible = false;
}
});
},
//新增按钮
async addBtn() {
//清空表单
this.$resetForm('addForm',this.addModel)
//获取学院列表
let res = await getCollegeListApi();
if (res && res.code == 200) {
console.log(res);
this.collogeList = res.data;
}
//显示弹框
this.addDialog.title = "新增专业";
this.addDialog.visible = true;
this.addModel.type = "0";
},
//重置按钮
resetBtn() {
},
//搜索按钮
searchBtn() {
},
},
};
</script>
<style lang="scss" scoped>
</style>
第43讲 专业列表制作与对接
1、api/major.js添加listApi()
import http from "@/utils/http";
//查询学院列表
export const getCollegeListApi = async()=>{
return await http.get("/api/major/getCollegeList")
}
//新增
export const addApi = async(parm)=>{
return await http.post("/api/major",parm)
}
//列表
export const listApi = async(parm)=>{
return await http.get("/api/major/list",parm)
}
2、majorList.vue页面
<template>
<el-main>
<!--搜索栏-->
<el-form :model="searchForm" :inline="true" size="small">
<el-form-item label="">
<el-input
v-model="searchForm.collageName"
placeholder="请输入学院名称"
></el-input>
</el-form-item>
<el-form-item label="">
<el-input
v-model="searchForm.majorName"
placeholder="请输入专业名称"
></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search" @click="searchBtn">搜索</el-button>
<el-button style="color: #ff7670" icon="el-icon-close" @click="resetBtn"
>重置</el-button
>
<el-button icon="el-icon-plus" type="primary" @click="addBtn"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格数据 -->
<el-table :height="tableHeight" :data="tableList" border stripe>
<el-table-column prop="majorName" label="专业名称"></el-table-column>
<el-table-column prop="collageName" label="所属学院"></el-table-column>
<el-table-column prop="orderNum" label="序号"></el-table-column>
<el-table-column label="操作" align="center" width="220">
<template slot-scope="scope">
<el-button
icon="el-icon-edit"
type="primary"
size="small"
@click="editBtn(scope.row)"
>编辑</el-button
>
<el-button
icon="el-icon-delete"
type="danger"
size="small"
@click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="searchForm.currentPage"
:page-sizes="[10, 20, 40, 80, 100]"
:page-size="searchForm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="searchForm.total"
background
>
</el-pagination>
<!-- 新增弹框 -->
<sys-dialog
:title="addDialog.title"
:height="addDialog.height"
:width="addDialog.width"
:visible="addDialog.visible"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addForm"
:rules="rules"
label-width="80px"
:inline="false"
size="small"
>
<el-form-item prop="collageId" label="所属学院">
<el-select
style="width: 100%"
v-model="addModel.collageId"
placeholder="请选择学院"
>
<el-option
v-for="item in collogeList"
:key="item.collageId"
:label="item.collageName"
:value="item.collageId"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="专业名称" prop="majorName">
<el-input v-model="addModel.majorName"></el-input>
</el-form-item>
<el-form-item label="序号">
<el-input v-model="addModel.orderNum"></el-input>
</el-form-item>
</el-form>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import SysDialog from "@/components/dialog/SysDialog.vue";
import {
getCollegeListApi, addApi, listApi } from "@/api/major.js";
export default {
components: {
SysDialog,
},
data() {
return {
//表格高度
tableHeight: 0,
//表单验证规则
rules: {
collageId: [
{
trigger: "blur",
required: true,
message: "请选择学院",
},
],
majorName: [
{
trigger: "blur",
required: true,
message: "请填写专业名称",
},
],
},
//新增表单属性
addModel: {
type: "",
majorId: "",
collageId: "",
majorName: "",
orderNum: "",
},
//弹框属性
addDialog: {
title: "",
height: 200,
width: 650,
visible: false,
},
searchForm: {
majorName: "",
collageName: "",
currentPage: 1,
pageSize: 10,
total: 0,
},
collogeList: [],
//表格数据
tableList: [],
};
},
created() {
this.getList();
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
methods: {
//页数改变时触发
currentChange(page) {
this.searchForm.currentPage = page;
this.getList();
},
//页容量改变时触发
sizeChange(size) {
this.searchForm.pageSize = size;
this.getList();
},
//删除按钮
deleteBtn(row) {
},
//编辑按钮
editBtn(row) {
},
//获取列表数据
async getList() {
let res = await listApi(this.searchForm);
if (res && res.code == 200) {
console.log(res);
//设置表格数据
this.tableList = res.data.records;
//设置分页
this.searchForm.total = res.data.total;
}
},
//弹框关闭
onClose() {
this.addDialog.visible = false;
},
//弹框确定
onConfirm() {
this.$refs.addForm.validate(async (valid) => {
if (valid) {
let res = null;
if (this.addModel.type == "0") {
res = await addApi(this.addModel);
}
if (res && res.code == 200) {
//信息提示
this.$message.success(res.msg);
//刷新列表
}
console.log(this.addModel);
this.addDialog.visible = false;
}
});
},
//新增按钮
async addBtn() {
//清空表单
this.$resetForm("addForm", this.addModel);
//获取学院列表
let res = await getCollegeListApi();
if (res && res.code == 200) {
console.log(res);
this.collogeList = res.data;
}
//显示弹框
this.addDialog.title = "新增专业";
this.addDialog.visible = true;
this.addModel.type = "0";
},
//重置按钮
resetBtn() {
this.searchForm.majorName = "";
this.searchForm.collageName = "";
this.searchForm.currentPage = 1;
this.getList();
},
//搜索按钮
searchBtn() {
this.getList();
},
},
};
</script>
<style lang="scss" scoped>
</style>
第44讲 专业编辑、删除接口对接
1、api/major.js添加editApi()和deleteApi()方法
import http from "@/utils/http";
//查询学院列表
export const getCollegeListApi = async()=>{
return await http.get("/api/major/getCollegeList")
}
//新增
export const addApi = async(parm)=>{
return await http.post("/api/major",parm)
}
//列表
export const listApi = async(parm)=>{
return await http.get("/api/major/list",parm)
}
//编辑
export const editApi = async(parm)=>{
return await http.put("/api/major",parm)
}
//删除
export const deleteApi = async(parm)=>{
return await http.delete("/api/major",parm)
}
2、majorList.vue页面
<template>
<el-main>
<!--搜索栏-->
<el-form :model="searchForm" :inline="true" size="small">
<el-form-item label="">
<el-input
v-model="searchForm.collageName"
placeholder="请输入学院名称"
></el-input>
</el-form-item>
<el-form-item label="">
<el-input
v-model="searchForm.majorName"
placeholder="请输入专业名称"
></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search" @click="searchBtn">搜索</el-button>
<el-button style="color: #ff7670" icon="el-icon-close" @click="resetBtn"
>重置</el-button
>
<el-button icon="el-icon-plus" type="primary" @click="addBtn"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格数据 -->
<el-table :height="tableHeight" :data="tableList" border stripe>
<el-table-column prop="majorName" label="专业名称"></el-table-column>
<el-table-column prop="collageName" label="所属学院"></el-table-column>
<el-table-column prop="orderNum" label="序号"></el-table-column>
<el-table-column label="操作" align="center" width="220">
<template slot-scope="scope">
<el-button
icon="el-icon-edit"
type="primary"
size="small"
@click="editBtn(scope.row)"
>编辑</el-button
>
<el-button
icon="el-icon-delete"
type="danger"
size="small"
@click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="searchForm.currentPage"
:page-sizes="[10, 20, 40, 80, 100]"
:page-size="searchForm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="searchForm.total"
background
>
</el-pagination>
<!-- 新增弹框 -->
<sys-dialog
:title="addDialog.title"
:height="addDialog.height"
:width="addDialog.width"
:visible="addDialog.visible"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addForm"
:rules="rules"
label-width="80px"
:inline="false"
size="small"
>
<el-form-item prop="collageId" label="所属学院">
<el-select
style="width: 100%"
v-model="addModel.collageId"
placeholder="请选择学院"
>
<el-option
v-for="item in collogeList"
:key="item.collageId"
:label="item.collageName"
:value="item.collageId"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="专业名称" prop="majorName">
<el-input v-model="addModel.majorName"></el-input>
</el-form-item>
<el-form-item label="序号">
<el-input v-model="addModel.orderNum"></el-input>
</el-form-item>
</el-form>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import SysDialog from "@/components/dialog/SysDialog.vue";
import {
getCollegeListApi,
addApi,
listApi,
editApi,
deleteApi,
} from "@/api/major.js";
export default {
components: {
SysDialog,
},
data() {
return {
//表格高度
tableHeight: 0,
//表单验证规则
rules: {
collageId: [
{
trigger: "blur",
required: true,
message: "请选择学院",
},
],
majorName: [
{
trigger: "blur",
required: true,
message: "请填写专业名称",
},
],
},
//新增表单属性
addModel: {
type: "",
majorId: "",
collageId: "",
majorName: "",
orderNum: "",
},
//弹框属性
addDialog: {
title: "",
height: 200,
width: 650,
visible: false,
},
searchForm: {
majorName: "",
collageName: "",
currentPage: 1,
pageSize: 10,
total: 0,
},
collogeList: [],
//表格数据
tableList: [],
};
},
created() {
this.getList();
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
methods: {
//页数改变时触发
currentChange(page) {
this.searchForm.currentPage = page;
this.getList();
},
//页容量改变时触发
sizeChange(size) {
this.searchForm.pageSize = size;
this.getList();
},
//删除按钮
async deleteBtn(row) {
//信息提示
const confirm = await this.$myconfirm("确定删除该数据吗?");
if (confirm) {
let res = await deleteApi({
majorId: row.majorId,
});
if (res && res.code == 200) {
//信息提示
this.$message.success(res.msg);
this.getList();
}
}
},
//编辑按钮
async editBtn(row) {
//清空表单
this.$resetForm("addForm", this.addModel);
//获取学院列表
let res = await getCollegeListApi();
if (res && res.code == 200) {
console.log(res);
this.collogeList = res.data;
}
//把要编辑的数据设置到表单绑定的对象里面
this.$objCoppy(row, this.addModel);
//显示弹框
this.addDialog.title = "编辑专业";
this.addDialog.visible = true;
this.addModel.type = "1";
},
//获取列表数据
async getList() {
let res = await listApi(this.searchForm);
if (res && res.code == 200) {
console.log(res);
//设置表格数据
this.tableList = res.data.records;
//设置分页
this.searchForm.total = res.data.total;
}
},
//弹框关闭
onClose() {
this.addDialog.visible = false;
},
//弹框确定
onConfirm() {
this.$refs.addForm.validate(async (valid) => {
if (valid) {
let res = null;
if (this.addModel.type == "0") {
res = await addApi(this.addModel);
} else {
res = await editApi(this.addModel);
}
if (res && res.code == 200) {
//信息提示
this.$message.success(res.msg);
//刷新列表
this.getList();
}
console.log(this.addModel);
this.addDialog.visible = false;
}
});
},
//新增按钮
async addBtn() {
//清空表单
this.$resetForm("addForm", this.addModel);
//获取学院列表
let res = await getCollegeListApi();
if (res && res.code == 200) {
console.log(res);
this.collogeList = res.data;
}
//显示弹框
this.addDialog.title = "新增专业";
this.addDialog.visible = true;
this.addModel.type