
基于vue + spring boot学生宿舍管理
1、环境准备
| 1、安装node.js |
| 2、安装vue-cli |
| 3、安装 vs code开发工具 |
复制
2、下载node.js
浏览器打开 https://nodejs.org/zh-cn/download/ 进入下载
1.2点击【以往的版本】进入所示列表界面,选择自己所需要的版本进行下载安装


3、vue-cli安装
1.2.1检查node.js是否安装
通过命令提示符,node -v npm -v查看,如果没有请先安装node.js,如下图,说明已经安装node.js
1.2.2.把npm换成cnpm
命令工具输入 npm install -g cnpm --registry=https://registry.npm.taobao.org
安装完成 输入 cnpm -v 查看是否安装成功
卸载cnpm npm uninstall cnpm -g
1.2.3.安装vue-cli
cnpm install -g @vue/cli
1.2.4.查看vue-cli是否安装成功
vue -V
注意 V是大写的
4、vs code安装
第03讲 vue-admin-template下载
1、vue-element-admin介绍
vue-element-admin 是一个后台前端解决方案,它基于 vue 和 element-ui实现。它使用了最新的前端技术栈,内置了 i18 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
建议
本项目的定位是后台集成方案,不太适合当基础模板来进行二次开发。因为本项目集成了很多你可能用不到的功能,会造成不少的代码冗余。如果你的项目不关注这方面的问题,也可以直接基于它进行二次开发。
- 集成方案: vue-element-admin
- 基础模板: vue-admin-template
- 桌面终端: electron-vue-admin
- Typescript 版: vue-typescript-admin-template (鸣谢: @Armour)
- Others: awesome-project
vue-element-admin和vue-admin-template区别
| 1、vue-admin-template是vue-element-admin的简化版,适合企业搭建项目;并且简化版有两个版本,注意选择; |
| 2、vue-element-admin 定位是后台集成方案,不太适合当基础模板来进行二次开发。因为本项目集成了很多你可能用不到的功能,会造成不少的代码冗余 |
复制
2、vue-admin-template下载
复制
3、运行项目
| 1.安装依赖 npm install |
| 2.运行项目 npm run dev |
复制
4、运行项目报错解决
| 1. error Multiple spaces found before '//需要添加该项,否则上级不...' no-multi-spaces错误 |
| 找到项目的.eslintrc.js配置文件把rules:中的 'no-multi-spaces': 'off' |
| |
| 2. error Trailing spaces not allowed no-trailing-spaces错误 |
| 找到项目的.eslintrc.js配置文件在rules:中添加 'no-trailing-spaces': 'error', |
复制
第04讲 配置左侧导航菜单
1、修改应用的名称
找到src目录下的settings.js配置文件,修改为如下所示
| module.exports = { |
| |
| title: '学生宿舍管理系统', |
| |
| |
| |
| |
| |
| fixedHeader: true, |
| |
| |
| |
| |
| |
| sidebarLogo: true |
| } |
| |
复制
2、修改右侧的下拉菜单
找到src/layout/components下的Navbar.vue文件,把el-dropdown-menu修改为如下所示代码
| <el-dropdown-menu slot="dropdown" class="user-dropdown"> |
| <el-dropdown-item divided> |
| <span style="display:block;">重置密码</span> |
| </el-dropdown-item> |
| <el-dropdown-item divided @click.native="logout"> |
| <span style="display:block;">退出登录</span> |
| </el-dropdown-item> |
| </el-dropdown-menu> |
复制
3、修改Dashboard为首页
3.1、修改router下的router.js里面的dashboard的title为 首页
| { |
| path: '/', |
| component: Layout, |
| redirect: '/dashboard', |
| children: [{ |
| path: 'dashboard', |
| name: 'Dashboard', |
| component: () => import('@/views/dashboard/index'), |
| meta: { title: '首页', icon: 'dashboard' } |
| }] |
| } |
复制
3.2、修改components/Breadcrumb/index.vue中的 title 为首页
| if (!this.isDashboard(first)) { |
| matched = [{ path: '/dashboard', meta: { title: '首页' }}].concat(matched) |
| } |
复制
4、新建模块页面,并创建页面对应的路由
| import Vue from 'vue' |
| import Router from 'vue-router' |
| |
| Vue.use(Router) |
| |
| |
| import Layout from '@/layout' |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export const constantRoutes = [ |
| { |
| path: '/login', |
| component: () => import('@/views/login/index'), |
| hidden: true |
| }, |
| |
| { |
| path: '/404', |
| component: () => import('@/views/404'), |
| hidden: true |
| }, |
| { |
| path: '/', |
| component: Layout, |
| redirect: '/dashboard', |
| children: [{ |
| path: 'dashboard', |
| name: 'Dashboard', |
| component: () => import('@/views/dashboard/index'), |
| meta: { title: '首页', icon: 'dashboard' } |
| }] |
| } |
| ] |
| |
| |
| |
| |
| |
| export const asyncRoutes ='/system [ |
| { |
| component:Layout, |
| alwaysShowh:true, |
| { |
| path: '/colloge', |
| icomponent:dLayout, |
| alwaysShow1,true name: 'colloge', |
| meta: da{ ti:l "2'学院管理', icon: 'el-icon5s2help' }, |
| children: [ |
| { |
| path: '/collogeList', |
| pa'/sysRoleLth:'用户管理's'icon:, |
| 'table' } |
| children: [ |
| { |
| path: '/sysUserList', |
| name |
| 'sysRoleList' path: '/sysMenuList', |
| name: 'collogeList', |
| component: () => import('@/views/system/sysMenuList'), |
| meta: { title: '菜单管理', icon: 'tree' } |
| } |
| ] |
| { |
| path: '/majorList', |
| name: 'majorList' |
| component: () => import('@/views/colloge/majorList'), |
| meta: { title: '专业管理', icon: 'tree' } |
| }, |
| { |
| path: '/classList', |
| name: 'classList', |
| component: () => import('@/views/colloge/collogeList'), |
| }, |
| mett: '学院管理', icoa: { |
| 'table' } |
| }, |
| } |
| </script> |
| |
| <style lang="scss" scoped> |
| |
| </style> |
| |
复制
3.2、在src/views下新建colloge文件夹,并新建如下页面
1、collogeList.vue页面
| <template> |
| <div>学院管理</div> |
| </template> |
| |
| <script> |
| export default {}; |
| </script> |
| |
| <style lang="scss" scoped> |
| </style> |
复制
2、majorList.vue页面
| <template> |
| <div>专业管理</div> |
| </template> |
| |
| <script> |
| export default {}; |
| </script> |
| |
| <style lang="scss" scoped> |
| </style> |
复制
3、classList.vue页面
| <template> |
| <div>班级管理</div> |
| </template> |
| |
| <script> |
| export default {}; |
| </script> |
| |
| <style lang="scss" scoped> |
| </style> |
复制
constantRoutes
})
constroutes:
#router#=#cre# "Router()
// Detail see20https://github.com/vuejs/vue-router/issues/0234#issuecomment-31794
465efunctionxresetRouter()port {
const newRoutern=acreateRouter()
merouter.matcher:= newRouter.matcher"// reset王router
}
export def虎ult router
| |
| |
| |
| |
| |
| 1.新建sysM,nuList.vue组件 |
| |
| ```js |
| <template> |
| <div> |
| 菜单管理component: () => import('@/views/colloge/classList'), |
| meta: { title: '班级管理', icon: 'tree' } |
| } |
| ] |
| children: [ |
| 用理 </div> |
| </template> |
| |
| <script> |
| { |
| export default } |
| ] |
| |
| const createRouter = () =>inewdRouter({ |
| : // mo3e1,'history' // require service support scrollBehavior: () => ({ y: 0 }), |
| date: "2016-05-01", |
| <div> name: "王小虎", |
| addresysRoleList.vue组件 |
| |
| ```js |
| <template> |
| <div> |
| 角色管理 |
| }, |
| |
| // 404 page must be placed at the end !!! |
| { path: '*', redirect: '/404', hidden: true </div> |
| </template> |
| |
| <script> |
| id: 3export default { |
| 2, |
| } |
| </script> |
| |
| <style lang="scss" scoped> |
| |
| </style> |
复制
3.新建sysUserList.vue组件
| <template> |
| date: 5、菜单改为打开一个 |
| |
| 找到src/layout下的components目录,修改SideBar目录下的index.vue中的 :unique-opened="true" |
| |
| |
| |
| #### 第05讲 项目添加添加tagsview选项卡 |
| |
| ###### 1、添加TagsView文件 |
| |
| 把vue-element-admin项目中的src\layout\components下的TagsView文件夹复制到vue-admin-template的 src\layout\components下 |
| |
| 把vue-element-admin\src\store\modules\tagsView.js 复制到vue-admin-template\srcstore\modules\ |
| |
| ###### 2、修改 vue-admin-template\src\layout\components\AppMain.vue文件 |
| |
| ```js |
| <template> |
| <section class="app-main"> |
| name: "王小虎", |
| address: "上海市普陀区金沙江路 1519 弄", |
| }, |
| ], |
| }, |
| { |
| id: 4, |
| date: "2016-05-03", |
| <transition name="fade-transform":"mode=王out-in,> <!-- <router-view :key="key" /> --> |
| <keep-alive :include="cachedrVisws上> |
| <router-view :key="key" },/> ],</keep-alive> </transition> |
| </section> |
| </template> |
| |
| <script> } export default { |
| name:}"AppMain" |
| mcoopned(: { |
| cachedViews) { |
| return this.$store.state.tagsView.cachedViews; |
| }, |
| key() { |
| return this.$route.path; |
| }, |
| }, |
| }; |
| </script> |
| |
| <style scoped> |
| .app-main { |
| /*50 = navbar */ |
| min-height: calc(100vh - 50px); |
| width: 100%; |
| position: relative; |
| overflow: hidden; |
| } |
| .fixed-header + .app-main { |
| padding-top: 50px; |
| } |
| </style> |
| |
| <style lang="scss"> |
| // fix css style bug in open el-dialog |
| .el-popup-parent--hidden { |
| .fixed-header { |
| padding-right: 15px; |
| } |
| } |
| </style> |
| |
| |
复制
3、修改vue-admin-template\src\layout\components\index.js
| 新增如下行: |
| export { default as TagsView } from './TagsView' |
复制
4、修改 vue-admin-template\src\layout\index.vue
| <template> |
| <div :class="classObj" class="app-wrapper"> |
| <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /> |
| <sidebar class="sidebar-container" /> |
| <div class="main-container"> |
| <div :class="{'fixed-header':fixedHeader}"> |
| <navbar /> |
| </div> |
| <tags-view /> |
| <app-main /> |
| </div> |
| </div> |
| </template> |
| |
| <script> |
| import { Navbar, Sidebar, AppMain,TagsView } from './components' |
| import ResizeMixin from './mixin/ResizeHandler' |
| |
| export default { |
| name: 'Layout', |
| components: { |
| Navbar, |
| Sidebar, |
| AppMain, |
| TagsView |
| }, |
| mixins: [ResizeMixin], |
| computed: { |
| sidebar() { |
| return this.$store.state.app.sidebar |
| }, |
| device() { |
| return this.$store.state.app.device |
| }, |
| fixedHeader() { |
| return this.$store.state.settings.fixedHeader |
| }, |
| classObj() { |
| return { |
| hideSidebar: !this.sidebar.opened, |
| openSidebar: this.sidebar.opened, |
| withoutAnimation: this.sidebar.withoutAnimation, |
| mobile: this.device === 'mobile' |
| } |
| } |
| }, |
| methods: { |
| handleClickOutside() { |
| this.$store.dispatch('app/closeSideBar', { withoutAnimation: false }) |
| } |
| } |
| } |
| </script> |
| |
| <style lang="scss" scoped> |
| @import "~@/styles/mixin.scss"; |
| @import "~@/styles/variables.scss"; |
| |
| .app-wrapper { |
| @include clearfix; |
| position: relative; |
| height: 100%; |
| width: 100%; |
| &.mobile.openSidebar{ |
| position: fixed; |
| top: 0; |
| } |
| } |
| .drawer-bg { |
| background: #000; |
| opacity: 0.3; |
| width: 100%; |
| top: 0; |
| height: 100%; |
| position: absolute; |
| z-index: 999; |
| } |
| |
| .fixed-header { |
| position: fixed; |
| top: 0; |
| right: 0; |
| z-index: 9; |
| width: calc(100% - #{$sideBarWidth}); |
| transition: width 0.28s; |
| } |
| |
| .hideSidebar .fixed-header { |
| width: calc(100% - 54px) |
| } |
| |
| .mobile .fixed-header { |
| width: 100%; |
| } |
| </style> |
复制
5、修改 vue-admin-template\src\store\getters.js,
新增
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews
| const getters = { |
| sidebar: state => state.app.sidebar, |
| device: state => state.app.device, |
| token: state => state.user.token, |
| avatar: state => state.user.avatar, |
| name: state => state.user.name, |
| visitedViews: state => state.tagsView.visitedViews, |
| cachedViews: state => state.tagsView.cachedViews |
| } |
| export default getters |
| |
复制
6、修改 vue-admin-template\src\store\index.js
引入 import tagsView from ‘./modules/tagsView’
| import Vue from 'vue' |
| import Vuex from 'vuex' |
| import getters from './getters' |
| import app from './modules/app' |
| import settings from './modules/settings' |
| import user from './modules/user' |
| import tagsView from './modules/tagsView' |
| Vue.use(Vuex) |
| |
| const store = new Vuex.Store({ |
| modules: { |
| app, |
| settings, |
| user, |
| tagsView |
| }, |
| getters |
| }) |
| |
| export default store |
| |
复制
7、运行报错
解决方式
删除vue-admin-template\src\layout\components\TagsView\index.vue中routes方法
8、解决开启头部固定,不会显示 TagsView的问题
如果settings里面开启的如下所示,TagsView将不会显示
复制
8.1、修改vue-admin-template\src\settings.js 添加
复制
8.2、修改vue-admin-template\src\store\modules\settings.js
| import defaultSettings from '@/settings' |
| |
| const { showSettings, fixedHeader, sidebarLogo,tagsView } = defaultSettings |
| |
| const state = { |
| showSettings: showSettings, |
| fixedHeader: fixedHeader, |
| sidebarLogo: sidebarLogo, |
| tagsView: tagsView, |
| } |
| |
| const mutations = { |
| CHANGE_SETTING: (state, { key, value }) => { |
| |
| if (state.hasOwnProperty(key)) { |
| state[key] = value |
| } |
| } |
| } |
| |
| const actions = { |
| changeSetting({ commit }, data) { |
| commit('CHANGE_SETTING', data) |
| } |
| } |
| |
| export default { |
| namespaced: true, |
| state, |
| mutations, |
| actions |
| } |
复制
8.3、修改 vue-admin-template\src\layout\components\AppMain.vue文件的样式如下
主要是有hasTagsView样式的时候
| <template> |
| <section class="app-main"> |
| <transition name="fade-transform" mode="out-in"> |
| |
| <keep-alive :include="cachedViews"> |
| <router-view :key="key" /> |
| </keep-alive> |
| </transition> |
| </section> |
| </template> |
| |
| <script> |
| export default { |
| name: "AppMain", |
| computed: { |
| cachedViews() { |
| return this.$store.state.tagsView.cachedViews; |
| }, |
| key() { |
| return this.$route.path; |
| }, |
| }, |
| }; |
| </script> |
| |
| <style lang="scss" scoped> |
| .app-main { |
| |
| min-height: calc(100vh - 50px); |
| width: 100%; |
| position: relative; |
| overflow: hidden; |
| } |
| |
| .fixed-header+.app-main { |
| padding-top: 50px; |
| } |
| |
| .hasTagsView { |
| .app-main { |
| |
| min-height: calc(100vh - 84px); |
| } |
| |
| .fixed-header+.app-main { |
| padding-top: 84px; |
| } |
| } |
| </style> |
| |
| <style lang="scss"> |
| // fix css style bug in open el-dialog |
| .el-popup-parent--hidden { |
| .fixed-header { |
| padding-right: 15px; |
| } |
| } |
| </style> |
| |
复制
8.4、修改 vue-admin-template\src\layout\index.vue如下
主要是通过needTagsView进行判断
| <template> |
| <div :class="classObj" class="app-wrapper"> |
| <div |
| v-if="device === 'mobile' && sidebar.opened" |
| class="drawer-bg" |
| @click="handleClickOutside" |
| /> |
| <sidebar class="sidebar-container" /> |
| <div :class="{ hasTagsView: needTagsView }" class="main-container"> |
| <div :class="{ 'fixed-header': fixedHeader }"> |
| <navbar /> |
| <tags-view v-if="needTagsView" /> |
| </div> |
| <app-main /> |
| </div> |
| |
| |
| |
| |
| |
| |
| |
| </div> |
| </template> |
| |
| <script> |
| import { Navbar, Sidebar, AppMain, TagsView } from "./components"; |
| import ResizeMixin from "./mixin/ResizeHandler"; |
| |
| export default { |
| name: "Layout", |
| components: { |
| Navbar, |
| Sidebar, |
| AppMain, |
| TagsView, |
| }, |
| mixins: [ResizeMixin], |
| computed: { |
| sidebar() { |
| return this.$store.state.app.sidebar; |
| }, |
| device() { |
| return this.$store.state.app.device; |
| }, |
| fixedHeader() { |
| return this.$store.state.settings.fixedHeader; |
| }, |
| needTagsView() { |
| return this.$store.state.settings.tagsView; |
| }, |
| classObj() { |
| return { |
| hideSidebar: !this.sidebar.opened, |
| openSidebar: this.sidebar.opened, |
| withoutAnimation: this.sidebar.withoutAnimation, |
| mobile: this.device === "mobile", |
| }; |
| }, |
| }, |
| methods: { |
| handleClickOutside() { |
| this.$store.dispatch("app/closeSideBar", { withoutAnimation: false }); |
| }, |
| }, |
| }; |
| </script> |
| |
| <style lang="scss" scoped> |
| @import "~@/styles/mixin.scss"; |
| @import "~@/styles/variables.scss"; |
| |
| .app-wrapper { |
| @include clearfix; |
| position: relative; |
| height: 100%; |
| width: 100%; |
| &.mobile.openSidebar { |
| position: fixed; |
| top: 0; |
| } |
| } |
| .drawer-bg { |
| background: #000; |
| opacity: 0.3; |
| width: 100%; |
| top: 0; |
| height: 100%; |
| position: absolute; |
| z-index: 999; |
| } |
| |
| .fixed-header { |
| position: fixed; |
| top: 0; |
| right: 0; |
| z-index: 9; |
| width: calc(100% - #{$sideBarWidth}); |
| transition: width 0.28s; |
| } |
| |
| .hideSidebar .fixed-header { |
| width: calc(100% - 54px); |
| } |
| |
| .mobile .fixed-header { |
| width: 100%; |
| } |
| </style> |
| |
复制
9、解决刷新浏览器,TagsView选项卡丢失问题
找到 src\views\layout\components\TagsView.vue 组件
9.1、在methods方法中添加如下方法
| |
| beforeUnload() { |
| |
| window.addEventListener("beforeunload", () => { |
| |
| let tabViews = this.visitedViews.map((item) => { |
| return { |
| fullPath: item.fullPath, |
| hash: item.hash, |
| meta: { ...item.meta }, |
| name: item.name, |
| params: { ...item.params }, |
| path: item.path, |
| query: { ...item.query }, |
| title: item.title, |
| }; |
| }); |
| sessionStorage.setItem("tabViews", JSON.stringify(tabViews)); |
| }); |
| |
| let oldViews = JSON.parse(sessionStorage.getItem("tabViews")) || []; |
| if (oldViews.length > 0) { |
| this.$store.state.tagsView.visitedViews = oldViews; |
| } |
| }, |
复制
9.2、mounted()生命周期函数中添加刷新选项卡方法
| mounted() { |
| this.initTags(); |
| this.addTags(); |
| |
| this.beforeUnload(); |
| }, |
复制
10、解决选项卡为【首页】不能关闭的问题
在router中的index.js找到首页路由配置项,并在 meta中添加 affix: true 如下meta配置所示
| { |
| path: '/', |
| component: Layout, |
| redirect: '/dashboard', |
| children: [{ |
| path: 'dashboard', |
| name: 'Dashboard', |
| component: () => import('@/views/dashboard/index'), |
| meta: { title: '首页', icon: 'dashboard', affix: true } |
| }] |
| } |
复制
第06讲 权限相关数据库设计
采用RBAC模型
1、用户表字段(sys_user)
字段名称 | 数据类型 | 字段大小 | 是否主键 | 是否为空 | 备注 |
---|
user_id | int | 11 | 是 | 否 | 用户id |
username | varchar | 64 | 否 | 是 | 登录账户 |
password | varchar | 128 | 否 | 是 | 登录密码 |
phone | varchar | 13 | 否 | 是 | 用户电话 |
email | varchar | 36 | 否 | 是 | 邮箱 |
sex | varchar | 2 | 否 | 是 | 0:男 1:女 |
is_admin | tinyint | 2 | 否 | 是 | 是否为超级管理员 1:是 0:否 |
is_account_non_expired | tinyint | 2 | 否 | 是 | 帐户是否过期(1 未过期,0已过期) |
is_account_non_locked | tinyint | 2 | 否 | 是 | 帐户是否被锁定(1 未锁定,0已锁定) |
is_credentials_non_expired | tinyint | 2 | 否 | 是 | 密码是否过期(1 未过期,0已过期) |
is_enabled | tinyint | 2 | 否 | 是 | 帐户是否可用(1 可用,0 删除用户) |
nick_name | varchar | 36 | 否 | 是 | 姓名 |
create_time | datetime | | 否 | 是 | 创建时间 |
update_time | datetime | | 否 | 是 | 更新时间 |
2、用户角色表(sys_user_role)
字段名称 | 数据类型 | 字段大小 | 是否主键 | 是否为空 | 备注 |
---|
user_role_id | int | 11 | 是 | 否 | 主键 |
user_id | int | 11 | 否 | 否 | 用户id |
role_id | int | 11 | 否 | 否 | 角色id |
3、角色表字段(sys_role)
字段名称 | 数据类型 | 字段大小 | 是否主键 | 是否为空 | 备注 |
---|
role_id | int | 11 | 是 | 否 | 角色id |
role_name | varchar | 64 | 否 | 是 | 角色名称 |
role_type | varchar | 2 | 否 | 是 | 角色类型 1:系统用户 2:学生 |
remark | varchar | 128 | 否 | 是 | 备注 |
create_time | datetime | | 否 | 是 | 创建时间 |
update_time | datetime | | 否 | 是 | 更新时间 |
4、角色菜单表(sys_role_menu)
字段名称 | 数据类型 | 字段大小 | 是否主键 | 是否为空 | 备注 |
---|
role_menu_id | int | 11 | 是 | 否 | 主键 |
menu_id | int | 11 | 否 | 否 | 菜单id |
role_id | int | 11 | 否 | 否 | 角色id |
5、菜单表字段(sys_menu)
字段名称 | 数据类型 | 字段大小 | 是否主键 | 是否为空 | 备注 |
---|
menu_id | int | 11 | 是 | 否 | 菜单id |
parent_id | int | 11 | 否 | 是 | 父级菜单id |
title | varchar | 64 | 否 | 是 | 菜单名称 |
code | varchar | 64 | 否 | 是 | 权限字段 |
name | varchar | 36 | 否 | 是 | 路由name |
path | varchar | 36 | 否 | 是 | 路由path |
url | varchar | 128 | 否 | 是 | 组件路径 |
type | varchar | 2 | 否 | 是 | 类型(0 目录 1菜单,2按钮) |
icon | varchar | 36 | 否 | 是 | 菜单图标 |
parent_name | varchar | 64 | 否 | 是 | 上级菜单名称 |
order_num | int | 11 | 否 | 是 | 序号 |
create_time | datetime | | 否 | 是 | 创建时间 |
update_time | datetime | | 否 | 是 | 更新时间 |
| |
| |
| |
| |
| |
| |
| drop table if exists sys_menu; |
| |
| drop table if exists sys_role; |
| |
| drop table if exists sys_role_menu; |
| |
| drop table if exists sys_user; |
| |
| drop table if exists sys_user_role; |
| |
| |
| |
| |
| create table sys_menu |
| ( |
| menu_id int not null auto_increment comment '菜单id', |
| parent_id int comment '父级菜单id', |
| title varchar(36) comment '菜单名称', |
| code varchar(36) comment '权限字段', |
| name varchar(36) comment '路由name', |
| path varchar(36) comment '路由path', |
| url varchar(128) comment '组件路径', |
| type varchar(2) comment '类型(0 目录 1菜单,2按钮)', |
| icon varchar(36) comment '菜单图标', |
| parent_name varchar(36) comment '上级菜单名称', |
| order_num int comment '序号', |
| create_time datetime comment '创建时间', |
| update_time datetime comment '更新时间', |
| primary key (menu_id) |
| ); |
| |
| |
| |
| |
| create table sys_role |
| ( |
| role_id int not null auto_increment comment '角色id', |
| role_name varchar(36) comment '角色名称', |
| role_type varchar(2) comment '角色类型 1:系统用户 2:学生', |
| remark varchar(64) comment '备注', |
| create_time datetime comment '创建时间', |
| update_time datetime comment '更新时间', |
| primary key (role_id) |
| ); |
| |
| |
| |
| |
| create table sys_role_menu |
| ( |
| role_menu_id int not null auto_increment comment '主键', |
| role_id int comment '角色id', |
| menu_id int comment '菜单id', |
| primary key (role_menu_id) |
| ); |
| |
| |
| |
| |
| create table sys_user |
| ( |
| user_id int not null auto_increment comment '用户id', |
| username varchar(36) comment '登录账户', |
| password varchar(128) comment '密码', |
| phone varchar(13) comment '13', |
| email varchar(36) comment '邮箱', |
| sex varchar(2) comment '性别', |
| is_admin varchar(2) comment '是否是管理员', |
| is_account_non_expired int comment '帐户是否过期(1 未过期,0已过期)', |
| is_account_non_locked int comment '帐户是否被锁定(1 未锁定,0已锁定)', |
| is_credentials_non_expired int comment '密码是否过期(1 未过期,0已过期)', |
| is_enabled int comment '帐户是否可用(1 可用,0 删除用户)', |
| nick_name varbinary(36) comment '姓名', |
| create_time datetime comment '创建时间', |
| update_time datetime comment '更新时间', |
| primary key (user_id) |
| ); |
| |
| |
| |
| |
| |
| create table sys_user_role |
| ( |
| user_role_id int not null auto_increment comment '主键', |
| user_id int comment '用户id', |
| role_id int comment '角色id', |
| primary key (user_role_id) |
| ); |
| |
| |
| |
复制
第07讲 后台多模块系统搭建
开发环境配置:
| 1、JDK安装配置 |
| 2、IDEA安装 |
| 3、maven安装 |
| 4、MySql安装 |
| 5、数据库可视化工具 Navicat安装 |
复制
maven配置
| 1、配置本地仓库地址: <localRepository>D:\javaDe\apache-maven-3.5.4\repo</localRepository> |
| 2、修改为阿里镜像: |
| <mirror> |
| <id>nexus-aliyun</id> |
| <mirrorOf>central</mirrorOf> |
| <name>Nexus aliyun</name> |
| <url>http://maven.aliyun.com/nexus/content/groups/public</url> |
| </mirror> |
复制
1、项目依赖版本号**
JDk1.8及以上、Maven3.5以上、MySq5.7以上
2、项目结构
itmk-base-parent | 父模块,pom类型、统一管理子模块 |
---|
itmk-base-common | 公共模块、如通用工具的封装等 |
itmk-base-web | 前端接口模块,提供api接口 |
3、创建itmk-base-parent父模块
1、打开IDEA,file -> new - > project
2、选择左侧Maven,Project SDK选择1.8及以上,点击Next
3、Name里面输入模块名称,Location选择项目存储路径,GroupId:输入包名,同一个项目,各个模块的包名一致 ArtifactId: 模块名称;点击Finish
4、由于itmk-base-parent作为父模块,把生成的模块中的src删除;
4、创建itmk-base-common模块
1.在父模块itmk-base-parent上右键->New->Module,如下所示
2.选择Maven,SDK选择1.8及以上,点击Next
3.Name:输入模块名称 itmk-base-common,点击Finish
5、创建itmk-base-web模块
1.itmk-base-parent模块右键,点击New->Module
2.选择Maven,SDK选择1.8及以上,点击 Next
3.Name填入模块名称,点击Finish
4.项目最终模块
第08讲 引入各个模块依赖
1、修改package类型
修改父模块 itmk-base-parent的pom.xml打包类型为 pom;
itmk-base-common的pom.xml打包类型为 jar;
itmk-base-wem的pom.xml打包类型为jar
2、itmk-base-parent pom.xml文件
| <?xml version="1.0" encoding="UTF-8"?> |
| <project xmlns="http://maven.apache.org/POM/4.0.0" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| <modelVersion>4.0.0</modelVersion> |
| |
| <groupId>com.itmk</groupId> |
| <artifactId>itmk-base-parent</artifactId> |
| <packaging>pom</packaging> |
| <version>1.0-SNAPSHOT</version> |
| <modules> |
| <module>itmk-base-common</module> |
| <module>itmk-base-web</module> |
| </modules> |
| <parent> |
| <groupId>org.springframework.boot</groupId> |
| <artifactId>spring-boot-starter-parent</artifactId> |
| <version>2.4.4</version> |
| </parent> |
| <properties> |
| <java.version>1.8</java.version> |
| <swagger2.version>3.0.0</swagger2.version> |
| <lombok-version>1.18.12</lombok-version> |
| <mybatis-plus.version>3.4.2</mybatis-plus.version> |
| <druid.version>1.2.1</druid.version> |
| <kaptcha.version>2.3.2</kaptcha.version> |
| <fastjson.version>1.2.68</fastjson.version> |
| <commons-lang.version>2.6</commons-lang.version> |
| <commons-collections.version>3.2.2</commons-collections.version> |
| <commons-io.version>2.6</commons-io.version> |
| <mysql-connection.version>8.0.21</mysql-connection.version> |
| </properties> |
| <dependencyManagement> |
| <dependencies> |
| |
| <dependency> |
| <groupId>org.projectlombok</groupId> |
| <artifactId>lombok</artifactId> |
| <version>${lombok-version}</version> |
| <scope>provided</scope> |
| </dependency> |
| <dependency> |
| <groupId>mysql</groupId> |
| <artifactId>mysql-connector-java</artifactId> |
| <version>${mysql-connection.version}</version> |
| <scope>runtime</scope> |
| </dependency> |
| |
| <dependency> |
| <groupId>com.alibaba</groupId> |
| <artifactId>druid-spring-boot-starter</artifactId> |
| <version>${druid.version}</version> |
| </dependency> |
| |
| <dependency> |
| <groupId>com.baomidou</groupId> |
| <artifactId>mybatis-plus-boot-starter</artifactId> |
| <version>${mybatis-plus.version}</version> |
| </dependency> |
| |
| <dependency> |
| <groupId>com.github.penggle</groupId> |
| <artifactId>kaptcha</artifactId> |
| <version>${kaptcha.version}</version> |
| </dependency> |
| |
| |
| <dependency> |
| <groupId>com.alibaba</groupId> |
| <artifactId>fastjson</artifactId> |
| <version>${fastjson.version}</version> |
| </dependency> |
| |
| <dependency> |
| <groupId>commons-lang</groupId> |
| <artifactId>commons-lang</artifactId> |
| <version>${commons-lang.version}</version> |
| </dependency> |
| <dependency> |
| <groupId>commons-collections</groupId> |
| <artifactId>commons-collections</artifactId> |
| <version>${commons-collections.version}</version> |
| </dependency> |
| <dependency> |
| <groupId>commons-io</groupId> |
| <artifactId>commons-io</artifactId> |
| <version>${commons-io.version}</version> |
| </dependency> |
| <dependency> |
| <groupId>io.springfox</groupId> |
| <artifactId>springfox-boot-starter</artifactId> |
| <version>${swagger2.version}</version> |
| </dependency> |
| </dependencies> |
| </dependencyManagement> |
| |
| </project> |
复制
3、itmk-base-common pom.xml
| <?xml version="1.0" encoding="UTF-8"?> |
| <project xmlns="http://maven.apache.org/POM/4.0.0" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| <parent> |
| <artifactId>itmk-base-parent</artifactId> |
| <groupId>com.itmk</groupId> |
| <version>1.0-SNAPSHOT</version> |
| </parent> |
| <modelVersion>4.0.0</modelVersion> |
| |
| <artifactId>itmk-base-common</artifactId> |
| <dependencies> |
| <dependency> |
| <groupId>org.projectlombok</groupId> |
| <artifactId>lombok</artifactId> |
| </dependency> |
| |
| <dependency> |
| <groupId>io.springfox</groupId> |
| <artifactId>springfox-boot-starter</artifactId> |
| </dependency> |
| |
| <dependency> |
| <groupId>io.jsonwebtoken</groupId> |
| <artifactId>jjwt</artifactId> |
| <version>0.9.0</version> |
| </dependency> |
| |
| <dependency> |
| <groupId>com.alibaba</groupId> |
| <artifactId>fastjson</artifactId> |
| </dependency> |
| </dependencies> |
| </project> |
复制
4、itmk-base-web pom.xml
| <?xml version="1.0" encoding="UTF-8"?> |
| <project xmlns="http://maven.apache.org/POM/4.0.0" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| <parent> |
| <artifactId>itmk-base-parent</artifactId> |
| <groupId>com.itmk</groupId> |
| <version>1.0-SNAPSHOT</version> |
| </parent> |
| <modelVersion>4.0.0</modelVersion> |
| |
| <artifactId>itmk-base-web</artifactId> |
| <dependencies> |
| <dependency> |
| <groupId>com.itmk</groupId> |
| <artifactId>itmk-base-common</artifactId> |
| <version>1.0-SNAPSHOT</version> |
| </dependency> |
| |
| <dependency> |
| <groupId>org.springframework.boot</groupId> |
| <artifactId>spring-boot-starter-web</artifactId> |
| </dependency> |
| <dependency> |
| <groupId>org.springframework.boot</groupId> |
| <artifactId>spring-boot-starter-aop</artifactId> |
| </dependency> |
| |
| |
| <dependency> |
| <groupId>org.springframework.boot</groupId> |
| <artifactId>spring-boot-starter-jdbc</artifactId> |
| </dependency> |
| <dependency> |
| <groupId>mysql</groupId> |
| <artifactId>mysql-connector-java</artifactId> |
| </dependency> |
| |
| <dependency> |
| <groupId>com.baomidou</groupId> |
| <artifactId>mybatis-plus-boot-starter</artifactId> |
| </dependency> |
| |
| <dependency> |
| <groupId>com.alibaba</groupId> |
| <artifactId>druid-spring-boot-starter</artifactId> |
| </dependency> |
| |
| <dependency> |
| <groupId>io.springfox</groupId> |
| <artifactId>springfox-boot-starter</artifactId> |
| </dependency> |
| <dependency> |
| <groupId>org.projectlombok</groupId> |
| <artifactId>lombok</artifactId> |
| </dependency> |
| <dependency> |
| <groupId>org.apache.commons</groupId> |
| <artifactId>commons-compress</artifactId> |
| <version>1.18</version> |
| </dependency> |
| <dependency> |
| <groupId>commons-lang</groupId> |
| <artifactId>commons-lang</artifactId> |
| </dependency> |
| </dependencies> |
| <build> |
| <plugins> |
| <plugin> |
| <groupId>org.springframework.boot</groupId> |
| <artifactId>spring-boot-maven-plugin</artifactId> |
| <version>2.1.4.RELEASE</version> |
| </plugin> |
| <plugin> |
| <groupId>org.apache.maven.plugins</groupId> |
| <artifactId>maven-compiler-plugin</artifactId> |
| <version>3.1</version> |
| <configuration> |
| <source>${java.version}</source> |
| <target>${java.version}</target> |
| </configuration> |
| </plugin> |
| <plugin> |
| <groupId>org.apache.maven.plugins</groupId> |
| <artifactId>maven-surefire-plugin</artifactId> |
| <version>2.19.1</version> |
| <configuration> |
| <skipTests>true</skipTests> |
| </configuration> |
| </plugin> |
| </plugins> |
| </build> |
| |
| </project> |
复制
第09讲 整合MyBatis Plus
mybatis plus官方教程**
复制
1、新建application.yml文件
1.1、在itmk-base-web模块resources文件下新建 application-test.yml文件
| #端口号配置 |
| server: |
| port: 8089 |
| #数据库连接配置 |
| spring: |
| datasource: |
| type: com.alibaba.druid.pool.DruidDataSource |
| driver-class-name: com.mysql.cj.jdbc.Driver |
| url: jdbc:mysql: |
| username: root |
| password: 123456 |
| |
| #mybatis plus配置 |
| mybatis-plus: |
| configuration: |
| log-impl: org.apache.ibatis.logging.stdout.StdOutImpl |
| global-config: |
| db-config: |
| #配置mybatis plus 在更新时只更新非空和非NULL的字段 |
| update-strategy: not_empty |
| |
| logging: |
| pattern: |
| console: '%d{yyyy-MM-dd} [%thread] %-5level %logger- %msg%n' |
复制
1.2、在itmk-base-web模块resources文件下新建 application.yml文件
| spring: |
| profiles: |
| active: test |
复制
2、配置MyBatis Plus配置文件
| package com.itmk.config.mybatis; |
| |
| import com.baomidou.mybatisplus.annotation.DbType; |
| import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
| import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; |
| import org.mybatis.spring.annotation.MapperScan; |
| import org.springframework.context.annotation.Bean; |
| import org.springframework.context.annotation.Configuration; |
| |
| @Configuration |
| @MapperScan("com.itmk.*.*.mapper") |
| public class MyBatisPlusConfig { |
| |
| @Bean |
| public MybatisPlusInterceptor mybatisPlusInterceptor() { |
| MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); |
| interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); |
| return interceptor; |
| } |
| } |
复制
3、封装返回值
在itmk-base-common下新建 com.itmk.utils包
| package com.itmk.utils; |
| import lombok.AllArgsConstructor; |
| import lombok.Data; |
| |
| @Data |
| @AllArgsConstructor |
| public class ResultVo<T> { |
| private String msg; |
| private int code; |
| private T data; |
| } |
复制
4、返回状态码定义
在itmk-base-common模块新建com.itmk.status包,然后新建 StatusCode类,如下所示
| package com.itmk.status; |
| |
| |
| |
| |
| public class StatusCode { |
| |
| public static final int SUCCESS_CODE = 200; |
| |
| public static final int ERROR_CODE = 500; |
| |
| public static final int NO_LOGIN = 600; |
| public static final int NO_AUTH = 700; |
| } |
复制
5、返回工具类的封装
在itmk-base-common模块下的com.itmk.utils包中新建ResultUtils类
| package com.itmk.utils; |
| |
| import com.itmk.status.StatusCode; |
| |
| |
| |
| |
| public class ResultUtils { |
| |
| |
| |
| |
| public static ResultVo succcess() { |
| return Vo(null, StatusCode.SUCCESS_CODE, null); |
| } |
| public static ResultVo success(String msg){ |
| return Vo(msg,StatusCode.SUCCESS_CODE,null); |
| } |
| |
| |
| |
| |
| |
| |
| public static ResultVo success(String msg,Object data){ |
| return Vo(msg,StatusCode.SUCCESS_CODE,data); |
| } |
| public static ResultVo success(String msg,int code,Object data){ |
| return Vo(msg,code,data); |
| } |
| public static ResultVo Vo(String msg, int code, Object data) { |
| return new ResultVo(msg, code, data); |
| } |
| |
| |
| |
| |
| |
| public static ResultVo error(){ |
| return Vo(null,StatusCode.ERROR_CODE,null); |
| } |
| public static ResultVo error(String msg){ |
| return Vo(msg,StatusCode.ERROR_CODE,null); |
| } |
| public static ResultVo error(String msg,int code,Object data){ |
| return Vo(msg,code,data); |
| } |
| public static ResultVo error(String msg,int code){ |
| return Vo(msg,code,null); |
| } |
| public static ResultVo error(String msg,Object data){ |
| return Vo(msg, StatusCode.ERROR_CODE,data); |
| } |
| } |
复制
第10讲 用户管理列表页面制作
1、sysUserList.vue页面编写
| <template> |
| <el-main> |
| <!-- 搜索栏 element ui的标签,就当做普通的div就可以,只是他添加了一些属性 |
| :model: form表单绑定的数据,通常是一个对象 |
| :rules: form表单验证的规则 |
| ref : 类似div的id,是唯一的 |
| label-width:表单文字标签的宽度 |
| :inline : 是否同一行显示 |
| size: 表单内组件的大小 |
| --> |
| <el-form |
| :model="listParm" |
| ref="searchRef" |
| label-width="80px" |
| :inline="true" |
| size="small" |
| > |
| <el-form-item> |
| <el-input |
| placeholder="请输入姓名" |
| v-model="listParm.nickName" |
| ></el-input> |
| </el-form-item> |
| <el-form-item> |
| <el-input placeholder="请输入电话" v-model="listParm.phone"></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 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="name" label="姓名"></el-table-column> |
| <el-table-column prop="address" label="地址"></el-table-column> |
| <el-table-column prop="date" label="日期"></el-table-column> |
| <el-table-column label="操作" align="center" width="180"> |
| <template slot-scope="scope"> |
| <el-button |
| type="primary" |
| size="small" |
| icon="el-icon-edit" |
| @click="editBtn(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> |
| |
| </el-main> |
| </template> |
| |
| <script> |
| export default { |
| data() { |
| return { |
| //表格高度 |
| tableHeight:0, |
| //列表查询的参数 |
| listParm: { |
| phone: "", |
| nickName: "", |
| currentPage:1, |
| pageSize:10, |
| total:0 |
| }, |
| //表格的数据 |
| tableData: [ |
| { |
| date: "2016-05-02", |
| name: "王小虎", |
| address: "上海市普陀区金沙江路 1518 弄", |
| }, |
| { |
| id: 2, |
| date: "2016-05-04", |
| name: "王小虎", |
| address: "上海市普陀区金沙江路 1517 弄", |
| }, |
| { |
| 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 弄", |
| }, |
| ], |
| }; |
| }, |
| methods: { |
| //重置按钮 |
| resetBtn(){ |
| |
| }, |
| //搜索按钮 |
| searchBtn(){ |
| |
| }, |
| //新增按钮 |
| addBtn() {}, |
| //编辑按钮 |
| editBtn(row) {}, |
| //删除按钮 |
| deleteBtn(row) {}, |
| //页容量改变触发 |
| sizeChange(val){ |
| |
| }, |
| //页数改变触发 |
| currentChange(val){ |
| |
| } |
| }, |
| mounted(){ |
| this.$nextTick(() =>{ |
| this.tableHeight = window.innerHeight -220 |
| }) |
| } |
| }; |
| </script> |
| |
| <style lang="scss" scoped> |
| </style> |
复制
2、分页插件显示中文
在main.js中引入如下,注释原来的local
| |
| import locale from 'element-ui/lib/locale/lang/zh-CN' |
复制
第11讲 通用弹框组件封装
| 知识点: |
| |
| 父组件向子组件传值 :属性绑定 |
| |
| 子组件调用父组件的方法 : $emit向父组件触发事件 |
复制
1.封装效果
2.对话框官网
https://element.eleme.cn/#/zh-CN/component/dialog
3.对话框封装
在components下新建system目录,然后新建SysDialog.vue组件,然后把官网弹框代码复制进去
| <!--弹出框组件 |
| 参数说明: |
| title:弹出框标题 |
| visible:控制弹出框的显示和影藏 |
| width:弹出框的宽度,百分百,0~100的整数 |
| before-close:弹出框右上角关闭事件 |
| close-on-click-modal:防止点击弹出框以外的区域造成弹出框关闭 |
| --> |
| <template> |
| <div> |
| <el-dialog |
| top="5vh" |
| :title="title" |
| :visible.sync="visible" |
| :width="width + 'px'" |
| :before-close="onClose" |
| :close-on-click-modal="false" |
| > |
| <div class="containner" :style="{ height: height + 'px' }"> |
| <slot name="content"></slot> |
| </div> |
| <span slot="footer" class="dialog-footer"> |
| <el-button @click="onClose">取 消</el-button> |
| <el-button type="primary" @click="onConfirm">确 定</el-button> |
| </span> |
| </el-dialog> |
| </div> |
| </template> |
| |
| <script> |
| export default { |
| props: { |
| title: { |
| type: String, |
| default: "标题", |
| }, |
| visible: { |
| type: Boolean, |
| default: false, |
| }, |
| width: { |
| type: Number, |
| default: 600, |
| }, |
| height: { |
| type: Number, |
| default: 250, |
| }, |
| }, |
| data() { |
| return {}; |
| }, |
| methods: { |
| onClose() { |
| this.$emit("onClose"); |
| }, |
| onConfirm() { |
| this.$emit("onConfirm"); |
| }, |
| }, |
| }; |
| </script> |
| |
| <style lang="scss" scoped> |
| .containner{ |
| overflow-x: initial; |
| overflow-y: auto; |
| } |
| |
| .el-dialog__wrapper { |
| ::v-deep .el-dialog { |
| border-top-left-radius: 7px !important; |
| border-top-right-radius: 7px !important; |
| .el-dialog__header { |
| border-top-left-radius: 7px !important; |
| border-top-right-radius: 7px !important; |
| background-color: #1890ff; |
| .el-dialog__title { |
| color: #fff; |
| font-size: 15px; |
| font-weight: 700; |
| } |
| .el-dialog__close { |
| color: #fff; |
| } |
| } |
| .el-dialog__body { |
| padding: 10px 10px !important; |
| } |
| .el-dialog__footer { |
| border-top: 1px solid #e8eaec !important; |
| padding: 10px !important; |
| } |
| } |
| } |
| </style> |
| |
复制
4.测试官网对话框
找到sysUserList.vue组件,然后引入SysDialog.vue组件,并注册SysDialog组件
| <template> |
| <div> |
| <sys-dialog |
| :title="addDialog.title" |
| :visible="addDialog.visible" |
| :width="addDialog.width" |
| :height="addDialog.height" |
| @onClose="onColse" |
| @onConfirm="onConfirm" |
| > |
| <div slot="content">弹框内容</div> |
| </sys-dialog> |
| </div> |
| </template> |
| |
| <script> |
| import SysDialog from "@/components/system/SysDialog"; |
| export default { |
| components: { |
| SysDialog |
| }, |
| data(){ |
| return{ |
| addDialog: { |
| title: "新增用", |
| visible: false, |
| width: 600, |
| height: 250, |
| }, |
| } |
| }, |
| methods:{ |
| |
| onColse() { |
| this.addDialog.visible = false; |
| }, |
| |
| onConfirm() { |
| this.addDialog.visible = false; |
| }, |
| } |
| }; |
| </script> |
| |
| <style lang="scss" scoped> |
| </style> |
复制
第12讲 新增用户页面布局讲解
1、解决点击弹框外关闭问题
| 1、添加 :close-on-click-modal='false' 属性 |
复制
2、新增表单
3、代码
| <!-- 新增或编辑弹框组件 --> |
| <sys-dialog |
| :title="dialog.title" |
| :visible="dialog.visible" |
| :width="dialog.width" |
| :height="dialog.height" |
| @onClose="onClose" |
| @onConfirm="onConfirm" |
| > |
| <div slot="content"> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| <el-form |
| :model="addModel" |
| ref="addRef" |
| :rules="rules" |
| label-width="60px" |
| size="small" |
| style="margin-right: 20px" |
| > |
| <el-row> |
| <el-col :span="12" :offset="0"> |
| <el-form-item label="姓名"> |
| <el-input v-model="addModel.nickName"></el-input> |
| </el-form-item> |
| </el-col> |
| <el-col :span="12" :offset="0"> |
| <el-form-item label="电话"> |
| <el-input v-model="addModel.phone"></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.email"></el-input> |
| </el-form-item> |
| </el-col> |
| <el-col :span="12" :offset="0"> |
| <el-form-item label="性别"> |
| <el-radio-group v-model="addModel.sex"> |
| <el-radio :label="'0'">男</el-radio> |
| <el-radio :label="'1'">女</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 v-model="addModel.username"></el-input> |
| </el-form-item> |
| </el-col> |
| <el-col :span="12" :offset="0"> |
| <el-form-item label="密码"> |
| <el-input v-model="addModel.password"></el-input> |
| </el-form-item> |
| </el-col> |
| </el-row> |
| </el-form> |
| </div> |
| </sys-dialog> |
复制
第13讲 表单验证规则
1、表单验证的关键
| 1、给表单添加ref属性 |
| 2、给el-form-item添加prop属性 |
| 3、定义表单验证的规则 |
| 4、表单提交时,通过 this.$refs.表单的ref.validate() |
复制
第14讲 用户管理接口开发
1、新建用户实体类
新建com.itmk.web.sys_user.entity包,然后新建SysUser实体类
| package com.itmk.web.sys_user.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; |
| |
| @Data |
| @TableName("sys_user") |
| public class SysUser { |
| @TableId(type = IdType.AUTO) |
| private Long userId; |
| private String username; |
| private String password; |
| private String phone; |
| private String email; |
| private String sex; |
| private String isAdmin; |
| |
| private boolean isAccountNonExpired = true; |
| |
| private boolean isAccountNonLocked = true; |
| |
| private boolean isCredentialsNonExpired = true; |
| |
| private boolean isEnabled = true; |
| private String nickName; |
| |
| private Date createTime; |
| |
| private Date updateTime; |
| } |
| |
复制
2、新建mapper接口
| package com.itmk.web.sys_user.mapper; |
| |
| import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| import com.itmk.web.sys_user.entity.SysUser; |
| |
| public interface SysUserMapper extends BaseMapper<SysUser> { |
| } |
| |
复制
3、新建mapper接口映射文件
| <!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.mapper.SysUserMapper"> |
| |
| </mapper> |
复制
4、新建service层
| 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); |
| } |
| |
复制
参数接收类
| package com.itmk.web.sys_user.entity; |
| |
| import lombok.Data; |
| |
| @Data |
| public class PageParm { |
| private Long currentPage; |
| private Long pageSize; |
| private String phone; |
| private String nickName; |
| } |
| |
复制
实现类
| 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 org.apache.commons.lang.StringUtils; |
| import org.springframework.stereotype.Service; |
| |
| @Service |
| public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService { |
| @Override |
| public IPage<SysUser> list(PageParm parm) { |
| |
| IPage<SysUser> page = new Page<>(); |
| page.setSize(parm.getPageSize()); |
| page.setCurrent(parm.getCurrentPage()); |
| 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 |
| privas.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; |
| |
| |
| |
| |
| |
| @Data |
| public class LoginParm { |
| private String username; |
| private String password; |
| private String userType; |
| } |
| |
复制
| package com.itmk.web.login.entity; |
| |
| import lombok.Data; |
| |
| |
| |
| |
| |
| @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) |
| } |
| |
| export function setUserId(userId) { |
| return sessionStorage.setItem(userIdKey, userId) |
| } |
| export function getUserId() { |
| return sessionStorage.getItem(userIdKey) |
| } |
| export function removeUserId() { |
| return sessionStorage.remove(userIdKey); |
| } |
| |
| export function clearSession() { |
| return sessionStorage.clear() |
| } |
| |
复制
3、store/user.js中的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', '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()方法
| |
| List<SysMenu> getMenuByUserId(Long userId); |
| |
| 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()方法
| |
| List<SysMenu> getMenuByUserId(@Param("userId") Long userId); |
| |
| 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<>(); |
| |
| 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="ediBtn(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" |
| :width="dialog.width" |
| :page-sizes="[10, 20, 40, 80, 100]" |
| :page-size="listParm.pageSize" |
| layout="total, sizes, prev, pager, next, jumper" |
| :total="listParm.total" |
| <!-- el-form :当做一个普通的form标签 |
| el-input : 相当于 普通的 input标签 |
| el-form-item : 表单的每一项 |
| model : 表单绑定的数据 |
| ref : 相当于一个div的id , 唯一的 |
| rules : 表单验证规则 |
| label-width : 表单域标签的宽度 |
| inline : 是否在同一行显示,如果和el-row使用时,不需要该属性 |
| size : 尺寸 |
| --> |
| background |
| > |
| </el-pagination> |
| <!-- 新增编辑弹框 --> |
| <sys-dialog |
| :title="dialog.title" |
| style="margin-right: 40px" |
| :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="nickName" label="姓名"> |
| <el-input v-model="addModel.nickName"></el-input> |
| </el-form-item> |
| </el-col> |
| <el-col :span="12" :offset="0"> |
| <el-form-item prop="phone" label="电话"> |
| <el-input v-model="addModel.phone"></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.email"></el-input> |
| </el-form-item> |
| </el-col> |
| <el-col :span="12" :offset="0"> |
| <el-form-item prop="sex" label="性别"> |
| <el-radio-group v-model="addModel.sex"> |
| <el-radio :label="'0'">男</el-radio> |
| <el-radio :label="'1'">女</el-radio> |
| </el-radio-group> |
| </el-form-item> |
| </el-col> |
| </el-row> |
| <el-row> |
| <el-col :span="12" :offset="0"> |
| <el-form-item prop="username" label="账户"> |
| <el-input v-model="addModel.username"></el-input> |
| </el-form-item> |
| </el-col> |
| <el-col v-if="addModel.type == '0'" :span="12" :offset="0"> |
| <el-form-item prop="password" label="密码"> |
| <el-input v-model="addModel.password"></el-input> |
| </el-form-item> |
| </el-col> |
| </el-row> |
| </el-form> |
| </div> |
| </sys-dialog> |
| </el-main> |
| </template> |
| |
| <script> |
| import { getListApi, addUserApi, editUserApi } from "@/api/user"; |
| //引入弹框组件 |
| import SysDialog from "@/components/dialog/SysDialog.vue"; |
| export default { |
| //注册弹框组件 |
| components: { |
| SysDialog, |
| }, |
| data() { |
| return { |
| //表单验证规则 |
| rules: { |
| nickName: [ |
| { |
| trigger: "blur", |
| required: true, |
| message: "请填写姓名", |
| }, |
| ], |
| phone: [ |
| { |
| trigger: "blur", |
| required: true, |
| message: "请填写电话", |
| }, |
| ], |
| sex: [ |
| { |
| trigger: "blur", |
| required: true, |
| message: "请选择性别", |
| }, |
| ], |
| username: [ |
| { |
| trigger: "blur", |
| required: true, |
| message: "请填写账户", |
| }, |
| ], |
| password: [ |
| { |
| trigger: "blur", |
| required: true, |
| message: "请填写密码", |
| }, |
| ], |
| }, |
| //表单绑定的数据 |
| addModel: { |
| type: "", |
| userId: "", |
| nickName: "", |
| phone: "", |
| email: "", |
| sex: "", |
| username: "", |
| password: "", |
| }, |
| //弹框属性 |
| dialog: { |
| title: "", |
| visible: false, |
| width: 630, |
| height: 200, |
| }, |
| //表格的高度 |
| tableHeight: 0, |
| listParm: { |
| total: 0, |
| pageSize: 10, //默认每页显示10条数据 |
| currentPage: 1, |
| nickName: "", |
| phone: "", |
| }, |
| tableData: [], |
| }; |
| }, |
| created() { |
| this.getList(); |
| }, |
| methods: { |
| async getList() { |
| let res = await getListApi(this.listParm); |
| console.log("请求成功"); |
| console.log(res); |
| if (res && res.code == 200) { |
| this.tableData = res.data.records; |
| this.listParm.total = res.data.total; |
| } |
| }, |
| //弹框的确定 |
| onConfirm() { |
| //表单验证 |
| this.$refs.addRef.validate(async (valid) => { |
| if (valid) { |
| let res = null; |
| if (this.addModel.type == "0") { |
| res = await addUserApi(this.addModel); |
| } else { |
| res = await editUserApi(this.addModel); |
| } |
| if (res && res.code == 200) { |
| //刷新表单 |
| this.getList(); |
| this.$message({ type: "success", message: res.msg }); |
| } |
| } |
| }); |
| }, |
| //弹框的取消 |
| onClose() { |
| this.dialog.visible = false; |
| }, |
| //页数改变时触发 |
| currentChange(val) {}, |
| //页容量改变时触发 |
| sizeChange(val) {}, |
| //编辑按钮 |
| editBtn(row) { |
| //设置弹框属性 |
| this.dialog.title = "编辑用户"; |
| this.dialog.visible = true; |
| //清空表单 |
| this.$resetForm("addRef", this.addModel); |
| //把当前要编辑的数据复制到表单数据域 |
| this.$objCoppy(row, this.addModel); |
| //设置编辑标识 |
| this.addModel.type = "1"; |
| }, |
| //搜索按钮 |
| searchBtn() {}, |
| //搜索按钮 |
| resetBtn() {}, |
| //新增按钮 |
| addBtn() { |
| //设置弹框属性 |
| this.dialog.title = "新增角色"; |
| this.dialog.visible = true; |
| //清空表单 |
| this.$resetForm("addRef", this.addModel); |
| //设置编辑标识 |
| this.addModel.type = "0"; |
| }, |
| }, |
| mounted() { |
| this.$nextTick(() => { |
| //计算表格的高度 |
| this.tableHeight = window.innerHeight - 220; |
| }); |
| }, |
| }; |
| </script> |
| |
| <style lang="scss" scoped> |
| </style> |
复制
第18讲 删除、搜索功能对接
1、api/user下新建如下方法
| |
| export const deleteUserApi = async(parm) =>{ |
| return await http.delete("/api/user",parm) |
| } |
| |
复制
2、sysUserList.vue
| <template> |
| <!-- 只需要把element的标签,当做一个普通的div --> |
| <el-main> |
| <!-- 搜索栏 |
| :model: 表单绑定的数据,通常是一个对象 |
| ref : 相当于一个div的id,唯一的 |
| :rules : 表单验证的规则 |
| label-width: 表单域标签的宽度,例如 '50px' |
| :inline : 是否在同一行显示 |
| size: 尺寸 |
| --> |
| <el-form |
| :model="listParm" |
| ref="form" |
| label-width="80px" |
| :inline="true" |
| size="small" |
| > |
| <el-form-item> |
| <el-input |
| placeholder="请输入姓名" |
| v-model="listParm.nickName" |
| ></el-input> |
| </el-form-item> |
| <el-form-item> |
| <el-input placeholder="请输入电话" v-model="listParm.phone"></el-input> |
| </el-form-item> |
| <el-form-item> |
| <el-button icon="el-icon-search" @click="searchBtn">搜索</el-button> |
| <el-button icon="el-icon-close" style="color: #ff7670" @click="resetBtn" |
| >重置</el-button |
| > |
| <el-button type="primary" icon="el-icon-plus" @click="addBtn" |
| >新增</el-button |
| > |
| </el-form-item> |
| </el-form> |
| <!-- 表格 |
| :data 表格的数据 |
| |
| --> |
| <el-table :height="tableHeight" :data="tableData" border stripe> |
| <el-table-column prop="nickName" label="姓名"></el-table-column> |
| <el-table-column prop="phone" label="电话"></el-table-column> |
| <el-table-column prop="email" label="邮箱"></el-table-column> |
| <el-table-column label="操作" width="180" align="center"> |
| <template slot-scope="scope"> |
| <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" |
| 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" |
| :width="dialog.width" |
| :visible="dialog.visible" |
| :height="dialog.height" |
| @onClose="onClose" |
| @onConfirm="onConfirm" |
| > |
| <div slot="content"> |
| <!-- el-form :当做一个普通的form标签 |
| el-input : 相当于 普通的 input标签 |
| el-form-item : 表单的每一项 |
| model : 表单绑定的数据 |
| ref : 相当于一个div的id , 唯一的 |
| rules : 表单验证规则 |
| label-width : 表单域标签的宽度 |
| inline : 是否在同一行显示,如果和el-row使用时,不需要该属性 |
| size : 尺寸 |
| --> |
| <el-form |
| :model="addModel" |
| ref="addRef" |
| :rules="rules" |
| label-width="80px" |
| size="small" |
| style="margin-right: 40px" |
| > |
| <el-row> |
| <el-col :span="12" :offset="0"> |
| <el-form-item prop="nickName" label="姓名"> |
| <el-input v-model="addModel.nickName"></el-input> |
| </el-form-item> |
| </el-col> |
| <el-col :span="12" :offset="0"> |
| <el-form-item prop="phone" label="电话"> |
| <el-input v-model="addModel.phone"></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.email"></el-input> |
| </el-form-item> |
| </el-col> |
| <el-col :span="12" :offset="0"> |
| <el-form-item prop="sex" label="性别"> |
| <el-radio-group v-model="addModel.sex"> |
| <el-radio :label="'0'">男</el-radio> |
| <el-radio :label="'1'">女</el-radio> |
| </el-radio-group> |
| </el-form-item> |
| </el-col> |
| </el-row> |
| <el-row> |
| <el-col :span="12" :offset="0"> |
| <el-form-item prop="username" label="账户"> |
| <el-input v-model="addModel.username"></el-input> |
| </el-form-item> |
| </el-col> |
| <el-col v-if="addModel.type == '0'" :span="12" :offset="0"> |
| <el-form-item prop="password" label="密码"> |
| <el-input v-model="addModel.password"></el-input> |
| </el-form-item> |
| </el-col> |
| </el-row> |
| </el-form> |
| </div> |
| </sys-dialog> |
| </el-main> |
| </template> |
| |
| <script> |
| import { getListApi, addUserApi, editUserApi, deleteUserApi } from "@/api/user"; |
| //引入弹框组件 |
| import SysDialog from "@/components/dialog/SysDialog.vue"; |
| export default { |
| //注册弹框组件 |
| components: { |
| SysDialog, |
| }, |
| data() { |
| return { |
| //表单验证规则 |
| rules: { |
| nickName: [ |
| { |
| trigger: "blur", |
| required: true, |
| message: "请填写姓名", |
| }, |
| ], |
| phone: [ |
| { |
| trigger: "blur", |
| required: true, |
| message: "请填写电话", |
| }, |
| ], |
| sex: [ |
| { |
| trigger: "blur", |
| required: true, |
| message: "请选择性别", |
| }, |
| ], |
| username: [ |
| { |
| trigger: "blur", |
| required: true, |
| message: "请填写账户", |
| }, |
| ], |
| password: [ |
| { |
| trigger: "blur", |
| required: true, |
| message: "请填写密码", |
| }, |
| ], |
| }, |
| //表单绑定的数据 |
| addModel: { |
| type: "", |
| userId: "", |
| nickName: "", |
| phone: "", |
| email: "", |
| sex: "", |
| username: "", |
| password: "", |
| }, |
| //弹框属性 |
| dialog: { |
| title: "", |
| visible: false, |
| width: 630, |
| height: 200, |
| }, |
| //表格的tableData: [], |
| }; |
| }, |
| created() { |
| this.getList(); |
| }, |
| methods: { |
| async getList() { |
| let res = await getListApi(this.listParm); |
| console.log("请求成功"); |
| console.log(res); |
| if (res && res.code == 200) { |
| this.tableData = res.data.records; |
| this.listParm.total = res.data.total; |
| } |
| }, |
| //弹框的leType: "", |
| remark: "", |
| }, |
| //弹框属性 |
| dialog: { |
| height: 150, |
| visible: false, |
| title: "", |
| }, |
| //表格高度 |
| tableHeight: 0, |
| //搜索栏数据 |
| listParm: { |
| roleName: "", |
| cu确定 |
| onConfirm() { |
| //表单验证 |
| this.$refs.addRef.validate(async (valid) => { |
| if (valid) { |
| let res = null; |
| if (this.addModel.type == "0") { |
| res = await addUserApi(this.addModel); |
| } else { |
| res = await editUserApi(this.addModel); |
| } |
| if (res && res.code == 200) { |
| //刷新表单 |
| this.getList(); |
| this.$message({ type: "success", message: res.msg }); |
| } |
| } |
| }); |
| }, |
| //弹框的取消 |
| onClose() { |
| this.dialog.visible = false; |
| }, |
| //页数改变时触发 |
| currentChange(val) { |
| this.listParm.currentPage = val; |
| this.getList(); |
| }, |
| //页容量改变时触发 |
| sizeChange(val) { |
| this.listParm.pageSize = val; |
| this.getList(); |
| }, |
| //编辑按钮 |
| editBtn(row) { |
| //设置弹框属性 |
| this.dialog.title = "编辑用户"; |
| this.dialog.visible = true; |
| //清空表单 |
| this.$resetForm("addRef", this.addModel); |
| //把当前要编辑的数据复制到表单数据域 |
| this.$objCoppy(row, this.addModel); |
| //设置编辑标识 |
| this.addModel.type = "1"; |
| }, |
| //删除按钮 |
| async deleteBtn(row) { |
| let confirm = await this.$myconfirm("确定删除该数据吗?"); |
| if (confirm) { |
| let res = await deleteUserApi({ userId: row.userId }); |
| if (res && res.code == 200) { |
| //刷新表单 |
| this.getList(); |
| this.$message({ type: "success", message: res.msg }); |
| } |
| } |
| }, |
| //搜索按钮 |
| searchBtn() { |
| this.getList(); |
| }, |
| //搜索按钮 |
| resetBtn() { |
| this.listParm.nickName = ""; |
| this.listParm.phone = ""; |
| this.getList(); |
| }, |
| //新增按钮 |
| addBtn() { |
| //设置弹框属性 |
| this.dialog.title = "新增用户"; |
| this.dialog.visible = true; |
| //清空表单 |
| this.$resetForm("addRef", this.addModel); |
| //设置编辑标识 |
| this.addModel.type = "0"; |
| }, |
| }, |
| mounted() { |
| this.$nextTick(() => { |
| //计算表格的高度 |
| this.tableHeight = window.innerHeight - 220; |
| }); |
| }, |
| }; |
| </script> |
| |
| <style lang="scss" scoped> |
| </style> |
复制
第19讲 角色管理模块接口开发
1、新建实体类
| package com.itmk.web.sys_role.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; |
| |
| @Data |
| @TableName("sys_role") |
| public class SysRole { |
| @TableId(type = IdType.AUTO) |
| private Long roleId; |
| private String roleName; |
| private String roleType; |
| private String remark; |
| private Date createTime; |
| private Date updateTime; |
| } |
| |
复制
列表参数接收
| package com.itmk.web.sys_role.entity; |
| |
| import lombok.Data; |
| |
| @Data |
| public class RoleParm { |
| private Long currentPage; |
| private Long pageSize; |
| private String roleName; |
| } |
| |
复制
2、新建mapper
| package com.itmk.web.sys_role.mapper; |
| |
| import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| import com.itmk.web.sys_role.entity.SysRole; |
| |
| public interface SysRoleMapper extends BaseMapper<SysRole> { |
| } |
| |
复制
映射文件
| <!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.mapper.SysRoleMapper"> |
| |
| </mapper> |
复制
3、service层
| package com.itmk.web.sys_role.service; |
| |
| import com.baomidou.mybatisplus.core.metadata.IPage; |
| import com.baomidou.mybatisplus.extension.service.IService; |
| import com.itmk.web.sys_role.entity.RoleParm; |
| import com.itmk.web.sys_role.entity.SysRole; |
| |
| public interface SysRoleService extends IService<SysRole> { |
| IPage<SysRole> list(RoleParm parm); |
| } |
| |
复制
实现类
| package com.itmk.web.sys_role.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_role.entity.RoleParm; |
| import com.itmk.web.sys_role.entity.SysRole; |
| import com.itmk.web.sys_role.mapper.SysRoleMapper; |
| import com.itmk.web.sys_role.service.SysRoleService; |
| import org.apache.commons.lang.StringUtils; |
| import org.springframework.stereotype.Service; |
| |
| @Service |
| public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService { |
| @Override |
| public IPage<SysRole> list(RoleParm parm) { |
| |
| IPage<SysRole> page = new Page<>(); |
| page.setSize(parm.getPageSize()); |
| page.setCurrent(parm.getCurrentPage()); |
| |
| QueryWrapper<SysRole> query = new QueryWrapper<>(); |
| if(StringUtils.isNotEmpty(parm.getRoleName())){ |
| query.lambda().like(SysRole::getRoleName,parm.getRoleName()); |
| } |
| return this.baseMapper.selectPage(page,query); |
| } |
| } |
| |
复制
4、控制器
| 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.RoleParm; |
| import com.itmk.web.sys_role.entity.SysRole; |
| import com.itmk.web.sys_role.service.SysRoleService; |
| 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; |
| |
| |
| @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 b = sysRoleService.removeById(roleId); |
| if(b){ |
| return ResultUtils.success("删除成功!"); |
| } |
| return ResultUtils.error("删除失败!"); |
| } |
| |
| |
| @GetMapping("/list") |
| public ResultVo getList(RoleParm parm){ |
| IPage<SysRole> list = sysRoleService.list(parm); |
| return ResultUtils.success("查询成功",list); |
| } |
| } |
| |
复制
第20讲角色管理列表制作
1、src/api新建role.js
| import http from '@/utils/http' |
| |
| export const getListApi = async(parm) =>{ |
| return await http.get("/api/role/list",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">搜索</el-button> |
| <el-button icon="el-icon-close" style="color: #ff7670">重置</el-button> |
| <el-button type="primary" 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="操作"> |
| <template slot-scope="scope"> |
| <el-button type="primary" size="small" @click="editBtn(scope.row)" |
| >编辑</el-button |
| > |
| <el-button 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="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> |
| </el-main> |
| </template> |
| |
| <script> |
| import { getListApi } from "@/api/role"; |
| export default { |
| data() { |
| return { |
| |
| tableHeight: 0, |
| |
| listParm: { |
| roleName: "", |
| currentPage: 1, |
| pageSize: 10, |
| total: 0, |
| }, |
| |
| tableData: [], |
| }; |
| }, |
| mounted() { |
| this.$nextTick(() => { |
| this.tableHeight = window.innerHeight - 220; |
| }); |
| }, |
| created() { |
| this.getList(); |
| }, |
| methods: { |
| |
| 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) {}, |
| |
| sizeChange(val) {}, |
| |
| deleteBtn(row) {}, |
| |
| editBtn(row) {}, |
| }, |
| }; |
| </script> |
| |
| <style lang="scss" scoped> |
| </style> |
| |
复制
第21讲 新增、编辑制作与对接
1、src/api/role.js添加如下方法
| |
| export const addRoleApi = async(parm) =>{ |
| return await http.post("/api/role",parm) |
| } |
| |
| export const editRoleApi = async(parm) =>{ |
| return await http.put("/api/role",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">搜索</el-button> |
| <el-button icon="el-icon-close" style="color: #ff7670">重置</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="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> |
| <!-- 分页 --> |
| <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.heightsys-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="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-rowame" 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 SysDialog from "@/components/dialog/SysDialog.vue"; |
| import { getListApi, addRoleApi, editRoleApi } from "@/api/role"; |
| export default { |
| // 注册组件 |
| components: { |
| SysDialog, |
| }, |
| data() { |
| return { |
| //角色类型 |
| 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: { |
| //新增按钮 |
| 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) {}, |
| //页容量改变时触发 |
| sizeChange(val) {}, |
| //删除按钮 |
| deleteBtn(row) {}, |
| //编辑按钮 |
| 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> |
复制
第22讲 删除、搜索功能对接
1、src/api/role.js添加如下方法
| |
| export const deleteRoleApi = async(parm) =>{ |
| return await http.delete("/api/role",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="180"> |
| <template slot-scope="scope"> |
| <el-button |
| type="primary" |
| size="small" |
| icon="el-icon-edit" |
| @click="editBtn(scope.row)" |
| >编辑</el-button |
| > |
| <el-button |
| type="danger" |
| size="small" |
| 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.heightsys-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="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> |
| </el-main> |
| </template> |
| |
| <script> |
| import SysDialog from "@/components/dialog/SysDialog.vue"; |
| import { getListApi, addRoleApi, editRoleApi, deleteRoleApi } from "@/api/role"; |
| import { getList } from "@/api/table"; |
| export default { |
| // 注册组件 |
| components: { |
| SysDialog, |
| }, |
| data() { |
| return { |
| //角色类型 |
| options: [ |
| { |
| value: "1", |
| label: "系统用户", |
| }, |
| { |
| value: "2", |
| label: "学生", |
| }, |
| e: [ |
| { |
| trigger: "blur", |
| required: true, |
| message: "请填写角色名称", |
| }, |
| ], |
| roleTyp0, |
| //表单验证规则 |
| rules: { |
| collageName: [ |
| { |
| trigger: "blur", |
| required: true, |
| message: "请选择角色类型", |
| }, |
| ], |
| }, |
| //表单数据 |
| addModel: { |
| type: "", // 0 新增 1: 编辑 |
| roleId: "", |
| roleName: "", |
| roleType: "", |
| remark: "", |
| }, |
| //弹框属性 |
| dialog: { |
| height: 150, |
| visible: false, |
| title: "", |
| }, |
| //表格的高度 |
| tableHeight: 0, |
| //表格数据 |
| tableData: [], |
| //列表参数 |
| listParm: { |
| rolageName: "", |
| currentPage: 1, |
| pageSize: 10, |
| total: 0, |
| }, |
| }; |
| }, |
| mounted() { |
| this.$nextTick(() => { |
| this.tableHeight = window.innerHeight - 220; |
| }); |
| }, |
| created() { |
| this.getList(); |
| }, |
| methods: { |
| //弹框关闭 |
| 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> |
复制
第23讲 菜单管理模块接口开发
1、新建实体类
| package com.itmk.web.sys_menu.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; |
| |
| import java.util.ArrayList; |
| import java.util.Date; |
| import java.util.List; |
| |
| @Data |
| @TableName("sys_menu") |
| public class SysMenu { |
| @TableId(type = IdType.AUTO) |
| private Long menuId; |
| private Long parentId; |
| private String title; |
| private String code; |
| private String name; |
| private String path; |
| private String url; |
| |
| private String type; |
| private String icon; |
| private String parentName; |
| private Long orderNum; |
| private Date createTime; |
| private Date updateTime; |
| |
| @TableField(exist = false) |
| private List<SysMenu> children = new ArrayList<>(); |
| } |
| |
复制
2、新建mapper
| package com.itmk.web.sys_menu.mapper; |
| |
| import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| import com.itmk.web.sys_menu.entity.SysMenu; |
| |
| public interface SysMenuMapper extends BaseMapper<SysMenu> { |
| } |
| |
复制
映射文件
| <!DOCTYPE mapper |
| PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
| "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| |
| <mapper namespace="com.itmk.web.sys_menu.mapper.SysMenuMapper"> |
| |
| </mapper> |
复制
3、新建service
| package com.itmk.web.sys_menu.service; |
| |
| import com.baomidou.mybatisplus.extension.service.IService; |
| import com.itmk.web.sys_menu.entity.SysMenu; |
| |
| import java.util.List; |
| |
| public interface SysMenuService extends IService<SysMenu> { |
| List<SysMenu> menuList(); |
| } |
| |
复制
实现类
| package com.itmk.web.sys_menu.service.impl; |
| |
| import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| import com.itmk.web.sys_menu.entity.MakeTree; |
| import com.itmk.web.sys_menu.entity.SysMenu; |
| import com.itmk.web.sys_menu.mapper.SysMenuMapper; |
| import com.itmk.web.sys_menu.service.SysMenuService; |
| import org.springframework.stereotype.Service; |
| |
| import java.util.List; |
| |
| @Service |
| public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService { |
| |
| @Override |
| public List<SysMenu> menuList() { |
| |
| QueryWrapper<SysMenu> query = new QueryWrapper<>(); |
| query.lambda().orderByAsc(SysMenu::getOrderNum); |
| List<SysMenu> menuList = this.baseMapper.selectList(query); |
| |
| List<SysMenu> list = MakeTree.makeMenuTree(menuList, 0L); |
| return list; |
| } |
| } |
| |
复制
| package com.itmk.web.sys_menu.entity; |
| |
| import org.springframework.beans.BeanUtils; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Optional; |
| |
| public class MakeTree { |
| |
| public static List<SysMenu> makeMenuTree(List<SysMenu> menuList, Long pid) { |
| List<SysMenu> list = new ArrayList<>(); |
| Optional.ofNullable(menuList).orElse(new ArrayList<>()) |
| .stream() |
| .filter(item -> item != null && item.getParentId() == pid) |
| .forEach(dom -> { |
| SysMenu menu = new SysMenu(); |
| BeanUtils.copyProperties(dom, menu); |
| |
| List<SysMenu> sysMenus = makeMenuTree(menuList, dom.getMenuId()); |
| menu.setChildren(sysMenus); |
| list.add(menu); |
| }); |
| return list; |
| } |
| } |
| |
复制
4、新建控制器
| package com.itmk.web.sys_menu.controller; |
| |
| import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| import com.itmk.utils.ResultUtils; |
| import com.itmk.utils.ResultVo; |
| import com.itmk.web.sys_menu.entity.SysMenu; |
| import com.itmk.web.sys_menu.service.SysMenuService; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.web.bind.annotation.*; |
| |
| import java.util.Date; |
| import java.util.List; |
| |
| @RestController |
| @RequestMapping("/api/menu") |
| public class SysMenuController { |
| @Autowired |
| private SysMenuService sysMenuService; |
| |
| |
| @PostMapping |
| public ResultVo addMenu(@RequestBody SysMenu menu){ |
| menu.setCreateTime(new Date()); |
| boolean save = sysMenuService.save(menu); |
| if(save){ |
| return ResultUtils.success("新增成功!"); |
| } |
| return ResultUtils.error("新增失败!"); |
| } |
| |
| |
| @PutMapping |
| public ResultVo editMenu(@RequestBody SysMenu menu){ |
| menu.setUpdateTime(new Date()); |
| boolean save = sysMenuService.updateById(menu); |
| if(save){ |
| return ResultUtils.success("编辑成功!"); |
| } |
| return ResultUtils.error("编辑失败!"); |
| } |
| |
| |
| @DeleteMapping("/{menuId}") |
| public ResultVo deleteMenu(@PathVariable("menuId") Long menuId){ |
| |
| QueryWrapper<SysMenu> query = new QueryWrapper<>(); |
| query.lambda().eq(SysMenu::getParentId,menuId); |
| List<SysMenu> list = sysMenuService.list(query); |
| if(list.size() > 0){ |
| return ResultUtils.error("该菜单存在下级,不能删除!"); |
| } |
| boolean save = sysMenuService.removeById(menuId); |
| if(save){ |
| return ResultUtils.success("删除成功!"); |
| } |
| return ResultUtils.error("删除失败!"); |
| } |
| |
| |
| public ResultVo getList(){ |
| List<SysMenu> list = sysMenuService.menuList(); |
| return ResultUtils.success("查询成功",list); |
| } |
| } |
| |
复制
点击获取
完整源代码+万字文档
点击跳转下一讲
【第24讲到第44讲】基于vue + spring boot学生宿舍管理系统











点击获取
完整源代码+万字文档