(must set!!!)
+ * meta : {
+ roles: ['admin','editor'] control the page roles (you can set multiple roles)
+ title: 'title' the name show in sidebar and breadcrumb (recommend set)
+ icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
+ breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
+ activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
+ }
+ */
+
+/**
+ * constantRoutes
+ * a base page that does not have permission requirements
+ * all roles can be accessed
+ */
+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' ,affix: true}
+ }]
+ },
+ {
+ path: '/',
+ component: Layout,
+ redirect: '/',
+ children: [{
+ path: 'workbench',
+ name: 'workbench',
+ component: () => import('@/views/workbench/workbench'),
+ meta: { title: '个人工作台', icon: 'dashboard' ,affix: true}
+ }]
+ },
+
+ {
+ path: '/',
+ component: Layout,
+ redirect: '/equipment',
+ children: [{
+ path: 'equipment',
+ name: 'Dashboard',
+ component: () => import('@/views/equipment/equilist'),
+ meta: { title: '设备列表', icon: 'dashboard' ,affix: true}
+ }]
+ },
+ {
+ path: '/',
+ component: Layout,
+ redirect: '/task',
+ children: [{
+ path: 'task',
+ name: 'task',
+ component: () => import('@/views/task/task'),
+ meta: { title: '数据查询', icon: 'dashboard' ,affix: true}
+ }]
+ },
+ {
+ path: '/',
+ component: Layout,
+ redirect: '/task',
+ children: [{
+ path: 'task',
+ name: 'task',
+ component: () => import('@/views/task/task'),
+ meta: { title: '审计日志', icon: 'dashboard' ,affix: true}
+ }]
+ },
+
+
+]
+
+const createRouter = () => new Router({
+ // mode: 'history', // require service support
+ scrollBehavior: () => ({ y: 0 }),
+ routes: constantRoutes
+})
+
+const router = createRouter()
+
+// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
+export function resetRouter() {
+ const newRouter = createRouter()
+ router.matcher = newRouter.matcher // reset router
+}
+
+export default router
diff --git a/x-admin-web/src/settings.js b/x-admin-web/src/settings.js
new file mode 100644
index 0000000..1fecd1a
--- /dev/null
+++ b/x-admin-web/src/settings.js
@@ -0,0 +1,16 @@
+module.exports = {
+
+ title: '智能动作采集平台',
+
+ /**
+ * @type {boolean} true | false
+ * @description Whether fix the header
+ */
+ fixedHeader: false,
+
+ /**
+ * @type {boolean} true | false
+ * @description Whether show the logo in sidebar
+ */
+ sidebarLogo: false
+}
diff --git a/x-admin-web/src/store/getters.js b/x-admin-web/src/store/getters.js
new file mode 100644
index 0000000..8f07c7a
--- /dev/null
+++ b/x-admin-web/src/store/getters.js
@@ -0,0 +1,13 @@
+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,
+ menuList: state => state.user.menuList,
+
+ visitedViews: state => state.tagsView.visitedViews,
+ cachedViews: state => state.tagsView.cachedViews,
+ permission_routes: state => state.permission.routes
+}
+export default getters
diff --git a/x-admin-web/src/store/index.js b/x-admin-web/src/store/index.js
new file mode 100644
index 0000000..bf429a5
--- /dev/null
+++ b/x-admin-web/src/store/index.js
@@ -0,0 +1,21 @@
+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
diff --git a/x-admin-web/src/store/modules/app.js b/x-admin-web/src/store/modules/app.js
new file mode 100644
index 0000000..7ea7e33
--- /dev/null
+++ b/x-admin-web/src/store/modules/app.js
@@ -0,0 +1,48 @@
+import Cookies from 'js-cookie'
+
+const state = {
+ sidebar: {
+ opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
+ withoutAnimation: false
+ },
+ device: 'desktop'
+}
+
+const mutations = {
+ TOGGLE_SIDEBAR: state => {
+ state.sidebar.opened = !state.sidebar.opened
+ state.sidebar.withoutAnimation = false
+ if (state.sidebar.opened) {
+ Cookies.set('sidebarStatus', 1)
+ } else {
+ Cookies.set('sidebarStatus', 0)
+ }
+ },
+ CLOSE_SIDEBAR: (state, withoutAnimation) => {
+ Cookies.set('sidebarStatus', 0)
+ state.sidebar.opened = false
+ state.sidebar.withoutAnimation = withoutAnimation
+ },
+ TOGGLE_DEVICE: (state, device) => {
+ state.device = device
+ }
+}
+
+const actions = {
+ toggleSideBar({ commit }) {
+ commit('TOGGLE_SIDEBAR')
+ },
+ closeSideBar({ commit }, { withoutAnimation }) {
+ commit('CLOSE_SIDEBAR', withoutAnimation)
+ },
+ toggleDevice({ commit }, device) {
+ commit('TOGGLE_DEVICE', device)
+ }
+}
+
+export default {
+ namespaced: true,
+ state,
+ mutations,
+ actions
+}
diff --git a/x-admin-web/src/store/modules/permission.js b/x-admin-web/src/store/modules/permission.js
new file mode 100644
index 0000000..aeb5ee5
--- /dev/null
+++ b/x-admin-web/src/store/modules/permission.js
@@ -0,0 +1,69 @@
+import { asyncRoutes, constantRoutes } from '@/router'
+
+/**
+ * Use meta.role to determine if the current user has permission
+ * @param roles
+ * @param route
+ */
+function hasPermission(roles, route) {
+ if (route.meta && route.meta.roles) {
+ return roles.some(role => route.meta.roles.includes(role))
+ } else {
+ return true
+ }
+}
+
+/**
+ * Filter asynchronous routing tables by recursion
+ * @param routes asyncRoutes
+ * @param roles
+ */
+export function filterAsyncRoutes(routes, roles) {
+ const res = []
+
+ routes.forEach(route => {
+ const tmp = { ...route }
+ if (hasPermission(roles, tmp)) {
+ if (tmp.children) {
+ tmp.children = filterAsyncRoutes(tmp.children, roles)
+ }
+ res.push(tmp)
+ }
+ })
+
+ return res
+}
+
+const state = {
+ routes: [],
+ addRoutes: []
+}
+
+const mutations = {
+ SET_ROUTES: (state, routes) => {
+ state.addRoutes = routes
+ state.routes = constantRoutes.concat(routes)
+ }
+}
+
+const actions = {
+ generateRoutes({ commit }, roles) {
+ return new Promise(resolve => {
+ let accessedRoutes
+ if (roles.includes('admin')) {
+ accessedRoutes = asyncRoutes || []
+ } else {
+ accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
+ }
+ commit('SET_ROUTES', accessedRoutes)
+ resolve(accessedRoutes)
+ })
+ }
+}
+
+export default {
+ namespaced: true,
+ state,
+ mutations,
+ actions
+}
diff --git a/x-admin-web/src/store/modules/settings.js b/x-admin-web/src/store/modules/settings.js
new file mode 100644
index 0000000..b3f33f8
--- /dev/null
+++ b/x-admin-web/src/store/modules/settings.js
@@ -0,0 +1,32 @@
+import defaultSettings from '@/settings'
+
+const { showSettings, fixedHeader, sidebarLogo } = defaultSettings
+
+const state = {
+ showSettings: showSettings,
+ fixedHeader: fixedHeader,
+ sidebarLogo: sidebarLogo
+}
+
+const mutations = {
+ CHANGE_SETTING: (state, { key, value }) => {
+ // eslint-disable-next-line no-prototype-builtins
+ if (state.hasOwnProperty(key)) {
+ state[key] = value
+ }
+ }
+}
+
+const actions = {
+ changeSetting({ commit }, data) {
+ commit('CHANGE_SETTING', data)
+ }
+}
+
+export default {
+ namespaced: true,
+ state,
+ mutations,
+ actions
+}
+
diff --git a/x-admin-web/src/store/modules/tagsView.js b/x-admin-web/src/store/modules/tagsView.js
new file mode 100644
index 0000000..57e7242
--- /dev/null
+++ b/x-admin-web/src/store/modules/tagsView.js
@@ -0,0 +1,160 @@
+const state = {
+ visitedViews: [],
+ cachedViews: []
+}
+
+const mutations = {
+ ADD_VISITED_VIEW: (state, view) => {
+ if (state.visitedViews.some(v => v.path === view.path)) return
+ state.visitedViews.push(
+ Object.assign({}, view, {
+ title: view.meta.title || 'no-name'
+ })
+ )
+ },
+ ADD_CACHED_VIEW: (state, view) => {
+ if (state.cachedViews.includes(view.name)) return
+ if (!view.meta.noCache) {
+ state.cachedViews.push(view.name)
+ }
+ },
+
+ DEL_VISITED_VIEW: (state, view) => {
+ for (const [i, v] of state.visitedViews.entries()) {
+ if (v.path === view.path) {
+ state.visitedViews.splice(i, 1)
+ break
+ }
+ }
+ },
+ DEL_CACHED_VIEW: (state, view) => {
+ const index = state.cachedViews.indexOf(view.name)
+ index > -1 && state.cachedViews.splice(index, 1)
+ },
+
+ DEL_OTHERS_VISITED_VIEWS: (state, view) => {
+ state.visitedViews = state.visitedViews.filter(v => {
+ return v.meta.affix || v.path === view.path
+ })
+ },
+ DEL_OTHERS_CACHED_VIEWS: (state, view) => {
+ const index = state.cachedViews.indexOf(view.name)
+ if (index > -1) {
+ state.cachedViews = state.cachedViews.slice(index, index + 1)
+ } else {
+ // if index = -1, there is no cached tags
+ state.cachedViews = []
+ }
+ },
+
+ DEL_ALL_VISITED_VIEWS: state => {
+ // keep affix tags
+ const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
+ state.visitedViews = affixTags
+ },
+ DEL_ALL_CACHED_VIEWS: state => {
+ state.cachedViews = []
+ },
+
+ UPDATE_VISITED_VIEW: (state, view) => {
+ for (let v of state.visitedViews) {
+ if (v.path === view.path) {
+ v = Object.assign(v, view)
+ break
+ }
+ }
+ }
+}
+
+const actions = {
+ addView({ dispatch }, view) {
+ dispatch('addVisitedView', view)
+ dispatch('addCachedView', view)
+ },
+ addVisitedView({ commit }, view) {
+ commit('ADD_VISITED_VIEW', view)
+ },
+ addCachedView({ commit }, view) {
+ commit('ADD_CACHED_VIEW', view)
+ },
+
+ delView({ dispatch, state }, view) {
+ return new Promise(resolve => {
+ dispatch('delVisitedView', view)
+ dispatch('delCachedView', view)
+ resolve({
+ visitedViews: [...state.visitedViews],
+ cachedViews: [...state.cachedViews]
+ })
+ })
+ },
+ delVisitedView({ commit, state }, view) {
+ return new Promise(resolve => {
+ commit('DEL_VISITED_VIEW', view)
+ resolve([...state.visitedViews])
+ })
+ },
+ delCachedView({ commit, state }, view) {
+ return new Promise(resolve => {
+ commit('DEL_CACHED_VIEW', view)
+ resolve([...state.cachedViews])
+ })
+ },
+
+ delOthersViews({ dispatch, state }, view) {
+ return new Promise(resolve => {
+ dispatch('delOthersVisitedViews', view)
+ dispatch('delOthersCachedViews', view)
+ resolve({
+ visitedViews: [...state.visitedViews],
+ cachedViews: [...state.cachedViews]
+ })
+ })
+ },
+ delOthersVisitedViews({ commit, state }, view) {
+ return new Promise(resolve => {
+ commit('DEL_OTHERS_VISITED_VIEWS', view)
+ resolve([...state.visitedViews])
+ })
+ },
+ delOthersCachedViews({ commit, state }, view) {
+ return new Promise(resolve => {
+ commit('DEL_OTHERS_CACHED_VIEWS', view)
+ resolve([...state.cachedViews])
+ })
+ },
+
+ delAllViews({ dispatch, state }, view) {
+ return new Promise(resolve => {
+ dispatch('delAllVisitedViews', view)
+ dispatch('delAllCachedViews', view)
+ resolve({
+ visitedViews: [...state.visitedViews],
+ cachedViews: [...state.cachedViews]
+ })
+ })
+ },
+ delAllVisitedViews({ commit, state }) {
+ return new Promise(resolve => {
+ commit('DEL_ALL_VISITED_VIEWS')
+ resolve([...state.visitedViews])
+ })
+ },
+ delAllCachedViews({ commit, state }) {
+ return new Promise(resolve => {
+ commit('DEL_ALL_CACHED_VIEWS')
+ resolve([...state.cachedViews])
+ })
+ },
+
+ updateVisitedView({ commit }, view) {
+ commit('UPDATE_VISITED_VIEW', view)
+ }
+}
+
+export default {
+ namespaced: true,
+ state,
+ mutations,
+ actions
+}
diff --git a/x-admin-web/src/store/modules/user.js b/x-admin-web/src/store/modules/user.js
new file mode 100644
index 0000000..110ad6a
--- /dev/null
+++ b/x-admin-web/src/store/modules/user.js
@@ -0,0 +1,102 @@
+import { login, logout, getInfo } from '@/api/user'
+import { getToken, setToken, removeToken } from '@/utils/auth'
+import { resetRouter } from '@/router'
+
+const getDefaultState = () => {
+ return {
+ token: getToken(),
+ name: '',
+ avatar: '',
+ menuList: []
+ }
+}
+
+const state = getDefaultState()
+
+const mutations = {
+ RESET_STATE: (state) => {
+ Object.assign(state, getDefaultState())
+ },
+ SET_TOKEN: (state, token) => {
+ state.token = token
+ },
+ SET_NAME: (state, name) => {
+ state.name = name
+ },
+ SET_AVATAR: (state, avatar) => {
+ state.avatar = avatar
+ },
+ SET_MENU_LIST: (state, menuList) => {
+ state.menuList = menuList
+ }
+}
+
+const actions = {
+ // user login
+ login({ commit }, userInfo) {
+ const { username, password } = userInfo
+ return new Promise((resolve, reject) => {
+ login({ username: username.trim(), password: password }).then(response => {
+ const { data } = response
+ commit('SET_TOKEN', data.token)
+ setToken(data.token)
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // get user info
+ getInfo({ commit, state }) {
+ return new Promise((resolve, reject) => {
+ getInfo(state.token).then(response => {
+ const { data } = response
+
+ if (!data) {
+ reject('Verification failed, please Login again.')
+ }
+
+ const { name, avatar, menuList } = data
+
+ commit('SET_NAME', name)
+ commit('SET_AVATAR', avatar)
+ commit('SET_MENU_LIST', menuList)
+ resolve(data)
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // user logout
+ logout({ commit, state }) {
+ return new Promise((resolve, reject) => {
+ logout(state.token).then(() => {
+ removeToken() // must remove token first
+ resetRouter()
+ commit('RESET_STATE')
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // remove token
+ resetToken({ commit }) {
+ return new Promise(resolve => {
+ removeToken() // must remove token first
+ commit('RESET_STATE')
+ resolve()
+ })
+ }
+}
+
+export default {
+ namespaced: true,
+ state,
+ mutations,
+ actions
+}
+
diff --git a/x-admin-web/src/styles/element-ui.scss b/x-admin-web/src/styles/element-ui.scss
new file mode 100644
index 0000000..0062411
--- /dev/null
+++ b/x-admin-web/src/styles/element-ui.scss
@@ -0,0 +1,49 @@
+// cover some element-ui styles
+
+.el-breadcrumb__inner,
+.el-breadcrumb__inner a {
+ font-weight: 400 !important;
+}
+
+.el-upload {
+ input[type="file"] {
+ display: none !important;
+ }
+}
+
+.el-upload__input {
+ display: none;
+}
+
+
+// to fixed https://github.com/ElemeFE/element/issues/2461
+.el-dialog {
+ transform: none;
+ left: 0;
+ position: relative;
+ margin: 0 auto;
+}
+
+// refine element ui upload
+.upload-container {
+ .el-upload {
+ width: 100%;
+
+ .el-upload-dragger {
+ width: 100%;
+ height: 200px;
+ }
+ }
+}
+
+// dropdown
+.el-dropdown-menu {
+ a {
+ display: block
+ }
+}
+
+// to fix el-date-picker css style
+.el-range-separator {
+ box-sizing: content-box;
+}
diff --git a/x-admin-web/src/styles/index.scss b/x-admin-web/src/styles/index.scss
new file mode 100644
index 0000000..3b4da51
--- /dev/null
+++ b/x-admin-web/src/styles/index.scss
@@ -0,0 +1,65 @@
+@import './variables.scss';
+@import './mixin.scss';
+@import './transition.scss';
+@import './element-ui.scss';
+@import './sidebar.scss';
+
+body {
+ height: 100%;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+ font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
+}
+
+label {
+ font-weight: 700;
+}
+
+html {
+ height: 100%;
+ box-sizing: border-box;
+}
+
+#app {
+ height: 100%;
+}
+
+*,
+*:before,
+*:after {
+ box-sizing: inherit;
+}
+
+a:focus,
+a:active {
+ outline: none;
+}
+
+a,
+a:focus,
+a:hover {
+ cursor: pointer;
+ color: inherit;
+ text-decoration: none;
+}
+
+div:focus {
+ outline: none;
+}
+
+.clearfix {
+ &:after {
+ visibility: hidden;
+ display: block;
+ font-size: 0;
+ content: " ";
+ clear: both;
+ height: 0;
+ }
+}
+
+// main-container global css
+.app-container {
+ padding: 20px;
+}
diff --git a/x-admin-web/src/styles/mixin.scss b/x-admin-web/src/styles/mixin.scss
new file mode 100644
index 0000000..36b74bb
--- /dev/null
+++ b/x-admin-web/src/styles/mixin.scss
@@ -0,0 +1,28 @@
+@mixin clearfix {
+ &:after {
+ content: "";
+ display: table;
+ clear: both;
+ }
+}
+
+@mixin scrollBar {
+ &::-webkit-scrollbar-track-piece {
+ background: #d3dce6;
+ }
+
+ &::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: #99a9bf;
+ border-radius: 20px;
+ }
+}
+
+@mixin relative {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
diff --git a/x-admin-web/src/styles/sidebar.scss b/x-admin-web/src/styles/sidebar.scss
new file mode 100644
index 0000000..94760cc
--- /dev/null
+++ b/x-admin-web/src/styles/sidebar.scss
@@ -0,0 +1,226 @@
+#app {
+
+ .main-container {
+ min-height: 100%;
+ transition: margin-left .28s;
+ margin-left: $sideBarWidth;
+ position: relative;
+ }
+
+ .sidebar-container {
+ transition: width 0.28s;
+ width: $sideBarWidth !important;
+ background-color: $menuBg;
+ height: 100%;
+ position: fixed;
+ font-size: 0px;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1001;
+ overflow: hidden;
+
+ // reset element-ui css
+ .horizontal-collapse-transition {
+ transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
+ }
+
+ .scrollbar-wrapper {
+ overflow-x: hidden !important;
+ }
+
+ .el-scrollbar__bar.is-vertical {
+ right: 0px;
+ }
+
+ .el-scrollbar {
+ height: 100%;
+ }
+
+ &.has-logo {
+ .el-scrollbar {
+ height: calc(100% - 50px);
+ }
+ }
+
+ .is-horizontal {
+ display: none;
+ }
+
+ a {
+ display: inline-block;
+ width: 100%;
+ overflow: hidden;
+ }
+
+ .svg-icon {
+ margin-right: 16px;
+ }
+
+ .sub-el-icon {
+ margin-right: 12px;
+ margin-left: -2px;
+ }
+
+ .el-menu {
+ border: none;
+ height: 100%;
+ width: 100% !important;
+ }
+
+ // menu hover
+ .submenu-title-noDropdown,
+ .el-submenu__title {
+ &:hover {
+ background-color: $menuHover !important;
+ }
+ }
+
+ .is-active>.el-submenu__title {
+ color: $subMenuActiveText !important;
+ }
+
+ & .nest-menu .el-submenu>.el-submenu__title,
+ & .el-submenu .el-menu-item {
+ min-width: $sideBarWidth !important;
+ background-color: $subMenuBg !important;
+
+ &:hover {
+ background-color: $subMenuHover !important;
+ }
+ }
+ }
+
+ .hideSidebar {
+ .sidebar-container {
+ width: 54px !important;
+ }
+
+ .main-container {
+ margin-left: 54px;
+ }
+
+ .submenu-title-noDropdown {
+ padding: 0 !important;
+ position: relative;
+
+ .el-tooltip {
+ padding: 0 !important;
+
+ .svg-icon {
+ margin-left: 20px;
+ }
+
+ .sub-el-icon {
+ margin-left: 19px;
+ }
+ }
+ }
+
+ .el-submenu {
+ overflow: hidden;
+
+ &>.el-submenu__title {
+ padding: 0 !important;
+
+ .svg-icon {
+ margin-left: 20px;
+ }
+
+ .sub-el-icon {
+ margin-left: 19px;
+ }
+
+ .el-submenu__icon-arrow {
+ display: none;
+ }
+ }
+ }
+
+ .el-menu--collapse {
+ .el-submenu {
+ &>.el-submenu__title {
+ &>span {
+ height: 0;
+ width: 0;
+ overflow: hidden;
+ visibility: hidden;
+ display: inline-block;
+ }
+ }
+ }
+ }
+ }
+
+ .el-menu--collapse .el-menu .el-submenu {
+ min-width: $sideBarWidth !important;
+ }
+
+ // mobile responsive
+ .mobile {
+ .main-container {
+ margin-left: 0px;
+ }
+
+ .sidebar-container {
+ transition: transform .28s;
+ width: $sideBarWidth !important;
+ }
+
+ &.hideSidebar {
+ .sidebar-container {
+ pointer-events: none;
+ transition-duration: 0.3s;
+ transform: translate3d(-$sideBarWidth, 0, 0);
+ }
+ }
+ }
+
+ .withoutAnimation {
+
+ .main-container,
+ .sidebar-container {
+ transition: none;
+ }
+ }
+}
+
+// when menu collapsed
+.el-menu--vertical {
+ &>.el-menu {
+ .svg-icon {
+ margin-right: 16px;
+ }
+ .sub-el-icon {
+ margin-right: 12px;
+ margin-left: -2px;
+ }
+ }
+
+ .nest-menu .el-submenu>.el-submenu__title,
+ .el-menu-item {
+ &:hover {
+ // you can use $subMenuHover
+ background-color: $menuHover !important;
+ }
+ }
+
+ // the scroll bar appears when the subMenu is too long
+ >.el-menu--popup {
+ max-height: 100vh;
+ overflow-y: auto;
+
+ &::-webkit-scrollbar-track-piece {
+ background: #d3dce6;
+ }
+
+ &::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: #99a9bf;
+ border-radius: 20px;
+ }
+ }
+}
diff --git a/x-admin-web/src/styles/transition.scss b/x-admin-web/src/styles/transition.scss
new file mode 100644
index 0000000..4cb27cc
--- /dev/null
+++ b/x-admin-web/src/styles/transition.scss
@@ -0,0 +1,48 @@
+// global transition css
+
+/* fade */
+.fade-enter-active,
+.fade-leave-active {
+ transition: opacity 0.28s;
+}
+
+.fade-enter,
+.fade-leave-active {
+ opacity: 0;
+}
+
+/* fade-transform */
+.fade-transform-leave-active,
+.fade-transform-enter-active {
+ transition: all .5s;
+}
+
+.fade-transform-enter {
+ opacity: 0;
+ transform: translateX(-30px);
+}
+
+.fade-transform-leave-to {
+ opacity: 0;
+ transform: translateX(30px);
+}
+
+/* breadcrumb transition */
+.breadcrumb-enter-active,
+.breadcrumb-leave-active {
+ transition: all .5s;
+}
+
+.breadcrumb-enter,
+.breadcrumb-leave-active {
+ opacity: 0;
+ transform: translateX(20px);
+}
+
+.breadcrumb-move {
+ transition: all .5s;
+}
+
+.breadcrumb-leave-active {
+ position: absolute;
+}
diff --git a/x-admin-web/src/styles/variables.scss b/x-admin-web/src/styles/variables.scss
new file mode 100644
index 0000000..be55772
--- /dev/null
+++ b/x-admin-web/src/styles/variables.scss
@@ -0,0 +1,25 @@
+// sidebar
+$menuText:#bfcbd9;
+$menuActiveText:#409EFF;
+$subMenuActiveText:#f4f4f5; //https://github.com/ElemeFE/element/issues/12951
+
+$menuBg:#304156;
+$menuHover:#263445;
+
+$subMenuBg:#1f2d3d;
+$subMenuHover:#001528;
+
+$sideBarWidth: 210px;
+
+// the :export directive is the magic sauce for webpack
+// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
+:export {
+ menuText: $menuText;
+ menuActiveText: $menuActiveText;
+ subMenuActiveText: $subMenuActiveText;
+ menuBg: $menuBg;
+ menuHover: $menuHover;
+ subMenuBg: $subMenuBg;
+ subMenuHover: $subMenuHover;
+ sideBarWidth: $sideBarWidth;
+}
diff --git a/x-admin-web/src/utils/auth.js b/x-admin-web/src/utils/auth.js
new file mode 100644
index 0000000..059af18
--- /dev/null
+++ b/x-admin-web/src/utils/auth.js
@@ -0,0 +1,15 @@
+import Cookies from 'js-cookie'
+
+const TokenKey = 'vue_admin_template_token'
+
+export function getToken() {
+ return Cookies.get(TokenKey)
+}
+
+export function setToken(token) {
+ return Cookies.set(TokenKey, token)
+}
+
+export function removeToken() {
+ return Cookies.remove(TokenKey)
+}
diff --git a/x-admin-web/src/utils/get-page-title.js b/x-admin-web/src/utils/get-page-title.js
new file mode 100644
index 0000000..64be362
--- /dev/null
+++ b/x-admin-web/src/utils/get-page-title.js
@@ -0,0 +1,10 @@
+import defaultSettings from '@/settings'
+
+const title = defaultSettings.title
+
+export default function getPageTitle(pageTitle) {
+ if (pageTitle) {
+ return `${pageTitle} - ${title}`
+ }
+ return `${title}`
+}
diff --git a/x-admin-web/src/utils/index.js b/x-admin-web/src/utils/index.js
new file mode 100644
index 0000000..4830c04
--- /dev/null
+++ b/x-admin-web/src/utils/index.js
@@ -0,0 +1,117 @@
+/**
+ * Created by PanJiaChen on 16/11/18.
+ */
+
+/**
+ * Parse the time to string
+ * @param {(Object|string|number)} time
+ * @param {string} cFormat
+ * @returns {string | null}
+ */
+export function parseTime(time, cFormat) {
+ if (arguments.length === 0 || !time) {
+ return null
+ }
+ const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
+ let date
+ if (typeof time === 'object') {
+ date = time
+ } else {
+ if ((typeof time === 'string')) {
+ if ((/^[0-9]+$/.test(time))) {
+ // support "1548221490638"
+ time = parseInt(time)
+ } else {
+ // support safari
+ // https://stackoverflow.com/questions/4310953/invalid-date-in-safari
+ time = time.replace(new RegExp(/-/gm), '/')
+ }
+ }
+
+ if ((typeof time === 'number') && (time.toString().length === 10)) {
+ time = time * 1000
+ }
+ date = new Date(time)
+ }
+ const formatObj = {
+ y: date.getFullYear(),
+ m: date.getMonth() + 1,
+ d: date.getDate(),
+ h: date.getHours(),
+ i: date.getMinutes(),
+ s: date.getSeconds(),
+ a: date.getDay()
+ }
+ const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
+ const value = formatObj[key]
+ // Note: getDay() returns 0 on Sunday
+ if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
+ return value.toString().padStart(2, '0')
+ })
+ return time_str
+}
+
+/**
+ * @param {number} time
+ * @param {string} option
+ * @returns {string}
+ */
+export function formatTime(time, option) {
+ if (('' + time).length === 10) {
+ time = parseInt(time) * 1000
+ } else {
+ time = +time
+ }
+ const d = new Date(time)
+ const now = Date.now()
+
+ const diff = (now - d) / 1000
+
+ if (diff < 30) {
+ return '刚刚'
+ } else if (diff < 3600) {
+ // less 1 hour
+ return Math.ceil(diff / 60) + '分钟前'
+ } else if (diff < 3600 * 24) {
+ return Math.ceil(diff / 3600) + '小时前'
+ } else if (diff < 3600 * 24 * 2) {
+ return '1天前'
+ }
+ if (option) {
+ return parseTime(time, option)
+ } else {
+ return (
+ d.getMonth() +
+ 1 +
+ '月' +
+ d.getDate() +
+ '日' +
+ d.getHours() +
+ '时' +
+ d.getMinutes() +
+ '分'
+ )
+ }
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function param2Obj(url) {
+ const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
+ if (!search) {
+ return {}
+ }
+ const obj = {}
+ const searchArr = search.split('&')
+ searchArr.forEach(v => {
+ const index = v.indexOf('=')
+ if (index !== -1) {
+ const name = v.substring(0, index)
+ const val = v.substring(index + 1, v.length)
+ obj[name] = val
+ }
+ })
+ return obj
+}
diff --git a/x-admin-web/src/utils/request.js b/x-admin-web/src/utils/request.js
new file mode 100644
index 0000000..2fb95ac
--- /dev/null
+++ b/x-admin-web/src/utils/request.js
@@ -0,0 +1,85 @@
+import axios from 'axios'
+import { MessageBox, Message } from 'element-ui'
+import store from '@/store'
+import { getToken } from '@/utils/auth'
+
+// create an axios instance
+const service = axios.create({
+ baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
+ // withCredentials: true, // send cookies when cross-domain requests
+ timeout: 5000 // request timeout
+})
+
+// request interceptor
+service.interceptors.request.use(
+ config => {
+ // do something before request is sent
+
+ if (store.getters.token) {
+ // let each request carry token
+ // ['X-Token'] is a custom headers key
+ // please modify it according to the actual situation
+ config.headers['X-Token'] = getToken()
+ }
+ return config
+ },
+ error => {
+ // do something with request error
+ console.log(error) // for debug
+ return Promise.reject(error)
+ }
+)
+
+// response interceptor
+service.interceptors.response.use(
+ /**
+ * If you want to get http information such as headers or status
+ * Please return response => response
+ */
+
+ /**
+ * Determine the request status by custom code
+ * Here is just an example
+ * You can also judge the status by HTTP Status Code
+ */
+ response => {
+ const res = response.data
+
+ // if the custom code is not 20000, it is judged as an error.
+ if (res.code !== 20000) {
+ Message({
+ message: res.message || 'Error',
+ type: 'error',
+ duration: 5 * 1000
+ })
+
+ // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
+ if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
+ // to re-login
+ MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
+ confirmButtonText: 'Re-Login',
+ cancelButtonText: 'Cancel',
+ type: 'warning'
+ }).then(() => {
+ store.dispatch('user/resetToken').then(() => {
+ location.reload()
+ })
+ })
+ }
+ return Promise.reject(new Error(res.message || 'Error'))
+ } else {
+ return res
+ }
+ },
+ error => {
+ console.log('err' + error) // for debug
+ Message({
+ message: error.message,
+ type: 'error',
+ duration: 5 * 1000
+ })
+ return Promise.reject(error)
+ }
+)
+
+export default service
diff --git a/x-admin-web/src/utils/validate.js b/x-admin-web/src/utils/validate.js
new file mode 100644
index 0000000..0c7f643
--- /dev/null
+++ b/x-admin-web/src/utils/validate.js
@@ -0,0 +1,21 @@
+/**
+ * Created by PanJiaChen on 16/11/18.
+ */
+
+/**
+ * @param {string} path
+ * @returns {Boolean}
+ */
+export function isExternal(path) {
+ return /^(https?:|mailto:|tel:)/.test(path)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validUsername(str) {
+ // const valid_map = ['admin', 'editor']
+ // return valid_map.indexOf(str.trim()) >= 0
+ return true;
+}
diff --git a/x-admin-web/src/views/404.vue b/x-admin-web/src/views/404.vue
new file mode 100644
index 0000000..1791f55
--- /dev/null
+++ b/x-admin-web/src/views/404.vue
@@ -0,0 +1,228 @@
+
+
+
+
+
+
OOPS!
+
+
{{ message }}
+
Please check that the URL you entered is correct, or click the button below to return to the homepage.
+
Back to home
+
+
+
+
+
+
+
+
diff --git a/x-admin-web/src/views/dashboard/index.vue b/x-admin-web/src/views/dashboard/index.vue
new file mode 100644
index 0000000..f468272
--- /dev/null
+++ b/x-admin-web/src/views/dashboard/index.vue
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/x-admin-web/src/views/equipment/equilist.vue b/x-admin-web/src/views/equipment/equilist.vue
new file mode 100644
index 0000000..c03bc91
--- /dev/null
+++ b/x-admin-web/src/views/equipment/equilist.vue
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+
+
+ 查询
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ (searchModel.pageNo - 1) * searchModel.pageSize + scope.$index + 1
+ }}
+
+
+
+
+
+
+
+
+ 可用
+ 不可用
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/x-admin-web/src/views/form/index.vue b/x-admin-web/src/views/form/index.vue
new file mode 100644
index 0000000..f4d66d3
--- /dev/null
+++ b/x-admin-web/src/views/form/index.vue
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+ Cancel
+
+
+
+
+
+
+
+
+
diff --git a/x-admin-web/src/views/login/index.vue b/x-admin-web/src/views/login/index.vue
new file mode 100644
index 0000000..b88280f
--- /dev/null
+++ b/x-admin-web/src/views/login/index.vue
@@ -0,0 +1,241 @@
+
+
+
+
+
+
欢迎使用智能动作采集平台
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 登 录
+
+
+
+
+
+
+
+
+
+
diff --git a/x-admin-web/src/views/nested/menu1/index.vue b/x-admin-web/src/views/nested/menu1/index.vue
new file mode 100644
index 0000000..30cb670
--- /dev/null
+++ b/x-admin-web/src/views/nested/menu1/index.vue
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/x-admin-web/src/views/nested/menu1/menu1-1/index.vue b/x-admin-web/src/views/nested/menu1/menu1-1/index.vue
new file mode 100644
index 0000000..27e173a
--- /dev/null
+++ b/x-admin-web/src/views/nested/menu1/menu1-1/index.vue
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/x-admin-web/src/views/nested/menu1/menu1-2/index.vue b/x-admin-web/src/views/nested/menu1/menu1-2/index.vue
new file mode 100644
index 0000000..0c86276
--- /dev/null
+++ b/x-admin-web/src/views/nested/menu1/menu1-2/index.vue
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/x-admin-web/src/views/nested/menu1/menu1-2/menu1-2-1/index.vue b/x-admin-web/src/views/nested/menu1/menu1-2/menu1-2-1/index.vue
new file mode 100644
index 0000000..f87d88f
--- /dev/null
+++ b/x-admin-web/src/views/nested/menu1/menu1-2/menu1-2-1/index.vue
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/x-admin-web/src/views/nested/menu1/menu1-2/menu1-2-2/index.vue b/x-admin-web/src/views/nested/menu1/menu1-2/menu1-2-2/index.vue
new file mode 100644
index 0000000..d88789f
--- /dev/null
+++ b/x-admin-web/src/views/nested/menu1/menu1-2/menu1-2-2/index.vue
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/x-admin-web/src/views/nested/menu1/menu1-3/index.vue b/x-admin-web/src/views/nested/menu1/menu1-3/index.vue
new file mode 100644
index 0000000..f7cd073
--- /dev/null
+++ b/x-admin-web/src/views/nested/menu1/menu1-3/index.vue
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/x-admin-web/src/views/nested/menu2/index.vue b/x-admin-web/src/views/nested/menu2/index.vue
new file mode 100644
index 0000000..19dd48f
--- /dev/null
+++ b/x-admin-web/src/views/nested/menu2/index.vue
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/x-admin-web/src/views/sys/role.vue b/x-admin-web/src/views/sys/role.vue
new file mode 100644
index 0000000..8f5a47f
--- /dev/null
+++ b/x-admin-web/src/views/sys/role.vue
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
+ 查询
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ (searchModel.pageNo - 1) * searchModel.pageSize + scope.$index + 1
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/x-admin-web/src/views/sys/user.vue b/x-admin-web/src/views/sys/user.vue
new file mode 100644
index 0000000..8d9dcf9
--- /dev/null
+++ b/x-admin-web/src/views/sys/user.vue
@@ -0,0 +1,294 @@
+
+
+
+
+
+
+
+
+ 查询
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ (searchModel.pageNo - 1) * searchModel.pageSize + scope.$index + 1
+ }}
+
+
+
+
+
+
+
+
+
+
+ 正常
+ 禁用
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{role.roleDesc}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/x-admin-web/src/views/table/index.vue b/x-admin-web/src/views/table/index.vue
new file mode 100644
index 0000000..a1ed847
--- /dev/null
+++ b/x-admin-web/src/views/table/index.vue
@@ -0,0 +1,79 @@
+
+
+
+
+
+ {{ scope.$index }}
+
+
+
+
+ {{ scope.row.title }}
+
+
+
+
+ {{ scope.row.author }}
+
+
+
+
+ {{ scope.row.pageviews }}
+
+
+
+
+ {{ scope.row.status }}
+
+
+
+
+
+ {{ scope.row.display_time }}
+
+
+
+
+
+
+
diff --git a/x-admin-web/src/views/task/task.vue b/x-admin-web/src/views/task/task.vue
new file mode 100644
index 0000000..fc48093
--- /dev/null
+++ b/x-admin-web/src/views/task/task.vue
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+ 查询
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 公开
+ 保密
+
+
+
+ l
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/x-admin-web/src/views/test/test1.vue b/x-admin-web/src/views/test/test1.vue
new file mode 100644
index 0000000..6ed0d08
--- /dev/null
+++ b/x-admin-web/src/views/test/test1.vue
@@ -0,0 +1,13 @@
+
+ 功能点一
+
+
+
+
+
\ No newline at end of file
diff --git a/x-admin-web/src/views/test/test2.vue b/x-admin-web/src/views/test/test2.vue
new file mode 100644
index 0000000..319b0f7
--- /dev/null
+++ b/x-admin-web/src/views/test/test2.vue
@@ -0,0 +1,13 @@
+
+ 功能点二
+
+
+
+
+
\ No newline at end of file
diff --git a/x-admin-web/src/views/test/test3.vue b/x-admin-web/src/views/test/test3.vue
new file mode 100644
index 0000000..4bae5eb
--- /dev/null
+++ b/x-admin-web/src/views/test/test3.vue
@@ -0,0 +1,13 @@
+
+ 功能点三
+
+
+
+
+
\ No newline at end of file
diff --git a/x-admin-web/src/views/tree/index.vue b/x-admin-web/src/views/tree/index.vue
new file mode 100644
index 0000000..89c6b01
--- /dev/null
+++ b/x-admin-web/src/views/tree/index.vue
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/x-admin-web/src/views/workbench/workbench.vue b/x-admin-web/src/views/workbench/workbench.vue
new file mode 100644
index 0000000..424cc65
--- /dev/null
+++ b/x-admin-web/src/views/workbench/workbench.vue
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+ 任务统计
+
+
+
+
+
+
+ 新建任务
+
+
+
+
+
+
+ 预览
+
+
+ {{ item }}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/x-admin-web/tests/unit/.eslintrc.js b/x-admin-web/tests/unit/.eslintrc.js
new file mode 100644
index 0000000..958d51b
--- /dev/null
+++ b/x-admin-web/tests/unit/.eslintrc.js
@@ -0,0 +1,5 @@
+module.exports = {
+ env: {
+ jest: true
+ }
+}
diff --git a/x-admin-web/tests/unit/components/Breadcrumb.spec.js b/x-admin-web/tests/unit/components/Breadcrumb.spec.js
new file mode 100644
index 0000000..1d94c8f
--- /dev/null
+++ b/x-admin-web/tests/unit/components/Breadcrumb.spec.js
@@ -0,0 +1,98 @@
+import { mount, createLocalVue } from '@vue/test-utils'
+import VueRouter from 'vue-router'
+import ElementUI from 'element-ui'
+import Breadcrumb from '@/components/Breadcrumb/index.vue'
+
+const localVue = createLocalVue()
+localVue.use(VueRouter)
+localVue.use(ElementUI)
+
+const routes = [
+ {
+ path: '/',
+ name: 'home',
+ children: [{
+ path: 'dashboard',
+ name: 'dashboard'
+ }]
+ },
+ {
+ path: '/menu',
+ name: 'menu',
+ children: [{
+ path: 'menu1',
+ name: 'menu1',
+ meta: { title: 'menu1' },
+ children: [{
+ path: 'menu1-1',
+ name: 'menu1-1',
+ meta: { title: 'menu1-1' }
+ },
+ {
+ path: 'menu1-2',
+ name: 'menu1-2',
+ redirect: 'noredirect',
+ meta: { title: 'menu1-2' },
+ children: [{
+ path: 'menu1-2-1',
+ name: 'menu1-2-1',
+ meta: { title: 'menu1-2-1' }
+ },
+ {
+ path: 'menu1-2-2',
+ name: 'menu1-2-2'
+ }]
+ }]
+ }]
+ }]
+
+const router = new VueRouter({
+ routes
+})
+
+describe('Breadcrumb.vue', () => {
+ const wrapper = mount(Breadcrumb, {
+ localVue,
+ router
+ })
+ it('dashboard', () => {
+ router.push('/dashboard')
+ const len = wrapper.findAll('.el-breadcrumb__inner').length
+ expect(len).toBe(1)
+ })
+ it('normal route', () => {
+ router.push('/menu/menu1')
+ const len = wrapper.findAll('.el-breadcrumb__inner').length
+ expect(len).toBe(2)
+ })
+ it('nested route', () => {
+ router.push('/menu/menu1/menu1-2/menu1-2-1')
+ const len = wrapper.findAll('.el-breadcrumb__inner').length
+ expect(len).toBe(4)
+ })
+ it('no meta.title', () => {
+ router.push('/menu/menu1/menu1-2/menu1-2-2')
+ const len = wrapper.findAll('.el-breadcrumb__inner').length
+ expect(len).toBe(3)
+ })
+ // it('click link', () => {
+ // router.push('/menu/menu1/menu1-2/menu1-2-2')
+ // const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
+ // const second = breadcrumbArray.at(1)
+ // console.log(breadcrumbArray)
+ // const href = second.find('a').attributes().href
+ // expect(href).toBe('#/menu/menu1')
+ // })
+ // it('noRedirect', () => {
+ // router.push('/menu/menu1/menu1-2/menu1-2-1')
+ // const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
+ // const redirectBreadcrumb = breadcrumbArray.at(2)
+ // expect(redirectBreadcrumb.contains('a')).toBe(false)
+ // })
+ it('last breadcrumb', () => {
+ router.push('/menu/menu1/menu1-2/menu1-2-1')
+ const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
+ const redirectBreadcrumb = breadcrumbArray.at(3)
+ expect(redirectBreadcrumb.contains('a')).toBe(false)
+ })
+})
diff --git a/x-admin-web/tests/unit/components/Hamburger.spec.js b/x-admin-web/tests/unit/components/Hamburger.spec.js
new file mode 100644
index 0000000..01ea303
--- /dev/null
+++ b/x-admin-web/tests/unit/components/Hamburger.spec.js
@@ -0,0 +1,18 @@
+import { shallowMount } from '@vue/test-utils'
+import Hamburger from '@/components/Hamburger/index.vue'
+describe('Hamburger.vue', () => {
+ it('toggle click', () => {
+ const wrapper = shallowMount(Hamburger)
+ const mockFn = jest.fn()
+ wrapper.vm.$on('toggleClick', mockFn)
+ wrapper.find('.hamburger').trigger('click')
+ expect(mockFn).toBeCalled()
+ })
+ it('prop isActive', () => {
+ const wrapper = shallowMount(Hamburger)
+ wrapper.setProps({ isActive: true })
+ expect(wrapper.contains('.is-active')).toBe(true)
+ wrapper.setProps({ isActive: false })
+ expect(wrapper.contains('.is-active')).toBe(false)
+ })
+})
diff --git a/x-admin-web/tests/unit/components/SvgIcon.spec.js b/x-admin-web/tests/unit/components/SvgIcon.spec.js
new file mode 100644
index 0000000..31467a9
--- /dev/null
+++ b/x-admin-web/tests/unit/components/SvgIcon.spec.js
@@ -0,0 +1,22 @@
+import { shallowMount } from '@vue/test-utils'
+import SvgIcon from '@/components/SvgIcon/index.vue'
+describe('SvgIcon.vue', () => {
+ it('iconClass', () => {
+ const wrapper = shallowMount(SvgIcon, {
+ propsData: {
+ iconClass: 'test'
+ }
+ })
+ expect(wrapper.find('use').attributes().href).toBe('#icon-test')
+ })
+ it('className', () => {
+ const wrapper = shallowMount(SvgIcon, {
+ propsData: {
+ iconClass: 'test'
+ }
+ })
+ expect(wrapper.classes().length).toBe(1)
+ wrapper.setProps({ className: 'test' })
+ expect(wrapper.classes().includes('test')).toBe(true)
+ })
+})
diff --git a/x-admin-web/tests/unit/utils/formatTime.spec.js b/x-admin-web/tests/unit/utils/formatTime.spec.js
new file mode 100644
index 0000000..24e165b
--- /dev/null
+++ b/x-admin-web/tests/unit/utils/formatTime.spec.js
@@ -0,0 +1,30 @@
+import { formatTime } from '@/utils/index.js'
+
+describe('Utils:formatTime', () => {
+ const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
+ const retrofit = 5 * 1000
+
+ it('ten digits timestamp', () => {
+ expect(formatTime((d / 1000).toFixed(0))).toBe('7月13日17时54分')
+ })
+ it('test now', () => {
+ expect(formatTime(+new Date() - 1)).toBe('刚刚')
+ })
+ it('less two minute', () => {
+ expect(formatTime(+new Date() - 60 * 2 * 1000 + retrofit)).toBe('2分钟前')
+ })
+ it('less two hour', () => {
+ expect(formatTime(+new Date() - 60 * 60 * 2 * 1000 + retrofit)).toBe('2小时前')
+ })
+ it('less one day', () => {
+ expect(formatTime(+new Date() - 60 * 60 * 24 * 1 * 1000)).toBe('1天前')
+ })
+ it('more than one day', () => {
+ expect(formatTime(d)).toBe('7月13日17时54分')
+ })
+ it('format', () => {
+ expect(formatTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
+ expect(formatTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
+ expect(formatTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
+ })
+})
diff --git a/x-admin-web/tests/unit/utils/param2Obj.spec.js b/x-admin-web/tests/unit/utils/param2Obj.spec.js
new file mode 100644
index 0000000..e106ed8
--- /dev/null
+++ b/x-admin-web/tests/unit/utils/param2Obj.spec.js
@@ -0,0 +1,14 @@
+import { param2Obj } from '@/utils/index.js'
+describe('Utils:param2Obj', () => {
+ const url = 'https://github.com/PanJiaChen/vue-element-admin?name=bill&age=29&sex=1&field=dGVzdA==&key=%E6%B5%8B%E8%AF%95'
+
+ it('param2Obj test', () => {
+ expect(param2Obj(url)).toEqual({
+ name: 'bill',
+ age: '29',
+ sex: '1',
+ field: window.btoa('test'),
+ key: '测试'
+ })
+ })
+})
diff --git a/x-admin-web/tests/unit/utils/parseTime.spec.js b/x-admin-web/tests/unit/utils/parseTime.spec.js
new file mode 100644
index 0000000..56045af
--- /dev/null
+++ b/x-admin-web/tests/unit/utils/parseTime.spec.js
@@ -0,0 +1,35 @@
+import { parseTime } from '@/utils/index.js'
+
+describe('Utils:parseTime', () => {
+ const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
+ it('timestamp', () => {
+ expect(parseTime(d)).toBe('2018-07-13 17:54:01')
+ })
+ it('timestamp string', () => {
+ expect(parseTime((d + ''))).toBe('2018-07-13 17:54:01')
+ })
+ it('ten digits timestamp', () => {
+ expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
+ })
+ it('new Date', () => {
+ expect(parseTime(new Date(d))).toBe('2018-07-13 17:54:01')
+ })
+ it('format', () => {
+ expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
+ expect(parseTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
+ expect(parseTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
+ })
+ it('get the day of the week', () => {
+ expect(parseTime(d, '{a}')).toBe('五') // 星期五
+ })
+ it('get the day of the week', () => {
+ expect(parseTime(+d + 1000 * 60 * 60 * 24 * 2, '{a}')).toBe('日') // 星期日
+ })
+ it('empty argument', () => {
+ expect(parseTime()).toBeNull()
+ })
+
+ it('null', () => {
+ expect(parseTime(null)).toBeNull()
+ })
+})
diff --git a/x-admin-web/tests/unit/utils/validate.spec.js b/x-admin-web/tests/unit/utils/validate.spec.js
new file mode 100644
index 0000000..f774905
--- /dev/null
+++ b/x-admin-web/tests/unit/utils/validate.spec.js
@@ -0,0 +1,17 @@
+import { validUsername, isExternal } from '@/utils/validate.js'
+
+describe('Utils:validate', () => {
+ it('validUsername', () => {
+ expect(validUsername('admin')).toBe(true)
+ expect(validUsername('editor')).toBe(true)
+ expect(validUsername('xxxx')).toBe(false)
+ })
+ it('isExternal', () => {
+ expect(isExternal('https://github.com/PanJiaChen/vue-element-admin')).toBe(true)
+ expect(isExternal('http://github.com/PanJiaChen/vue-element-admin')).toBe(true)
+ expect(isExternal('github.com/PanJiaChen/vue-element-admin')).toBe(false)
+ expect(isExternal('/dashboard')).toBe(false)
+ expect(isExternal('./dashboard')).toBe(false)
+ expect(isExternal('dashboard')).toBe(false)
+ })
+})
diff --git a/x-admin-web/vue.config.js b/x-admin-web/vue.config.js
new file mode 100644
index 0000000..47e96f7
--- /dev/null
+++ b/x-admin-web/vue.config.js
@@ -0,0 +1,125 @@
+'use strict'
+const path = require('path')
+const defaultSettings = require('./src/settings.js')
+
+function resolve(dir) {
+ return path.join(__dirname, dir)
+}
+
+const name = defaultSettings.title || 'vue Admin Template' // page title
+
+// If your port is set to 80,
+// use administrator privileges to execute the command line.
+// For example, Mac: sudo npm run
+// You can change the port by the following methods:
+// port = 9528 npm run dev OR npm run dev --port = 9528
+const port = 8888 // dev port
+
+// All configuration item explanations can be find in https://cli.vuejs.org/config/
+module.exports = {
+ /**
+ * You will need to set publicPath if you plan to deploy your site under a sub path,
+ * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
+ * then publicPath should be set to "/bar/".
+ * In most cases please use '/' !!!
+ * Detail: https://cli.vuejs.org/config/#publicpath
+ */
+ publicPath: '/',
+ outputDir: 'dist',
+ assetsDir: 'static',
+ lintOnSave: false,
+ productionSourceMap: false,
+ devServer: {
+ port: port,
+ open: false,
+ overlay: {
+ warnings: false,
+ errors: true
+ },
+ //before: require('./mock/mock-server.js')
+ },
+ configureWebpack: {
+ // provide the app's title in webpack's name field, so that
+ // it can be accessed in index.html to inject the correct title.
+ name: name,
+ resolve: {
+ alias: {
+ '@': resolve('src')
+ }
+ }
+ },
+ chainWebpack(config) {
+ // it can improve the speed of the first screen, it is recommended to turn on preload
+ // config.plugins.delete('preload')
+
+ // when there are many pages, it will cause too many meaningless requests
+ config.plugins.delete('prefetch')
+
+ // set svg-sprite-loader
+ config.module
+ .rule('svg')
+ .exclude.add(resolve('src/icons'))
+ .end()
+ config.module
+ .rule('icons')
+ .test(/\.svg$/)
+ .include.add(resolve('src/icons'))
+ .end()
+ .use('svg-sprite-loader')
+ .loader('svg-sprite-loader')
+ .options({
+ symbolId: 'icon-[name]'
+ })
+ .end()
+
+ // set preserveWhitespace
+ config.module
+ .rule('vue')
+ .use('vue-loader')
+ .loader('vue-loader')
+ .tap(options => {
+ options.compilerOptions.preserveWhitespace = true
+ return options
+ })
+ .end()
+
+ config
+ .when(process.env.NODE_ENV !== 'development',
+ config => {
+ config
+ .plugin('ScriptExtHtmlWebpackPlugin')
+ .after('html')
+ .use('script-ext-html-webpack-plugin', [{
+ // `runtime` must same as runtimeChunk name. default is `runtime`
+ inline: /runtime\..*\.js$/
+ }])
+ .end()
+ config
+ .optimization.splitChunks({
+ chunks: 'all',
+ cacheGroups: {
+ libs: {
+ name: 'chunk-libs',
+ test: /[\\/]node_modules[\\/]/,
+ priority: 10,
+ chunks: 'initial' // only package third parties that are initially dependent
+ },
+ elementUI: {
+ name: 'chunk-elementUI', // split elementUI into a single package
+ priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
+ test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
+ },
+ commons: {
+ name: 'chunk-commons',
+ test: resolve('src/components'), // can customize your rules
+ minChunks: 3, // minimum common number
+ priority: 5,
+ reuseExistingChunk: true
+ }
+ }
+ })
+ config.optimization.runtimeChunk('single')
+ }
+ )
+ }
+}
diff --git a/x-admin/x-admin/.gitignore b/x-admin/x-admin/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/x-admin/x-admin/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/x-admin/x-admin/.mvn/wrapper/maven-wrapper.jar b/x-admin/x-admin/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 0000000..bf82ff0
Binary files /dev/null and b/x-admin/x-admin/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/x-admin/x-admin/.mvn/wrapper/maven-wrapper.properties b/x-admin/x-admin/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..ca5ab4b
--- /dev/null
+++ b/x-admin/x-admin/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
diff --git a/x-admin/x-admin/codes/com/lantu/sys/controller/EquipController.java b/x-admin/x-admin/codes/com/lantu/sys/controller/EquipController.java
new file mode 100644
index 0000000..f69214d
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/controller/EquipController.java
@@ -0,0 +1,18 @@
+package com.lantu.sys.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.stereotype.Controller;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Controller
+@RequestMapping("/sys/equip")
+public class EquipController {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/controller/MenuController.java b/x-admin/x-admin/codes/com/lantu/sys/controller/MenuController.java
new file mode 100644
index 0000000..8abdc59
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/controller/MenuController.java
@@ -0,0 +1,18 @@
+package com.lantu.sys.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.stereotype.Controller;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Controller
+@RequestMapping("/sys/menu")
+public class MenuController {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/controller/RoleController.java b/x-admin/x-admin/codes/com/lantu/sys/controller/RoleController.java
new file mode 100644
index 0000000..852359a
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/controller/RoleController.java
@@ -0,0 +1,18 @@
+package com.lantu.sys.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.stereotype.Controller;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Controller
+@RequestMapping("/sys/role")
+public class RoleController {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/controller/RoleMenuController.java b/x-admin/x-admin/codes/com/lantu/sys/controller/RoleMenuController.java
new file mode 100644
index 0000000..03bf995
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/controller/RoleMenuController.java
@@ -0,0 +1,18 @@
+package com.lantu.sys.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.stereotype.Controller;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Controller
+@RequestMapping("/sys/roleMenu")
+public class RoleMenuController {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/controller/UserController.java b/x-admin/x-admin/codes/com/lantu/sys/controller/UserController.java
new file mode 100644
index 0000000..2df2269
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/controller/UserController.java
@@ -0,0 +1,18 @@
+package com.lantu.sys.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.stereotype.Controller;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Controller
+@RequestMapping("/sys/user")
+public class UserController {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/controller/UserRoleController.java b/x-admin/x-admin/codes/com/lantu/sys/controller/UserRoleController.java
new file mode 100644
index 0000000..7dc4ebe
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/controller/UserRoleController.java
@@ -0,0 +1,18 @@
+package com.lantu.sys.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.stereotype.Controller;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Controller
+@RequestMapping("/sys/userRole")
+public class UserRoleController {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/entity/Equip.java b/x-admin/x-admin/codes/com/lantu/sys/entity/Equip.java
new file mode 100644
index 0000000..4fa50ce
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/entity/Equip.java
@@ -0,0 +1,111 @@
+package com.lantu.sys.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ *
+ *
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@TableName("x_equip")
+@ApiModel(value = "Equip对象", description = "")
+public class Equip implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "id", type = IdType.AUTO)
+ private Integer id;
+
+ private String form;
+
+ private String focal;
+
+ private Integer status;
+
+ private Integer deleted;
+
+ private String x1;
+
+ private String x2;
+
+ private String x3;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+ public String getForm() {
+ return form;
+ }
+
+ public void setForm(String form) {
+ this.form = form;
+ }
+ public String getFocal() {
+ return focal;
+ }
+
+ public void setFocal(String focal) {
+ this.focal = focal;
+ }
+ public Integer getStatus() {
+ return status;
+ }
+
+ public void setStatus(Integer status) {
+ this.status = status;
+ }
+ public Integer getDeleted() {
+ return deleted;
+ }
+
+ public void setDeleted(Integer deleted) {
+ this.deleted = deleted;
+ }
+ public String getx1() {
+ return x1;
+ }
+
+ public void setx1(String x1) {
+ this.x1 = x1;
+ }
+ public String getx2() {
+ return x2;
+ }
+
+ public void setx2(String x2) {
+ this.x2 = x2;
+ }
+ public String getx3() {
+ return x3;
+ }
+
+ public void setx3(String x3) {
+ this.x3 = x3;
+ }
+
+ @Override
+ public String toString() {
+ return "Equip{" +
+ "id=" + id +
+ ", form=" + form +
+ ", focal=" + focal +
+ ", status=" + status +
+ ", deleted=" + deleted +
+ ", x1=" + x1 +
+ ", x2=" + x2 +
+ ", x3=" + x3 +
+ "}";
+ }
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/entity/Menu.java b/x-admin/x-admin/codes/com/lantu/sys/entity/Menu.java
new file mode 100644
index 0000000..7dc3d75
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/entity/Menu.java
@@ -0,0 +1,131 @@
+package com.lantu.sys.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ *
+ *
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@TableName("x_menu")
+@ApiModel(value = "Menu对象", description = "")
+public class Menu implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "menu_id", type = IdType.AUTO)
+ private Integer menuId;
+
+ private String component;
+
+ private String path;
+
+ private String redirect;
+
+ private String name;
+
+ private String title;
+
+ private String icon;
+
+ private Integer parentId;
+
+ private String isLeaf;
+
+ private Boolean hidden;
+
+ public Integer getMenuId() {
+ return menuId;
+ }
+
+ public void setMenuId(Integer menuId) {
+ this.menuId = menuId;
+ }
+ public String getComponent() {
+ return component;
+ }
+
+ public void setComponent(String component) {
+ this.component = component;
+ }
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+ public String getRedirect() {
+ return redirect;
+ }
+
+ public void setRedirect(String redirect) {
+ this.redirect = redirect;
+ }
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+ public String getIcon() {
+ return icon;
+ }
+
+ public void setIcon(String icon) {
+ this.icon = icon;
+ }
+ public Integer getParentId() {
+ return parentId;
+ }
+
+ public void setParentId(Integer parentId) {
+ this.parentId = parentId;
+ }
+ public String getIsLeaf() {
+ return isLeaf;
+ }
+
+ public void setIsLeaf(String isLeaf) {
+ this.isLeaf = isLeaf;
+ }
+ public Boolean getHidden() {
+ return hidden;
+ }
+
+ public void setHidden(Boolean hidden) {
+ this.hidden = hidden;
+ }
+
+ @Override
+ public String toString() {
+ return "Menu{" +
+ "menuId=" + menuId +
+ ", component=" + component +
+ ", path=" + path +
+ ", redirect=" + redirect +
+ ", name=" + name +
+ ", title=" + title +
+ ", icon=" + icon +
+ ", parentId=" + parentId +
+ ", isLeaf=" + isLeaf +
+ ", hidden=" + hidden +
+ "}";
+ }
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/entity/Role.java b/x-admin/x-admin/codes/com/lantu/sys/entity/Role.java
new file mode 100644
index 0000000..d23e42b
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/entity/Role.java
@@ -0,0 +1,61 @@
+package com.lantu.sys.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ *
+ *
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@TableName("x_role")
+@ApiModel(value = "Role对象", description = "")
+public class Role implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "role_id", type = IdType.AUTO)
+ private Integer roleId;
+
+ private String roleName;
+
+ private String roleDesc;
+
+ public Integer getRoleId() {
+ return roleId;
+ }
+
+ public void setRoleId(Integer roleId) {
+ this.roleId = roleId;
+ }
+ public String getRoleName() {
+ return roleName;
+ }
+
+ public void setRoleName(String roleName) {
+ this.roleName = roleName;
+ }
+ public String getRoleDesc() {
+ return roleDesc;
+ }
+
+ public void setRoleDesc(String roleDesc) {
+ this.roleDesc = roleDesc;
+ }
+
+ @Override
+ public String toString() {
+ return "Role{" +
+ "roleId=" + roleId +
+ ", roleName=" + roleName +
+ ", roleDesc=" + roleDesc +
+ "}";
+ }
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/entity/RoleMenu.java b/x-admin/x-admin/codes/com/lantu/sys/entity/RoleMenu.java
new file mode 100644
index 0000000..c94ae39
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/entity/RoleMenu.java
@@ -0,0 +1,61 @@
+package com.lantu.sys.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ *
+ *
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@TableName("x_role_menu")
+@ApiModel(value = "RoleMenu对象", description = "")
+public class RoleMenu implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "id", type = IdType.AUTO)
+ private Integer id;
+
+ private Integer roleId;
+
+ private Integer menuId;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+ public Integer getRoleId() {
+ return roleId;
+ }
+
+ public void setRoleId(Integer roleId) {
+ this.roleId = roleId;
+ }
+ public Integer getMenuId() {
+ return menuId;
+ }
+
+ public void setMenuId(Integer menuId) {
+ this.menuId = menuId;
+ }
+
+ @Override
+ public String toString() {
+ return "RoleMenu{" +
+ "id=" + id +
+ ", roleId=" + roleId +
+ ", menuId=" + menuId +
+ "}";
+ }
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/entity/User.java b/x-admin/x-admin/codes/com/lantu/sys/entity/User.java
new file mode 100644
index 0000000..a96284c
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/entity/User.java
@@ -0,0 +1,111 @@
+package com.lantu.sys.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ *
+ *
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@TableName("x_user")
+@ApiModel(value = "User对象", description = "")
+public class User implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "id", type = IdType.AUTO)
+ private Integer id;
+
+ private String username;
+
+ private String password;
+
+ private String email;
+
+ private String phone;
+
+ private Integer status;
+
+ private String avatar;
+
+ private Integer deleted;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+ public Integer getStatus() {
+ return status;
+ }
+
+ public void setStatus(Integer status) {
+ this.status = status;
+ }
+ public String getAvatar() {
+ return avatar;
+ }
+
+ public void setAvatar(String avatar) {
+ this.avatar = avatar;
+ }
+ public Integer getDeleted() {
+ return deleted;
+ }
+
+ public void setDeleted(Integer deleted) {
+ this.deleted = deleted;
+ }
+
+ @Override
+ public String toString() {
+ return "User{" +
+ "id=" + id +
+ ", username=" + username +
+ ", password=" + password +
+ ", email=" + email +
+ ", phone=" + phone +
+ ", status=" + status +
+ ", avatar=" + avatar +
+ ", deleted=" + deleted +
+ "}";
+ }
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/entity/UserRole.java b/x-admin/x-admin/codes/com/lantu/sys/entity/UserRole.java
new file mode 100644
index 0000000..d5b9b74
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/entity/UserRole.java
@@ -0,0 +1,61 @@
+package com.lantu.sys.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ *
+ *
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@TableName("x_user_role")
+@ApiModel(value = "UserRole对象", description = "")
+public class UserRole implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "id", type = IdType.AUTO)
+ private Integer id;
+
+ private Integer userId;
+
+ private Integer roleId;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+ public Integer getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Integer userId) {
+ this.userId = userId;
+ }
+ public Integer getRoleId() {
+ return roleId;
+ }
+
+ public void setRoleId(Integer roleId) {
+ this.roleId = roleId;
+ }
+
+ @Override
+ public String toString() {
+ return "UserRole{" +
+ "id=" + id +
+ ", userId=" + userId +
+ ", roleId=" + roleId +
+ "}";
+ }
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/mapper/EquipMapper.java b/x-admin/x-admin/codes/com/lantu/sys/mapper/EquipMapper.java
new file mode 100644
index 0000000..7048410
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/mapper/EquipMapper.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.mapper;
+
+import com.lantu.sys.entity.Equip;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface EquipMapper extends BaseMapper {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/mapper/MenuMapper.java b/x-admin/x-admin/codes/com/lantu/sys/mapper/MenuMapper.java
new file mode 100644
index 0000000..cd0ecf2
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/mapper/MenuMapper.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.mapper;
+
+import com.lantu.sys.entity.Menu;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface MenuMapper extends BaseMapper {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/mapper/RoleMapper.java b/x-admin/x-admin/codes/com/lantu/sys/mapper/RoleMapper.java
new file mode 100644
index 0000000..3d3ac30
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/mapper/RoleMapper.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.mapper;
+
+import com.lantu.sys.entity.Role;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface RoleMapper extends BaseMapper {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/mapper/RoleMenuMapper.java b/x-admin/x-admin/codes/com/lantu/sys/mapper/RoleMenuMapper.java
new file mode 100644
index 0000000..08fd938
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/mapper/RoleMenuMapper.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.mapper;
+
+import com.lantu.sys.entity.RoleMenu;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface RoleMenuMapper extends BaseMapper {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/mapper/UserMapper.java b/x-admin/x-admin/codes/com/lantu/sys/mapper/UserMapper.java
new file mode 100644
index 0000000..f30cf9f
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/mapper/UserMapper.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.mapper;
+
+import com.lantu.sys.entity.User;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface UserMapper extends BaseMapper {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/mapper/UserRoleMapper.java b/x-admin/x-admin/codes/com/lantu/sys/mapper/UserRoleMapper.java
new file mode 100644
index 0000000..5a20c15
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/mapper/UserRoleMapper.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.mapper;
+
+import com.lantu.sys.entity.UserRole;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface UserRoleMapper extends BaseMapper {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/service/IEquipService.java b/x-admin/x-admin/codes/com/lantu/sys/service/IEquipService.java
new file mode 100644
index 0000000..624638d
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/service/IEquipService.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.service;
+
+import com.lantu.sys.entity.Equip;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface IEquipService extends IService {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/service/IMenuService.java b/x-admin/x-admin/codes/com/lantu/sys/service/IMenuService.java
new file mode 100644
index 0000000..cef81d5
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/service/IMenuService.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.service;
+
+import com.lantu.sys.entity.Menu;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface IMenuService extends IService {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/service/IRoleMenuService.java b/x-admin/x-admin/codes/com/lantu/sys/service/IRoleMenuService.java
new file mode 100644
index 0000000..29edf4e
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/service/IRoleMenuService.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.service;
+
+import com.lantu.sys.entity.RoleMenu;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface IRoleMenuService extends IService {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/service/IRoleService.java b/x-admin/x-admin/codes/com/lantu/sys/service/IRoleService.java
new file mode 100644
index 0000000..23a8351
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/service/IRoleService.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.service;
+
+import com.lantu.sys.entity.Role;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface IRoleService extends IService {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/service/IUserRoleService.java b/x-admin/x-admin/codes/com/lantu/sys/service/IUserRoleService.java
new file mode 100644
index 0000000..dd979d8
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/service/IUserRoleService.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.service;
+
+import com.lantu.sys.entity.UserRole;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface IUserRoleService extends IService {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/service/IUserService.java b/x-admin/x-admin/codes/com/lantu/sys/service/IUserService.java
new file mode 100644
index 0000000..254e630
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/service/IUserService.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.service;
+
+import com.lantu.sys.entity.User;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface IUserService extends IService {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/service/impl/EquipServiceImpl.java b/x-admin/x-admin/codes/com/lantu/sys/service/impl/EquipServiceImpl.java
new file mode 100644
index 0000000..09a19c8
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/service/impl/EquipServiceImpl.java
@@ -0,0 +1,20 @@
+package com.lantu.sys.service.impl;
+
+import com.lantu.sys.entity.Equip;
+import com.lantu.sys.mapper.EquipMapper;
+import com.lantu.sys.service.IEquipService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Service
+public class EquipServiceImpl extends ServiceImpl implements IEquipService {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/service/impl/MenuServiceImpl.java b/x-admin/x-admin/codes/com/lantu/sys/service/impl/MenuServiceImpl.java
new file mode 100644
index 0000000..6610756
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/service/impl/MenuServiceImpl.java
@@ -0,0 +1,20 @@
+package com.lantu.sys.service.impl;
+
+import com.lantu.sys.entity.Menu;
+import com.lantu.sys.mapper.MenuMapper;
+import com.lantu.sys.service.IMenuService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Service
+public class MenuServiceImpl extends ServiceImpl implements IMenuService {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/service/impl/RoleMenuServiceImpl.java b/x-admin/x-admin/codes/com/lantu/sys/service/impl/RoleMenuServiceImpl.java
new file mode 100644
index 0000000..4041fdb
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/service/impl/RoleMenuServiceImpl.java
@@ -0,0 +1,20 @@
+package com.lantu.sys.service.impl;
+
+import com.lantu.sys.entity.RoleMenu;
+import com.lantu.sys.mapper.RoleMenuMapper;
+import com.lantu.sys.service.IRoleMenuService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Service
+public class RoleMenuServiceImpl extends ServiceImpl implements IRoleMenuService {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/service/impl/RoleServiceImpl.java b/x-admin/x-admin/codes/com/lantu/sys/service/impl/RoleServiceImpl.java
new file mode 100644
index 0000000..2933bd9
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/service/impl/RoleServiceImpl.java
@@ -0,0 +1,20 @@
+package com.lantu.sys.service.impl;
+
+import com.lantu.sys.entity.Role;
+import com.lantu.sys.mapper.RoleMapper;
+import com.lantu.sys.service.IRoleService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Service
+public class RoleServiceImpl extends ServiceImpl implements IRoleService {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/service/impl/UserRoleServiceImpl.java b/x-admin/x-admin/codes/com/lantu/sys/service/impl/UserRoleServiceImpl.java
new file mode 100644
index 0000000..4913d3d
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/service/impl/UserRoleServiceImpl.java
@@ -0,0 +1,20 @@
+package com.lantu.sys.service.impl;
+
+import com.lantu.sys.entity.UserRole;
+import com.lantu.sys.mapper.UserRoleMapper;
+import com.lantu.sys.service.IUserRoleService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Service
+public class UserRoleServiceImpl extends ServiceImpl implements IUserRoleService {
+
+}
diff --git a/x-admin/x-admin/codes/com/lantu/sys/service/impl/UserServiceImpl.java b/x-admin/x-admin/codes/com/lantu/sys/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..15895ea
--- /dev/null
+++ b/x-admin/x-admin/codes/com/lantu/sys/service/impl/UserServiceImpl.java
@@ -0,0 +1,20 @@
+package com.lantu.sys.service.impl;
+
+import com.lantu.sys.entity.User;
+import com.lantu.sys.mapper.UserMapper;
+import com.lantu.sys.service.IUserService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Service
+public class UserServiceImpl extends ServiceImpl implements IUserService {
+
+}
diff --git a/x-admin/x-admin/mvnw b/x-admin/x-admin/mvnw
new file mode 100644
index 0000000..8a8fb22
--- /dev/null
+++ b/x-admin/x-admin/mvnw
@@ -0,0 +1,316 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /usr/local/etc/mavenrc ] ; then
+ . /usr/local/etc/mavenrc
+ fi
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`\\unset -f command; \\command -v java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+ fi
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=`cygpath --path --windows "$javaClass"`
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ $MAVEN_DEBUG_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" \
+ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/x-admin/x-admin/mvnw.cmd b/x-admin/x-admin/mvnw.cmd
new file mode 100644
index 0000000..1d8ab01
--- /dev/null
+++ b/x-admin/x-admin/mvnw.cmd
@@ -0,0 +1,188 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% ^
+ %JVM_CONFIG_MAVEN_PROPS% ^
+ %MAVEN_OPTS% ^
+ %MAVEN_DEBUG_OPTS% ^
+ -classpath %WRAPPER_JAR% ^
+ "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+ %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
+
+cmd /C exit /B %ERROR_CODE%
diff --git a/x-admin/x-admin/pom.xml b/x-admin/x-admin/pom.xml
new file mode 100644
index 0000000..0747807
--- /dev/null
+++ b/x-admin/x-admin/pom.xml
@@ -0,0 +1,111 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.7.16
+
+
+ com.lantu
+ x-admin
+ 0.0.1-SNAPSHOT
+ x-admin
+ x-admin
+
+ 1.8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ com.mysql
+ mysql-connector-j
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ 3.5.2
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+ 2.0.7
+
+
+ com.baomidou
+ mybatis-plus-generator
+ 3.5.2
+
+
+
+ org.freemarker
+ freemarker
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+
+
+
+
+
+
+
+
+
+
+ io.jsonwebtoken
+ jjwt
+ 0.9.1
+
+
+ io.springfox
+ springfox-boot-starter
+ 3.0.0
+
+
+
+ org.springframework.security
+ spring-security-core
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/x-admin/x-admin/src/main/java/com/lantu/XAdminApplication.java b/x-admin/x-admin/src/main/java/com/lantu/XAdminApplication.java
new file mode 100644
index 0000000..4b1582e
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/XAdminApplication.java
@@ -0,0 +1,24 @@
+package com.lantu;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+@SpringBootApplication
+@MapperScan("com.lantu.*.mapper")
+public class XAdminApplication {
+
+ public static void main(String[] args) {
+
+ SpringApplication.run(XAdminApplication.class, args);
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder(){
+ return new BCryptPasswordEncoder();
+ }
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/common/utils/JwtUtil.java b/x-admin/x-admin/src/main/java/com/lantu/common/utils/JwtUtil.java
new file mode 100644
index 0000000..0ef8ddf
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/common/utils/JwtUtil.java
@@ -0,0 +1,65 @@
+package com.lantu.common.utils;
+
+import com.alibaba.fastjson2.JSON;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.JwtBuilder;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.util.Base64;
+import java.util.Date;
+import java.util.UUID;
+
+/**
+ * 作者:cyf
+ * 描述:无
+ */
+@Component
+public class JwtUtil {
+ // 有效期
+ private static final long JWT_EXPIRE = 30*60*1000L; //半小时
+ // 令牌秘钥
+ private static final String JWT_KEY = "123456";
+
+ public String createToken(Object data){
+ // 当前时间
+ long currentTime = System.currentTimeMillis();
+ // 过期时间
+ long expTime = currentTime+JWT_EXPIRE;
+ // 构建jwt
+ JwtBuilder builder = Jwts.builder()
+ .setId(UUID.randomUUID()+"")
+ .setSubject(JSON.toJSONString(data))
+ .setIssuer("system")
+ .setIssuedAt(new Date(currentTime))
+ .signWith(SignatureAlgorithm.HS256, encodeSecret(JWT_KEY))
+ .setExpiration(new Date(expTime));
+ return builder.compact();
+ }
+
+ private SecretKey encodeSecret(String key){
+ byte[] encode = Base64.getEncoder().encode(key.getBytes());
+ SecretKeySpec aes = new SecretKeySpec(encode, 0, encode.length, "AES");
+ return aes;
+ }
+
+ public Claims parseToken(String token){
+ Claims body = Jwts.parser()
+ .setSigningKey(encodeSecret(JWT_KEY))
+ .parseClaimsJws(token)
+ .getBody();
+ return body;
+ }
+
+ public T parseToken(String token,Class clazz){
+ Claims body = Jwts.parser()
+ .setSigningKey(encodeSecret(JWT_KEY))
+ .parseClaimsJws(token)
+ .getBody();
+ return JSON.parseObject(body.getSubject(),clazz);
+ }
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/common/vo/Result.java b/x-admin/x-admin/src/main/java/com/lantu/common/vo/Result.java
new file mode 100644
index 0000000..fda3c0d
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/common/vo/Result.java
@@ -0,0 +1,47 @@
+package com.lantu.common.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 作者:cyf
+ * 描述:无
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Result {
+ private Integer code;
+ private String message;
+ private T data;
+
+ public static Result success(){
+ return new Result<>(20000,"success", null);
+ }
+ public static Result success(T data){
+ return new Result<>(20000,"success", data);
+ }
+ public static Result success(T data, String message){
+ return new Result<>(20000,message, data);
+ }
+ public static Result success(String message){
+ return new Result<>(20000,message, null);
+ }
+ public static Result fail(){
+ return new Result<>(20001,"fail",null);
+ }
+
+ public static Result fail(Integer code){
+ return new Result<>(code,"fail",null);
+ }
+
+ public static Result fail(Integer code, String message){
+ return new Result<>(code,message,null);
+ }
+
+ public static Result fail( String message){
+ return new Result<>(20001,message,null);
+ }
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/config/MpConfig.java b/x-admin/x-admin/src/main/java/com/lantu/config/MpConfig.java
new file mode 100644
index 0000000..084f3fb
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/config/MpConfig.java
@@ -0,0 +1,21 @@
+package com.lantu.config;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 作者:cyf
+ * 描述:无
+ */
+@Configuration
+public class MpConfig {
+ @Bean
+ public MybatisPlusInterceptor mybatisPlusInterceptor() {
+ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+ interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+ return interceptor;
+ }
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/config/MyCorsConfig.java b/x-admin/x-admin/src/main/java/com/lantu/config/MyCorsConfig.java
new file mode 100644
index 0000000..af24ac7
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/config/MyCorsConfig.java
@@ -0,0 +1,28 @@
+package com.lantu.config;
+
+import org.springframework.web.filter.CorsFilter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+
+/**
+ * 作者:cyf
+ * 描述:无
+ */
+@Configuration
+public class MyCorsConfig {
+ @Bean
+ public CorsFilter corsFilter(){
+ CorsConfiguration configuration = new CorsConfiguration();
+ configuration.addAllowedOrigin("http://localhost:8888");
+ configuration.setAllowCredentials(true);
+ configuration.addAllowedMethod("*");
+ configuration.addAllowedHeader("*");
+
+ UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
+ urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", configuration);
+
+ return new CorsFilter(urlBasedCorsConfigurationSource);
+ }
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/config/MyInterceptorConfig.java b/x-admin/x-admin/src/main/java/com/lantu/config/MyInterceptorConfig.java
new file mode 100644
index 0000000..8209b29
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/config/MyInterceptorConfig.java
@@ -0,0 +1,32 @@
+package com.lantu.config;
+
+import com.lantu.interceptor.JwtValidateInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * 作者:cyf
+ * 描述:无
+ */
+@Configuration
+public class MyInterceptorConfig implements WebMvcConfigurer {
+ @Autowired
+ private JwtValidateInterceptor jwtValidateInterceptor;
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ InterceptorRegistration registration = registry.addInterceptor(jwtValidateInterceptor);
+ registration.addPathPatterns("/**")
+ .excludePathPatterns(
+ "/user/login",
+ "/user/info",
+ "/user/logout",
+ "/error",
+ "/swagger-ui/**",
+ "/swagger-resources/**",
+ "/v3/**"
+ );
+ }
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/config/MyRedisConfig.java b/x-admin/x-admin/src/main/java/com/lantu/config/MyRedisConfig.java
new file mode 100644
index 0000000..00ecaaf
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/config/MyRedisConfig.java
@@ -0,0 +1,58 @@
+package com.lantu.config;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import javax.annotation.Resource;
+import java.text.SimpleDateFormat;
+import java.util.TimeZone;
+
+/**
+ * 作者:cyf
+ * 描述:无
+ */
+
+@Configuration
+public class MyRedisConfig {
+
+ @Resource
+ private RedisConnectionFactory factory;
+
+ @Bean
+ public RedisTemplate redisTemplate(){
+ RedisTemplate redisTemplate = new RedisTemplate<>();
+ redisTemplate.setConnectionFactory(factory);
+
+ redisTemplate.setKeySerializer(new StringRedisSerializer());
+
+ Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
+ redisTemplate.setValueSerializer(serializer);
+
+ ObjectMapper om = new ObjectMapper();
+ om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+ om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+ om.setTimeZone(TimeZone.getDefault());
+ om.configure(MapperFeature.USE_ANNOTATIONS, false);
+ om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+ om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
+ om.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ serializer.setObjectMapper(om);
+
+ return redisTemplate;
+ }
+}
+
diff --git a/x-admin/x-admin/src/main/java/com/lantu/config/MySwaggerConfig.java b/x-admin/x-admin/src/main/java/com/lantu/config/MySwaggerConfig.java
new file mode 100644
index 0000000..29ca2d1
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/config/MySwaggerConfig.java
@@ -0,0 +1,65 @@
+package com.lantu.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.oas.annotations.EnableOpenApi;
+import springfox.documentation.service.*;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+
+import java.util.Collections;
+import java.util.List;
+
+
+/**
+ * 作者:cyf
+ * 描述:无
+ */
+@Configuration
+@EnableOpenApi
+@EnableWebMvc
+public class MySwaggerConfig {
+ @Bean
+ public Docket api() {
+ return new Docket(DocumentationType.OAS_30)
+ .apiInfo(apiInfo())
+ .select()
+ .apis(RequestHandlerSelectors.basePackage("com.lantu"))
+ .paths(PathSelectors.any())
+ .build()
+ .securitySchemes(Collections.singletonList(securityScheme()))
+ .securityContexts(Collections.singletonList(securityContext()));
+ }
+ private SecurityScheme securityScheme() {
+ //return new ApiKey("Authorization", "Authorization", "header");
+ return new ApiKey("X-Token", "X-Token", "header");
+ }
+ private SecurityContext securityContext() {
+ return SecurityContext.builder()
+ .securityReferences(defaultAuth())
+ .forPaths(PathSelectors.regex("^(?!auth).*$"))
+ .build();
+ }
+
+ private List defaultAuth() {
+ AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+ AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+ authorizationScopes[0] = authorizationScope;
+ return Collections.singletonList(
+ new SecurityReference("X-Token", authorizationScopes));
+ }
+
+ private ApiInfo apiInfo() {
+ return new ApiInfoBuilder()
+ .title("神盾局特工管理系统接口文档")
+ .description("全网最简单的SpringBoot+Vue前后端分离项目实战")
+ .version("1.0")
+ .contact(new Contact("qqcn", "http://www.qqcn.cn", "qqcn@aliyun.com"))
+ .build();
+ }
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/interceptor/JwtValidateInterceptor.java b/x-admin/x-admin/src/main/java/com/lantu/interceptor/JwtValidateInterceptor.java
new file mode 100644
index 0000000..50f7e09
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/interceptor/JwtValidateInterceptor.java
@@ -0,0 +1,42 @@
+package com.lantu.interceptor;
+
+import com.alibaba.fastjson2.JSON;
+import com.lantu.common.utils.JwtUtil;
+import com.lantu.common.vo.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 作者:cyf
+ * 描述:无
+ */
+@Component
+@Slf4j
+public class JwtValidateInterceptor implements HandlerInterceptor {
+ @Autowired
+ private JwtUtil jwtUtil;
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ String token = request.getHeader("X-Token");
+ log.debug(request.getRequestURI() + "需要验证" + token);
+ if (token != null){
+ try {
+ jwtUtil.parseToken(token);
+ log.debug(request.getRequestURI() + "验证通过");
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ log.debug(request.getRequestURI() + "验证失败,禁止访问");
+ response.setContentType("application/json;charset=utf-8");
+ Result fail = Result.fail(20003, "jwt无效,请重新登录");
+ response.getWriter().write(JSON.toJSONString(fail));
+ return false; //拦截
+ }
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/controller/EquipController.java b/x-admin/x-admin/src/main/java/com/lantu/sys/controller/EquipController.java
new file mode 100644
index 0000000..d805807
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/controller/EquipController.java
@@ -0,0 +1,76 @@
+package com.lantu.sys.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.lantu.common.vo.Result;
+import com.lantu.sys.entity.Equip;
+import com.lantu.sys.service.IEquipService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@RestController
+@RequestMapping("/equip")
+public class EquipController {
+ @Autowired
+ private IEquipService equipService;
+
+ @PostMapping
+ public Result> addEquip(@RequestBody Equip equip){
+ equipService.addEquip(equip);
+ return Result.success("新增设备成功");
+ }
+
+ @PutMapping
+ public Result> updateEquip(@RequestBody Equip equip){
+ equipService.updateById(equip);
+ return Result.success("修改设备成功");
+ }
+
+ @GetMapping("/{id}")
+ public Result getEquipById(@PathVariable("id") Integer id){
+ Equip equip= equipService.getById(id);
+ return Result.success(equip);
+ }
+
+ @DeleteMapping("/{id}")
+ public Result deleteEquipById(@PathVariable("id") Integer id){
+ equipService.removeById(id);
+ return Result.success("删除设备成功");
+ }
+
+
+ @GetMapping("/list")
+ public Result> getEquipList(@RequestParam(value = "status",required = false) String status,
+ @RequestParam(value = "facol",required = false) String facol,
+ @RequestParam(value = "pageNo") Long pageNo,
+ @RequestParam(value = "pageSize") Long pageSize){
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(StringUtils.hasLength(status),Equip::getx2,status);
+ wrapper.eq(StringUtils.hasLength(facol),Equip::getFocal,facol);
+ wrapper.orderByDesc(Equip::getId);
+ Page page = new Page<>(pageNo,pageSize);
+ equipService.page(page,wrapper);
+ Map data = new HashMap<>();
+ data.put("total",page.getTotal());
+ data.put("rows",page.getRecords());
+ return Result.success(data);
+
+
+ }
+
+
+
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/controller/MenuController.java b/x-admin/x-admin/src/main/java/com/lantu/sys/controller/MenuController.java
new file mode 100644
index 0000000..d0ca912
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/controller/MenuController.java
@@ -0,0 +1,36 @@
+package com.lantu.sys.controller;
+
+import com.lantu.common.vo.Result;
+import com.lantu.sys.entity.Menu;
+import com.lantu.sys.service.IMenuService;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@RestController
+@RequestMapping("/sys/menu")
+public class MenuController {
+ @Autowired
+ private IMenuService menuService;
+
+ @ApiOperation("查询所有菜单数据")
+ @GetMapping
+ public Result> getAllMenu(){
+ List menuList = menuService.getAllMenu();
+
+ return Result.success(menuList);
+ }
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/controller/RoleController.java b/x-admin/x-admin/src/main/java/com/lantu/sys/controller/RoleController.java
new file mode 100644
index 0000000..192e8ba
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/controller/RoleController.java
@@ -0,0 +1,78 @@
+package com.lantu.sys.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.lantu.common.vo.Result;
+import com.lantu.sys.entity.Role;
+import com.lantu.sys.service.IRoleService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@RestController
+@RequestMapping("/role")
+public class RoleController {
+ @Autowired
+ private IRoleService roleService;
+
+ @GetMapping("/list")
+ public Result> getRoleList(@RequestParam(value = "roleName",required = false) String roleName,
+ @RequestParam(value = "pageNo") Long pageNo,
+ @RequestParam(value = "pageSize") Long pageSize){
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(StringUtils.hasLength(roleName),Role::getRoleName,roleName);
+ wrapper.orderByDesc(Role::getRoleId);
+ Page page = new Page<>(pageNo,pageSize);
+
+ roleService.page(page,wrapper);
+ Map data = new HashMap<>();
+ data.put("total",page.getTotal());
+ data.put("rows",page.getRecords());
+ return Result.success(data);
+
+
+ }
+
+ @PostMapping
+ public Result> addRole(@RequestBody Role role){
+ roleService.addRole(role);
+ return Result.success("新增角色成功");
+ }
+
+ @PutMapping
+ public Result> updateRole(@RequestBody Role role){
+ roleService.updateRole(role);
+ return Result.success("修改角色成功");
+ }
+
+ @GetMapping("/{id}")
+ public Result getRoleById(@PathVariable("id") Integer id){
+ Role role = roleService.getRoleById(id);
+ return Result.success(role);
+ }
+
+ @DeleteMapping("/{id}")
+ public Result deleteRoleById(@PathVariable("id") Integer id){
+ roleService.deleteRoleById(id);
+ return Result.success("删除角色成功");
+ }
+
+ @GetMapping("/all")
+ public Result> getAllRole(){
+ List roleList = roleService.list();
+ return Result.success(roleList);
+ }
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/controller/RoleMenuController.java b/x-admin/x-admin/src/main/java/com/lantu/sys/controller/RoleMenuController.java
new file mode 100644
index 0000000..1d5c715
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/controller/RoleMenuController.java
@@ -0,0 +1,18 @@
+package com.lantu.sys.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.stereotype.Controller;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@Controller
+@RequestMapping("/sys/roleMenu")
+public class RoleMenuController {
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/controller/UserController.java b/x-admin/x-admin/src/main/java/com/lantu/sys/controller/UserController.java
new file mode 100644
index 0000000..658ebb8
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/controller/UserController.java
@@ -0,0 +1,117 @@
+package com.lantu.sys.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.lantu.common.vo.Result;
+import com.lantu.sys.entity.User;
+import com.lantu.sys.service.IUserService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@Api(tags = {"用户接口列表"})
+@RestController
+@RequestMapping("/user")
+//@CrossOrigin 跨域
+public class UserController {
+ @Autowired
+ private IUserService userService;
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @GetMapping("/all")
+ public Result> getAllUser() {
+ List list = userService.list();
+ return Result.success(list, "查询成功");
+ }
+ @ApiOperation("用户登录")
+
+ @PostMapping("/login")
+ public Result> login(@RequestBody User user){
+ Map data = userService.login(user);
+ if (data != null) {
+ return Result.success(data);
+ }
+ return Result.fail(20002, "用户名或密码错误");
+ }
+
+ @GetMapping("/info")
+ public Result> getUserInfo(@RequestParam("token") String token){
+ //根据token获取用户信息
+ Map data = userService.getUserInfo(token);
+ if (data != null){
+ return Result.success(data);
+ }
+ return Result.fail(20003,"登录信息无效,请重新登录");
+ }
+
+
+
+ @PostMapping("/logout")
+ public Result> logout(@RequestHeader("X-token") String token){
+ userService.logout(token);
+ return Result.success();
+ }
+ @GetMapping("/list")
+ public Result> getUserList(@RequestParam(value = "username",required = false) String username,
+ @RequestParam(value = "phone",required = false) String phone,
+ @RequestParam(value = "pageNo") Long pageNo,
+ @RequestParam(value = "pageSize") Long pageSize){
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(StringUtils.hasLength(username),User::getUsername,username);
+ wrapper.eq(StringUtils.hasLength(phone),User::getPhone,phone);
+ wrapper.orderByDesc(User::getId);
+ Page page = new Page<>(pageNo,pageSize);
+
+ userService.page(page,wrapper);
+ Map data = new HashMap<>();
+ data.put("total",page.getTotal());
+ data.put("rows",page.getRecords());
+ return Result.success(data);
+
+
+ }
+
+ @PostMapping
+ public Result> addUser(@RequestBody User user){
+ user.setPassword(passwordEncoder.encode(user.getPassword()));
+ userService.addUser(user);
+ return Result.success("新增用户成功");
+ }
+
+ @PutMapping
+ public Result> updateUser(@RequestBody User user){
+ user.setPassword(null);
+ userService.updateUser(user);
+ return Result.success("修改用户成功");
+ }
+
+ @GetMapping("/{id}")
+ public Result getUserById(@PathVariable("id") Integer id){
+ User user = userService.getUserById(id);
+ return Result.success(user);
+ }
+
+ @DeleteMapping("/{id}")
+ public Result deleteUserById(@PathVariable("id") Integer id){
+ userService.deleteUserById(id);
+ return Result.success("删除用户成功");
+ }
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/controller/UserRoleController.java b/x-admin/x-admin/src/main/java/com/lantu/sys/controller/UserRoleController.java
new file mode 100644
index 0000000..086e1c1
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/controller/UserRoleController.java
@@ -0,0 +1,18 @@
+package com.lantu.sys.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.stereotype.Controller;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@Controller
+@RequestMapping("/sys/userRole")
+public class UserRoleController {
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/entity/Equip.java b/x-admin/x-admin/src/main/java/com/lantu/sys/entity/Equip.java
new file mode 100644
index 0000000..ed116bc
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/entity/Equip.java
@@ -0,0 +1,103 @@
+package com.lantu.sys.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+
+import java.io.Serializable;
+
+/**
+ *
+ *
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@TableName("x_equip")
+@ApiModel(value = "Equip对象", description = "")
+public class Equip implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ @TableId(value = "id", type = IdType.AUTO)
+ private Integer id;
+ private String form;
+ private String focal;
+ private Integer status;
+ private Integer deleted;
+ private String x1;
+ private String x2;
+ private String x3;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+ public String getForm() {
+ return form;
+ }
+
+ public void setForm(String form) {
+ this.form = form;
+ }
+ public String getFocal() {
+ return focal;
+ }
+
+ public void setFocal(String focal) {
+ this.focal = focal;
+ }
+ public Integer getStatus() {
+ return status;
+ }
+
+ public void setStatus(Integer status) {
+ this.status = status;
+ }
+ public Integer getDeleted() {
+ return deleted;
+ }
+
+ public void setDeleted(Integer deleted) {
+ this.deleted = deleted;
+ }
+ public String getx1() {
+ return x1;
+ }
+
+ public void setx1(String x1) {
+ this.x1 = x1;
+ }
+ public String getx2() {
+ return x2;
+ }
+
+ public void setx2(String x2) {
+ this.x2 = x2;
+ }
+ public String getx3() {
+ return x3;
+ }
+
+ public void setx3(String x3) {
+ this.x3 = x3;
+ }
+
+ @Override
+ public String toString() {
+ return "Equip{" +
+ "id=" + id +
+ ", form=" + form +
+ ", focal=" + focal +
+ ", status=" + status +
+ ", deleted=" + deleted +
+ ", x1=" + x1 +
+ ", x2=" + x2 +
+ ", x3=" + x3 +
+ "}";
+ }
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/entity/Menu.java b/x-admin/x-admin/src/main/java/com/lantu/sys/entity/Menu.java
new file mode 100644
index 0000000..025cd09
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/entity/Menu.java
@@ -0,0 +1,59 @@
+package com.lantu.sys.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 com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ *
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@TableName("x_menu")
+@Data
+@ApiModel(value = "Menu对象", description = "")
+public class Menu implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "menu_id", type = IdType.AUTO)
+ private Integer menuId;
+ private String component;
+ private String path;
+ private String redirect;
+ private String name;
+ private String title;
+ private String icon;
+ private Integer parentId;
+ private String isLeaf;
+ private Boolean hidden;
+
+ @TableField(exist = false)
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private List children;
+
+ @TableField(exist = false)
+ private Map meta;
+ public Map getMeta(){
+ meta = new HashMap<>();
+ meta.put("title",title);
+ meta.put("icon",icon);
+ return meta;
+
+ }
+
+
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/entity/Role.java b/x-admin/x-admin/src/main/java/com/lantu/sys/entity/Role.java
new file mode 100644
index 0000000..9ba663f
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/entity/Role.java
@@ -0,0 +1,68 @@
+package com.lantu.sys.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 io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ *
+ *
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@TableName("x_role")
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@ApiModel(value = "Role对象", description = "")
+public class Role implements Serializable {
+ private static final long serialVersionUID = 1L;
+ @TableId(value = "role_id", type = IdType.AUTO)
+ private Integer roleId;
+ private String roleName;
+ private String roleDesc;
+
+ @TableField(exist = false)
+ private List menuIdList;
+
+ public Integer getRoleId() {
+ return roleId;
+ }
+
+ public void setRoleId(Integer roleId) {
+ this.roleId = roleId;
+ }
+ public String getRoleName() {
+ return roleName;
+ }
+
+ public void setRoleName(String roleName) {
+ this.roleName = roleName;
+ }
+ public String getRoleDesc() {
+ return roleDesc;
+ }
+
+ public void setRoleDesc(String roleDesc) {
+ this.roleDesc = roleDesc;
+ }
+
+ @Override
+ public String toString() {
+ return "Role{" +
+ "roleId=" + roleId +
+ ", roleName=" + roleName +
+ ", roleDesc=" + roleDesc +
+ "}";
+ }
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/entity/RoleMenu.java b/x-admin/x-admin/src/main/java/com/lantu/sys/entity/RoleMenu.java
new file mode 100644
index 0000000..523d5d5
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/entity/RoleMenu.java
@@ -0,0 +1,68 @@
+package com.lantu.sys.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *
+ *
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@TableName("x_role_menu")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ApiModel(value = "RoleMenu对象", description = "")
+public class RoleMenu implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "id", type = IdType.AUTO)
+ private Integer id;
+ private Integer roleId;
+ private Integer menuId;
+
+
+
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+ public Integer getRoleId() {
+ return roleId;
+ }
+
+ public void setRoleId(Integer roleId) {
+ this.roleId = roleId;
+ }
+ public Integer getMenuId() {
+ return menuId;
+ }
+
+ public void setMenuId(Integer menuId) {
+ this.menuId = menuId;
+ }
+
+ @Override
+ public String toString() {
+ return "RoleMenu{" +
+ "id=" + id +
+ ", roleId=" + roleId +
+ ", menuId=" + menuId +
+ "}";
+ }
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/entity/User.java b/x-admin/x-admin/src/main/java/com/lantu/sys/entity/User.java
new file mode 100644
index 0000000..fa7e56a
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/entity/User.java
@@ -0,0 +1,108 @@
+package com.lantu.sys.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 io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ *
+ *
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@TableName("x_user")
+@Data
+@ApiModel(value = "User对象", description = "")
+public class User implements Serializable {
+ private static final long serialVersionUID = 1L;
+ @TableId(value = "id", type = IdType.AUTO)
+ private Integer id;
+ private String username;
+ private String password;
+ private String email;
+ private String phone;
+ private Integer status;
+ private String avatar;
+ private Integer deleted;
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+ public Integer getStatus() {
+ return status;
+ }
+
+ public void setStatus(Integer status) {
+ this.status = status;
+ }
+ public String getAvatar() {
+ return avatar;
+ }
+
+ public void setAvatar(String avatar) {
+ this.avatar = avatar;
+ }
+ public Integer getDeleted() {
+ return deleted;
+ }
+
+ public void setDeleted(Integer deleted) {
+ this.deleted = deleted;
+ }
+
+ @Override
+ public String toString() {
+ return "User{" +
+ "id=" + id +
+ ", username=" + username +
+ ", password=" + password +
+ ", email=" + email +
+ ", phone=" + phone +
+ ", status=" + status +
+ ", avatar=" + avatar +
+ ", deleted=" + deleted +
+ "}";
+ }
+
+ @TableField(exist = false)
+ private List roleIdList;
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/entity/UserRole.java b/x-admin/x-admin/src/main/java/com/lantu/sys/entity/UserRole.java
new file mode 100644
index 0000000..df816df
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/entity/UserRole.java
@@ -0,0 +1,63 @@
+package com.lantu.sys.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *
+ *
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@TableName("x_user_role")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ApiModel(value = "UserRole对象", description = "")
+public class UserRole implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ @TableId(value = "id", type = IdType.AUTO)
+ private Integer id;
+ private Integer userId;
+ private Integer roleId;
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+ public Integer getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Integer userId) {
+ this.userId = userId;
+ }
+ public Integer getRoleId() {
+ return roleId;
+ }
+
+ public void setRoleId(Integer roleId) {
+ this.roleId = roleId;
+ }
+
+ @Override
+ public String toString() {
+ return "UserRole{" +
+ "id=" + id +
+ ", userId=" + userId +
+ ", roleId=" + roleId +
+ "}";
+ }
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/EquipMapper.java b/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/EquipMapper.java
new file mode 100644
index 0000000..7048410
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/EquipMapper.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.mapper;
+
+import com.lantu.sys.entity.Equip;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface EquipMapper extends BaseMapper {
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/MenuMapper.java b/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/MenuMapper.java
new file mode 100644
index 0000000..a165d1c
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/MenuMapper.java
@@ -0,0 +1,20 @@
+package com.lantu.sys.mapper;
+
+import com.lantu.sys.entity.Menu;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+public interface MenuMapper extends BaseMapper {
+ public List getMenuListByUserId(@Param("userId") Integer userdId, @Param("pid") Integer pid);
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/RoleMapper.java b/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/RoleMapper.java
new file mode 100644
index 0000000..fd08b8b
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/RoleMapper.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.mapper;
+
+import com.lantu.sys.entity.Role;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+public interface RoleMapper extends BaseMapper {
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/RoleMenuMapper.java b/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/RoleMenuMapper.java
new file mode 100644
index 0000000..5ff3094
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/RoleMenuMapper.java
@@ -0,0 +1,19 @@
+package com.lantu.sys.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.lantu.sys.entity.RoleMenu;
+
+import java.util.List;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+public interface RoleMenuMapper extends BaseMapper {
+ public List getMenuIdListByRoleId(Integer roleId);
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/UserMapper.java b/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/UserMapper.java
new file mode 100644
index 0000000..3289f19
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/UserMapper.java
@@ -0,0 +1,19 @@
+package com.lantu.sys.mapper;
+
+import com.lantu.sys.entity.User;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import java.util.List;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+public interface UserMapper extends BaseMapper {
+ public List getRoleNameByUserId(Integer userId);
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/UserRoleMapper.java b/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/UserRoleMapper.java
new file mode 100644
index 0000000..0332ea8
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/mapper/UserRoleMapper.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.mapper;
+
+import com.lantu.sys.entity.UserRole;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+public interface UserRoleMapper extends BaseMapper {
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/service/IEquipService.java b/x-admin/x-admin/src/main/java/com/lantu/sys/service/IEquipService.java
new file mode 100644
index 0000000..7918837
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/service/IEquipService.java
@@ -0,0 +1,17 @@
+package com.lantu.sys.service;
+
+import com.lantu.sys.entity.Equip;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+public interface IEquipService extends IService {
+
+ void addEquip(Equip equip);
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/service/IMenuService.java b/x-admin/x-admin/src/main/java/com/lantu/sys/service/IMenuService.java
new file mode 100644
index 0000000..9a3a82c
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/service/IMenuService.java
@@ -0,0 +1,20 @@
+package com.lantu.sys.service;
+
+import com.lantu.sys.entity.Menu;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+public interface IMenuService extends IService {
+
+ List getAllMenu();
+ List getMenuListByUserId(Integer userId);
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/service/IRoleMenuService.java b/x-admin/x-admin/src/main/java/com/lantu/sys/service/IRoleMenuService.java
new file mode 100644
index 0000000..24c54a8
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/service/IRoleMenuService.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.service;
+
+import com.lantu.sys.entity.RoleMenu;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+public interface IRoleMenuService extends IService {
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/service/IRoleService.java b/x-admin/x-admin/src/main/java/com/lantu/sys/service/IRoleService.java
new file mode 100644
index 0000000..9f41d23
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/service/IRoleService.java
@@ -0,0 +1,23 @@
+package com.lantu.sys.service;
+
+import com.lantu.sys.entity.Role;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+public interface IRoleService extends IService {
+
+ void addRole(Role role);
+
+ Role getRoleById(Integer id);
+
+ void updateRole(Role role);
+
+ void deleteRoleById(Integer id);
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/service/IUserRoleService.java b/x-admin/x-admin/src/main/java/com/lantu/sys/service/IUserRoleService.java
new file mode 100644
index 0000000..d85bcf6
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/service/IUserRoleService.java
@@ -0,0 +1,16 @@
+package com.lantu.sys.service;
+
+import com.lantu.sys.entity.UserRole;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+public interface IUserRoleService extends IService {
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/service/IUserService.java b/x-admin/x-admin/src/main/java/com/lantu/sys/service/IUserService.java
new file mode 100644
index 0000000..e9e236b
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/service/IUserService.java
@@ -0,0 +1,31 @@
+package com.lantu.sys.service;
+
+import com.lantu.sys.entity.User;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.Map;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+public interface IUserService extends IService {
+
+ Map login(User user);
+
+ Map getUserInfo(String token);
+
+ void logout(String token);
+
+ void addUser(User user);
+
+ User getUserById(Integer id);
+
+ void updateUser(User user);
+
+ void deleteUserById(Integer id);
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/EquipServiceImpl.java b/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/EquipServiceImpl.java
new file mode 100644
index 0000000..048c25f
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/EquipServiceImpl.java
@@ -0,0 +1,26 @@
+package com.lantu.sys.service.impl;
+
+import com.lantu.sys.entity.Equip;
+import com.lantu.sys.mapper.EquipMapper;
+import com.lantu.sys.service.IEquipService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author cyf
+ * @since 2023-11-15
+ */
+@Service
+public class EquipServiceImpl extends ServiceImpl implements IEquipService {
+
+ @Override
+ @Transactional
+ public void addEquip(Equip equip) {
+ this.baseMapper.insert(equip);
+ }
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/MenuServiceImpl.java b/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/MenuServiceImpl.java
new file mode 100644
index 0000000..0eab458
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/MenuServiceImpl.java
@@ -0,0 +1,71 @@
+package com.lantu.sys.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.lantu.sys.entity.Menu;
+import com.lantu.sys.mapper.MenuMapper;
+import com.lantu.sys.service.IMenuService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@Service
+public class MenuServiceImpl extends ServiceImpl implements IMenuService {
+
+
+ @Override
+ public List getAllMenu() {
+ //一级菜单
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(Menu::getParentId, 0);
+ List menuList = this.list(wrapper);
+ //填充子菜单
+ setMenuChildren(menuList);
+
+ return menuList;
+ }
+
+
+
+ private void setMenuChildren(List menuList) {
+ if (menuList != null){
+ for (Menu menu: menuList) {
+ LambdaQueryWrapper subWrapper = new LambdaQueryWrapper<>();
+ subWrapper.eq(Menu::getParentId, menu.getMenuId());
+ List subMenuList = this.list(subWrapper);
+ menu.setChildren(subMenuList);
+ //递归
+ setMenuChildren(subMenuList);
+ }
+ }
+ }
+ @Override
+ public List getMenuListByUserId(Integer userId) {
+ //一级菜单
+ List menuList = this.baseMapper.getMenuListByUserId(userId, 0);
+ //子菜单
+ setMenuChildrenByUserId(userId, menuList);
+
+ return menuList;
+ }
+
+ private void setMenuChildrenByUserId(Integer userId, List menuList) {
+ if (null != menuList){
+ for (Menu menu : menuList){
+ List subMenuList = this.baseMapper.getMenuListByUserId(userId, menu.getMenuId());
+ menu.setChildren(subMenuList);
+ //递归
+ setMenuChildrenByUserId(userId, subMenuList);
+ }
+
+ }
+ }
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/RoleMenuServiceImpl.java b/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/RoleMenuServiceImpl.java
new file mode 100644
index 0000000..c50d263
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/RoleMenuServiceImpl.java
@@ -0,0 +1,20 @@
+package com.lantu.sys.service.impl;
+
+import com.lantu.sys.entity.RoleMenu;
+import com.lantu.sys.mapper.RoleMenuMapper;
+import com.lantu.sys.service.IRoleMenuService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@Service
+public class RoleMenuServiceImpl extends ServiceImpl implements IRoleMenuService {
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/RoleServiceImpl.java b/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/RoleServiceImpl.java
new file mode 100644
index 0000000..6f1839c
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/RoleServiceImpl.java
@@ -0,0 +1,78 @@
+package com.lantu.sys.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.lantu.sys.entity.Role;
+import com.lantu.sys.entity.RoleMenu;
+import com.lantu.sys.mapper.RoleMapper;
+import com.lantu.sys.mapper.RoleMenuMapper;
+import com.lantu.sys.service.IRoleService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@Service
+public class RoleServiceImpl extends ServiceImpl implements IRoleService {
+
+ @Resource
+ private RoleMenuMapper roleMenuMapper;
+
+ @Override
+ @Transactional
+ public void addRole(Role role) {
+ //写入角色表
+ this.baseMapper.insert(role);
+ //写入角色菜单关系表
+ if (null != role.getMenuIdList()) {
+ for (Integer menuId : role.getMenuIdList()) {
+ roleMenuMapper.insert(new RoleMenu(null, role.getRoleId(), menuId));
+ }
+ }
+ }
+
+ @Override
+ public Role getRoleById(Integer id) {
+ Role role = this.baseMapper.selectById(id);
+ List menuIdList = roleMenuMapper.getMenuIdListByRoleId(id);
+ role.setMenuIdList(menuIdList);
+ return role;
+ }
+
+ @Override
+ @Transactional
+ public void updateRole(Role role) {
+ //修改角色表
+ this.baseMapper.updateById(role);
+ //删除原有权限
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(RoleMenu::getRoleId, role.getRoleId());
+ roleMenuMapper.delete(wrapper);
+ //新增权限
+ if (null != role.getMenuIdList()) {
+ for (Integer menuId : role.getMenuIdList()) {
+ roleMenuMapper.insert(new RoleMenu(null, role.getRoleId(), menuId));
+ }
+
+
+ }
+ }
+
+ @Override
+ public void deleteRoleById(Integer id) {
+ this.baseMapper.deleteById(id);
+ //删除权限
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(RoleMenu::getRoleId, id);
+ roleMenuMapper.delete(wrapper);
+ }
+}
\ No newline at end of file
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/UserRoleServiceImpl.java b/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/UserRoleServiceImpl.java
new file mode 100644
index 0000000..06fbec3
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/UserRoleServiceImpl.java
@@ -0,0 +1,20 @@
+package com.lantu.sys.service.impl;
+
+import com.lantu.sys.entity.UserRole;
+import com.lantu.sys.mapper.UserRoleMapper;
+import com.lantu.sys.service.IUserRoleService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@Service
+public class UserRoleServiceImpl extends ServiceImpl implements IUserRoleService {
+
+}
diff --git a/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/UserServiceImpl.java b/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..d8fdc68
--- /dev/null
+++ b/x-admin/x-admin/src/main/java/com/lantu/sys/service/impl/UserServiceImpl.java
@@ -0,0 +1,188 @@
+package com.lantu.sys.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.lantu.common.utils.JwtUtil;
+import com.lantu.sys.entity.Menu;
+import com.lantu.sys.entity.User;
+import com.lantu.sys.entity.UserRole;
+import com.lantu.sys.mapper.UserMapper;
+import com.lantu.sys.mapper.UserRoleMapper;
+import com.lantu.sys.service.IMenuService;
+import com.lantu.sys.service.IUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author cyf
+ * @since 2023-10-08
+ */
+@Service
+public class UserServiceImpl extends ServiceImpl implements IUserService {
+
+ @Autowired
+ private RedisTemplate redisTemplate;
+
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @Autowired
+ private IMenuService menuService;
+
+ @Autowired
+ private JwtUtil jwtUtil;
+
+ @Autowired
+ private UserRoleMapper userRoleMapper;
+ @Override
+ public Map login(User user) {
+ //根据用户名和密码查询
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(User::getUsername,user.getUsername());
+ User loginUser = this.baseMapper.selectOne(wrapper);
+ //结果不为空,并且密码和传入密码是匹配的,则生成token,并将用户信息存入redis
+ if (loginUser != null && passwordEncoder.matches(user.getPassword(), loginUser.getPassword())){
+ // 暂时用UUID,终极方案是jwt
+// String key = "user:" + UUID.randomUUID();
+
+ // 存入redis
+ loginUser.setPassword(null);
+// redisTemplate.opsForValue().set(key,loginUser,30, TimeUnit.MINUTES);
+ String token = jwtUtil.createToken(loginUser);
+ //返回数据
+ Map data = new HashMap<>();
+ data.put("token",token);
+ return data;
+ }
+ return null;
+ }
+// @Override
+// public Map login(User user) {
+// //根据用户名和密码查询
+// LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+// wrapper.eq(User::getUsername,user.getUsername());
+// wrapper.eq(User::getPassword,user.getPassword());
+// User loginUser = this.baseMapper.selectOne(wrapper);
+// //结果不为空,则生成token,并将用户信息存入redis
+// if (loginUser != null){
+// // 暂时用UUID,终极方案是jwt
+// String key = "user:" + UUID.randomUUID();
+// // 存入redis
+// loginUser.setPassword(null);
+// redisTemplate.opsForValue().set(key,loginUser,30, TimeUnit.MINUTES);
+//
+// //返回数据
+// Map data = new HashMap<>();
+// data.put("token",key);
+// return data;
+// }
+// return null;
+// }
+
+ @Override
+ public Map getUserInfo(String token) {
+ //根据token获取用户信息,redis
+// Object obj = redisTemplate.opsForValue().get(token);
+ User loginUser = null;
+ try {
+ loginUser = jwtUtil.parseToken(token, User.class);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (loginUser != null){
+// User loginUser = JSON.parseObject(JSON.toJSONString(obj),User.class);
+ Map data = new HashMap<>();
+ data.put("name", loginUser.getUsername());
+ data.put("avatar", loginUser.getAvatar());
+ //角色
+ List rolelist = this.baseMapper.getRoleNameByUserId(loginUser.getId());
+ data.put("roles",rolelist);
+
+ //权限列表
+ List menuList = menuService.getMenuListByUserId(loginUser.getId());
+ data.put("menuList",menuList);
+
+ return data;
+
+ }
+ return null;
+ }
+
+ @Override
+ public void logout(String token) {
+
+// redisTemplate.delete(token);
+ }
+
+ @Override
+ @Transactional
+ public void addUser(User user) {
+ // 写入用户表
+ this.baseMapper.insert(user);
+ //写入用户角色表
+ List roleIdList = user.getRoleIdList();
+ if (roleIdList != null){
+ for (Integer roleId : roleIdList) {
+ userRoleMapper.insert(new UserRole(null, user.getId(), roleId));
+ }
+ }
+
+ }
+
+ @Override
+ public User getUserById(Integer id) {
+ User user = this.baseMapper.selectById(id);
+
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(UserRole::getUserId, id);
+ List userRoleList = userRoleMapper.selectList(wrapper);
+
+ List roleIdList = userRoleList.stream()
+ .map(userRole -> {return userRole.getRoleId();})
+ .collect(Collectors.toList());
+ user.setRoleIdList(roleIdList);
+ return user;
+ }
+
+ @Override
+ @Transactional
+ public void updateUser(User user) {
+ //更新用户表
+ this.baseMapper.updateById(user);
+ //删除原有角色
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(UserRole::getUserId, user.getId());
+ userRoleMapper.delete(wrapper);
+ //设置新角色
+ List roleIdList = user.getRoleIdList();
+ if (roleIdList != null){
+ for (Integer roleId : roleIdList) {
+ userRoleMapper.insert(new UserRole(null, user.getId(), roleId));
+ }
+ }
+
+ }
+
+ @Override
+ public void deleteUserById(Integer id) {
+ this.baseMapper.deleteById(id);
+ //删除原有角色
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.eq(UserRole::getUserId, id);
+ userRoleMapper.delete(wrapper);
+ }
+
+}
diff --git a/x-admin/x-admin/src/main/resources/application.yml b/x-admin/x-admin/src/main/resources/application.yml
new file mode 100644
index 0000000..a0fc8ce
--- /dev/null
+++ b/x-admin/x-admin/src/main/resources/application.yml
@@ -0,0 +1,25 @@
+server:
+ port: 9999
+
+spring:
+ datasource:
+ username: root
+ password: 123456
+ url: jdbc:mysql:///xdb
+ redis:
+ port: 6379
+ host: localhost
+logging:
+ level:
+ com.lantu: debug
+
+#mybatis-plus:
+# mapper-locations:
+# classpath: mappersys\*.xml
+mybatis-plus:
+ global-config:
+ db-config:
+ logic-delete-field: deleted
+ logic-not-delete-value: 0
+ logic-delete-value: 1
+ type-aliases-package: com.lantu.*.entity
\ No newline at end of file
diff --git a/x-admin/x-admin/src/main/resources/mapper/sys/EquipMapper.xml b/x-admin/x-admin/src/main/resources/mapper/sys/EquipMapper.xml
new file mode 100644
index 0000000..dd169e3
--- /dev/null
+++ b/x-admin/x-admin/src/main/resources/mapper/sys/EquipMapper.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/x-admin/x-admin/src/main/resources/mapper/sys/MenuMapper.xml b/x-admin/x-admin/src/main/resources/mapper/sys/MenuMapper.xml
new file mode 100644
index 0000000..7f96635
--- /dev/null
+++ b/x-admin/x-admin/src/main/resources/mapper/sys/MenuMapper.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
diff --git a/x-admin/x-admin/src/main/resources/mapper/sys/RoleMapper.xml b/x-admin/x-admin/src/main/resources/mapper/sys/RoleMapper.xml
new file mode 100644
index 0000000..211ff02
--- /dev/null
+++ b/x-admin/x-admin/src/main/resources/mapper/sys/RoleMapper.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/x-admin/x-admin/src/main/resources/mapper/sys/RoleMenuMapper.xml b/x-admin/x-admin/src/main/resources/mapper/sys/RoleMenuMapper.xml
new file mode 100644
index 0000000..81e8dad
--- /dev/null
+++ b/x-admin/x-admin/src/main/resources/mapper/sys/RoleMenuMapper.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/x-admin/x-admin/src/main/resources/mapper/sys/UserMapper.xml b/x-admin/x-admin/src/main/resources/mapper/sys/UserMapper.xml
new file mode 100644
index 0000000..77c4fd3
--- /dev/null
+++ b/x-admin/x-admin/src/main/resources/mapper/sys/UserMapper.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ SELECT
+ b.role_name
+ FROM x_user_role a, x_role b
+ WHERE
+ a.role_id = b.role_id
+ AND a.user_id = #{userId}
+
+
+
diff --git a/x-admin/x-admin/src/main/resources/mapper/sys/UserRoleMapper.xml b/x-admin/x-admin/src/main/resources/mapper/sys/UserRoleMapper.xml
new file mode 100644
index 0000000..fd92297
--- /dev/null
+++ b/x-admin/x-admin/src/main/resources/mapper/sys/UserRoleMapper.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/x-admin/x-admin/src/test/java/com/lantu/CodeGenerator.java b/x-admin/x-admin/src/test/java/com/lantu/CodeGenerator.java
new file mode 100644
index 0000000..75e02ea
--- /dev/null
+++ b/x-admin/x-admin/src/test/java/com/lantu/CodeGenerator.java
@@ -0,0 +1,40 @@
+package com.lantu;
+
+import com.baomidou.mybatisplus.generator.FastAutoGenerator;
+import com.baomidou.mybatisplus.generator.config.OutputFile;
+import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
+
+import java.util.Collections;
+
+/**
+ * 作者:cyf
+ * 描述:无
+ */
+public class CodeGenerator {
+ public static void main(String[] args) {
+ String url = "jdbc:mysql:///xdb";
+ String username = "root";
+ String password = "123456";
+ String moduleName = "sys";
+ String tables = "x_user,x_role,x_menu,x_user_role,x_role_menu,x_equip";
+ String mapperlocation = "D:\\pingtai\\x-admin\\x-admin\\src\\main\\resources\\mapper\\" + moduleName;
+ FastAutoGenerator.create(url, username, password)
+ .globalConfig(builder -> {
+ builder.author("cyf") // 设置作者
+ .enableSwagger() // 开启 swagger 模式
+// .fileOverride() // 覆盖已生成文件
+ .outputDir("D:\\pingtai\\x-admin\\x-admin\\codes"); // 指定输出目录
+ })
+ .packageConfig(builder -> {
+ builder.parent("com.lantu") // 设置父包名
+ .moduleName(moduleName) // 设置父包模块名
+ .pathInfo(Collections.singletonMap(OutputFile.xml, mapperlocation)); // 设置mapperXml生成路径
+ })
+ .strategyConfig(builder -> {
+ builder.addInclude(tables) // 设置需要生成的表名
+ .addTablePrefix("x_"); // 设置过滤表前缀
+ })
+ .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
+ .execute();
+ }
+}