mirror of https://gitee.com/xiaonuobase/snowy
parent
b2da2975f4
commit
92adbfb5a1
|
@ -12,7 +12,7 @@
|
||||||
.app-loading__logo {margin-bottom: 30px;}
|
.app-loading__logo {margin-bottom: 30px;}
|
||||||
.app-loading__logo img {width: 90px;vertical-align: bottom;}
|
.app-loading__logo img {width: 90px;vertical-align: bottom;}
|
||||||
.app-loading__title {font-size: 24px;color: #333;margin-top: 30px;}
|
.app-loading__title {font-size: 24px;color: #333;margin-top: 30px;}
|
||||||
.h-full { height: 100% }
|
.app-main { height: 100% }
|
||||||
@keyframes loader {
|
@keyframes loader {
|
||||||
0% {
|
0% {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
<strong>We're sorry but Snowy2.0 doesn't work properly without JavaScript
|
<strong>We're sorry but Snowy2.0 doesn't work properly without JavaScript
|
||||||
enabled. Please enable it to continue.</strong>
|
enabled. Please enable it to continue.</strong>
|
||||||
</noscript>
|
</noscript>
|
||||||
<div id="app" class="h-full"></div>
|
<div id="app" class="app-main"></div>
|
||||||
<script type="module" src="/src/main.js"></script>
|
<script type="module" src="/src/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 243 KiB |
Binary file not shown.
Before Width: | Height: | Size: 122 KiB |
Binary file not shown.
Before Width: | Height: | Size: 82 KiB |
Binary file not shown.
Before Width: | Height: | Size: 78 KiB |
|
@ -415,9 +415,12 @@
|
||||||
} else {
|
} else {
|
||||||
data.localDataSource = r.records
|
data.localDataSource = r.records
|
||||||
}
|
}
|
||||||
data.localLoading = false
|
|
||||||
getTableProps()
|
getTableProps()
|
||||||
})
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
.finally(() => {
|
||||||
|
data.localLoading = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
<div class="right-menu-item" @click="closeOtherTabs">
|
<div class="right-menu-item" @click="closeOtherTabs">
|
||||||
<close-outlined class="snowy-header-tags-right" />
|
<close-outlined class="snowy-header-tags-right" />
|
||||||
<div class="pl-3 snowy-header-tags-right-font">关闭其他标签</div>
|
<div class="pl-3 snowy-header-tags-right-font">关闭其他</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="right-menu-item" @click="maximize">
|
<div class="right-menu-item" @click="maximize">
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="right-menu-item" @click="openWindow">
|
<div class="right-menu-item" @click="openWindow">
|
||||||
<select-outlined class="snowy-header-tags-right" />
|
<select-outlined class="snowy-header-tags-right" />
|
||||||
<div class="pl-3 snowy-header-tags-right-font">新窗口打开</div>
|
<div class="pl-3 snowy-header-tags-right-font">新窗口</div>
|
||||||
</div>
|
</div>
|
||||||
</xn-context-menu>
|
</xn-context-menu>
|
||||||
<a-tabs
|
<a-tabs
|
||||||
|
@ -366,7 +366,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 10px 20px;
|
padding: 10px 10px;
|
||||||
color: #333;
|
color: #333;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -433,7 +433,7 @@
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
.snowy-header-tags-right {
|
.snowy-header-tags-right {
|
||||||
margin-right: 10px;
|
margin-right: 5px;
|
||||||
color: var(--font-color);
|
color: var(--font-color);
|
||||||
}
|
}
|
||||||
.snowy-header-tags-right-font {
|
.snowy-header-tags-right-font {
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { globalStore, keepAliveStore } from '@/store'
|
import { globalStore, keepAliveStore, viewTagsStore } from '@/store'
|
||||||
import { themeEnum } from '@/layout/enum/themeEnum'
|
import { themeEnum } from '@/layout/enum/themeEnum'
|
||||||
import { layoutEnum } from '@/layout/enum/layoutEnum'
|
import { layoutEnum } from '@/layout/enum/layoutEnum'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
@ -82,6 +82,8 @@
|
||||||
import DoubleRowMenu from '@/layout/menu/doubleRowMenu.vue'
|
import DoubleRowMenu from '@/layout/menu/doubleRowMenu.vue'
|
||||||
import TopMenu from '@/layout/menu/topMenu.vue'
|
import TopMenu from '@/layout/menu/topMenu.vue'
|
||||||
import { NextLoading } from '@/utils/loading'
|
import { NextLoading } from '@/utils/loading'
|
||||||
|
import { useMenuStore } from '@/store/menu'
|
||||||
|
import { userStore } from '@/store/user'
|
||||||
|
|
||||||
const store = globalStore()
|
const store = globalStore()
|
||||||
const kStore = keepAliveStore()
|
const kStore = keepAliveStore()
|
||||||
|
@ -156,7 +158,13 @@
|
||||||
})
|
})
|
||||||
// 路由监听高亮
|
// 路由监听高亮
|
||||||
const showThis = () => {
|
const showThis = () => {
|
||||||
pMenu.value = route.meta.breadcrumb ? route.meta.breadcrumb[0] : {}
|
// route是一个只读路由对象。需要使用 useRouter 函数来获取路由实例
|
||||||
|
router.getRoutes().filter((item) => {
|
||||||
|
if (item.path === route.path) {
|
||||||
|
pMenu.value = item.meta.breadcrumb ? item.meta.breadcrumb[0] : {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// pMenu.value = route.meta.breadcrumb ? route.meta.breadcrumb[0] : {}
|
||||||
// 展开的
|
// 展开的
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
// 取得默认路由地址并设置展开
|
// 取得默认路由地址并设置展开
|
||||||
|
@ -199,26 +207,39 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const init = () => {
|
||||||
// 执行-start
|
// 执行-start
|
||||||
moduleMenu.value = router.getMenu()
|
moduleMenu.value = router.getMenu()
|
||||||
// 获取缓存中的菜单模块是哪个
|
// 获取缓存中的菜单模块是哪个
|
||||||
const menuModuleId = tool.data.get('SNOWY_MENU_MODULE_ID')
|
const menuModuleId = tool.data.get('SNOWY_MENU_MODULE_ID')
|
||||||
if (menuModuleId) {
|
if (menuModuleId) {
|
||||||
// 防止切换一个无此应用的人
|
// 防止切换一个无此应用的人
|
||||||
const module = router.getMenu().filter((item) => item.id === menuModuleId)
|
const module = router.getMenu().filter((item) => item.id === menuModuleId)
|
||||||
if (module.length > 0) {
|
if (module.length > 0) {
|
||||||
menu.value = module[0].children
|
menu.value = module[0].children
|
||||||
|
} else {
|
||||||
|
menu.value = router.getMenu()[0].children
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
menu.value = router.getMenu()[0].children
|
menu.value = router.getMenu()[0].children
|
||||||
}
|
}
|
||||||
} else {
|
showThis()
|
||||||
menu.value = router.getMenu()[0].children
|
|
||||||
}
|
}
|
||||||
showThis()
|
|
||||||
|
watchEffect(() => {
|
||||||
|
const menuStore = useMenuStore()
|
||||||
|
if (menuStore.refreshFlag) {
|
||||||
|
init()
|
||||||
|
// 更新标签
|
||||||
|
viewTagsStore().updateOrRemoveViewTags(router.getRoutes())
|
||||||
|
menuStore.changeRefreshFlag(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 取消loading
|
// 取消loading
|
||||||
NextLoading.done()
|
NextLoading.done()
|
||||||
|
showThis()
|
||||||
onLayoutResize()
|
onLayoutResize()
|
||||||
window.addEventListener('resize', onLayoutResize)
|
window.addEventListener('resize', onLayoutResize)
|
||||||
window.addEventListener('resize', getNav)
|
window.addEventListener('resize', getNav)
|
||||||
|
@ -227,6 +248,8 @@
|
||||||
settingFixedWidth()
|
settingFixedWidth()
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
getNav(menu.value)
|
getNav(menu.value)
|
||||||
|
// 刷新登录信息,不影响其他
|
||||||
|
userStore().refreshUserLoginUserInfo()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
// 动态获取横向导航栏隐藏数量
|
// 动态获取横向导航栏隐藏数量
|
||||||
|
|
|
@ -8,11 +8,13 @@
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
import { useMenuStore } from '@/store/menu'
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const gohome = () => {
|
const gohome = () => {
|
||||||
location.href = '/'
|
location.href = '/'
|
||||||
}
|
}
|
||||||
const goback = () => {
|
const goback = () => {
|
||||||
router.go(-1)
|
router.go(-1)
|
||||||
|
useMenuStore().changeRefreshFlag(true)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -18,9 +18,9 @@ import whiteListRouters from './whiteList'
|
||||||
import userRoutes from '@/config/route'
|
import userRoutes from '@/config/route'
|
||||||
import tool from '@/utils/tool'
|
import tool from '@/utils/tool'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
const modules = import.meta.glob('/src/views/**/**.vue')
|
import { globalStore } from '@/store'
|
||||||
import { globalStore, searchStore } from '@/store'
|
|
||||||
import { NextLoading } from '@/utils/loading'
|
import { NextLoading } from '@/utils/loading'
|
||||||
|
import { useMenuStore } from '@/store/menu'
|
||||||
|
|
||||||
// 进度条配置
|
// 进度条配置
|
||||||
NProgress.configure({ showSpinner: false, speed: 500 })
|
NProgress.configure({ showSpinner: false, speed: 500 })
|
||||||
|
@ -72,13 +72,21 @@ router.beforeEach(async (to, from, next) => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isGetRouter.value) {
|
||||||
|
// 初始化菜单加载,代码位置不能变动
|
||||||
|
const menuStore = useMenuStore()
|
||||||
|
menuStore.refreshMenu()
|
||||||
|
isGetRouter.value = true
|
||||||
|
next({ ...to, replace: true })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
const token = tool.data.get('TOKEN')
|
const token = tool.data.get('TOKEN')
|
||||||
|
|
||||||
// 页面刷新,加载loading
|
// 页面刷新,加载loading
|
||||||
if (from.path === '/' && to.path !== '/login' && !window.nextLoading && token) {
|
if (from.path === '/' && to.path !== '/login' && !window.nextLoading && token) {
|
||||||
NextLoading.start()
|
NextLoading.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to.path === '/login') {
|
if (to.path === '/login') {
|
||||||
// 当用户输入了login路由,将其跳转首页即可
|
// 当用户输入了login路由,将其跳转首页即可
|
||||||
if (token) {
|
if (token) {
|
||||||
|
@ -89,7 +97,6 @@ router.beforeEach(async (to, from, next) => {
|
||||||
}
|
}
|
||||||
// 删除路由(替换当前layout路由)
|
// 删除路由(替换当前layout路由)
|
||||||
router.addRoute(routes[0])
|
router.addRoute(routes[0])
|
||||||
isGetRouter.value = false
|
|
||||||
next()
|
next()
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
|
@ -108,27 +115,6 @@ router.beforeEach(async (to, from, next) => {
|
||||||
if (to.meta.fullpage) {
|
if (to.meta.fullpage) {
|
||||||
to.matched = [to.matched[to.matched.length - 1]]
|
to.matched = [to.matched[to.matched.length - 1]]
|
||||||
}
|
}
|
||||||
// 加载动态/静态路由
|
|
||||||
if (!isGetRouter.value) {
|
|
||||||
const apiMenu = tool.data.get('MENU') || []
|
|
||||||
if (apiMenu.length === 0) {
|
|
||||||
// 创建默认模块,显示默认菜单
|
|
||||||
apiMenu[0] = cloneDeep(userRoutes.module[0])
|
|
||||||
}
|
|
||||||
const childrenApiMenu = apiMenu[0].children
|
|
||||||
apiMenu[0].children = [...(childrenApiMenu ? childrenApiMenu : []), ...userRoutes.menu]
|
|
||||||
let menuRouter = filterAsyncRouter(apiMenu)
|
|
||||||
menuRouter = flatAsyncRoutes(menuRouter)
|
|
||||||
menuRouter.forEach((item) => {
|
|
||||||
router.addRoute('layout', item)
|
|
||||||
})
|
|
||||||
|
|
||||||
const search_store = searchStore()
|
|
||||||
search_store.init(menuRouter)
|
|
||||||
isGetRouter.value = true
|
|
||||||
next({ ...to, replace: true })
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
beforeEach(to, from)
|
beforeEach(to, from)
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
|
@ -150,7 +136,8 @@ router.onError((error) => {
|
||||||
|
|
||||||
// 入侵追加自定义方法、对象
|
// 入侵追加自定义方法、对象
|
||||||
router.getMenu = () => {
|
router.getMenu = () => {
|
||||||
let apiMenu = tool.data.get('MENU') || []
|
const menuStore = useMenuStore()
|
||||||
|
let apiMenu = menuStore.menuData.value || tool.data.get('MENU') || []
|
||||||
// 增加固定路由
|
// 增加固定路由
|
||||||
if (apiMenu.length === 0) {
|
if (apiMenu.length === 0) {
|
||||||
// 创建默认模块,显示默认菜单
|
// 创建默认模块,显示默认菜单
|
||||||
|
@ -182,64 +169,4 @@ const filterUrl = (map) => {
|
||||||
return newMap
|
return newMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// 转换
|
|
||||||
const filterAsyncRouter = (routerMap) => {
|
|
||||||
const accessedRouters = []
|
|
||||||
routerMap.forEach((item) => {
|
|
||||||
item.meta = item.meta ? item.meta : {}
|
|
||||||
// 处理外部链接特殊路由
|
|
||||||
if (item.meta.type === 'iframe') {
|
|
||||||
item.meta.url = item.path
|
|
||||||
item.path = `/${item.name}`
|
|
||||||
}
|
|
||||||
// MAP转路由对象
|
|
||||||
const route = {
|
|
||||||
path: item.path,
|
|
||||||
name: item.name,
|
|
||||||
meta: item.meta,
|
|
||||||
redirect: item.redirect,
|
|
||||||
children: item.children ? filterAsyncRouter(item.children) : null,
|
|
||||||
component: loadComponent(item.component)
|
|
||||||
}
|
|
||||||
accessedRouters.push(route)
|
|
||||||
})
|
|
||||||
return accessedRouters
|
|
||||||
}
|
|
||||||
const loadComponent = (component) => {
|
|
||||||
if (component) {
|
|
||||||
if (component.includes('/')) {
|
|
||||||
return modules[`/src/views/${component}.vue`]
|
|
||||||
}
|
|
||||||
return modules[`/src/views/${component}/index.vue`]
|
|
||||||
} else {
|
|
||||||
return () => import(/* @vite-ignore */ `/src/layout/other/empty.vue`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 路由扁平化
|
|
||||||
const flatAsyncRoutes = (routes, breadcrumb = []) => {
|
|
||||||
const res = []
|
|
||||||
routes.forEach((route) => {
|
|
||||||
const tmp = { ...route }
|
|
||||||
if (tmp.children) {
|
|
||||||
const childrenBreadcrumb = [...breadcrumb]
|
|
||||||
childrenBreadcrumb.push(route)
|
|
||||||
const tmpRoute = { ...route }
|
|
||||||
tmpRoute.meta.breadcrumb = childrenBreadcrumb
|
|
||||||
delete tmpRoute.children
|
|
||||||
res.push(tmpRoute)
|
|
||||||
const childrenRoutes = flatAsyncRoutes(tmp.children, childrenBreadcrumb)
|
|
||||||
childrenRoutes.map((item) => {
|
|
||||||
res.push(item)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
const tmpBreadcrumb = [...breadcrumb]
|
|
||||||
tmpBreadcrumb.push(tmp)
|
|
||||||
tmp.meta.breadcrumb = tmpBreadcrumb
|
|
||||||
res.push(tmp)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|
|
@ -15,6 +15,7 @@ import routerUtil from '@/utils/routerUtil'
|
||||||
import Layout from '@/layout/index.vue'
|
import Layout from '@/layout/index.vue'
|
||||||
import Login from '@/views/auth/login/login.vue'
|
import Login from '@/views/auth/login/login.vue'
|
||||||
import Findpwd from '@/views/auth/findPwd/index.vue'
|
import Findpwd from '@/views/auth/findPwd/index.vue'
|
||||||
|
import Callback from '@/views/auth/login/callback.vue'
|
||||||
|
|
||||||
// 系统路由
|
// 系统路由
|
||||||
const routes = [
|
const routes = [
|
||||||
|
@ -41,7 +42,7 @@ const routes = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/callback',
|
path: '/callback',
|
||||||
component: () => import('@/views/auth/login/callback.vue'),
|
component: Callback,
|
||||||
meta: {
|
meta: {
|
||||||
title: '三方登录'
|
title: '三方登录'
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
/**
|
||||||
|
* Copyright [2022] [https://www.xiaonuo.vip]
|
||||||
|
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||||
|
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||||
|
* 2.请不要删除和修改Snowy源码头部的版权声明。
|
||||||
|
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
|
||||||
|
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
|
||||||
|
* 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
|
||||||
|
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||||||
|
*/
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import tool from '@/utils/tool'
|
||||||
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
import userRoutes from '@/config/route'
|
||||||
|
import { searchStore } from '@/store/search'
|
||||||
|
import router from '@/router'
|
||||||
|
import userCenterApi from '@/api/sys/userCenterApi'
|
||||||
|
import whiteList from '@/router/whiteList'
|
||||||
|
import routesData from '@/router/systemRouter'
|
||||||
|
|
||||||
|
const modules = import.meta.glob('/src/views/**/**.vue')
|
||||||
|
export const useMenuStore = defineStore('menuStore', () => {
|
||||||
|
const menuData = ref([])
|
||||||
|
const refreshFlag = ref(false)
|
||||||
|
// 改变刷新标志
|
||||||
|
const changeRefreshFlag = (flag) => {
|
||||||
|
refreshFlag.value = flag
|
||||||
|
}
|
||||||
|
// 加载菜单
|
||||||
|
const loadMenu = () => {
|
||||||
|
// 获取用户菜单
|
||||||
|
const apiMenu = tool.data.get('MENU') || []
|
||||||
|
if (apiMenu.length === 0) {
|
||||||
|
// 创建默认模块,显示默认菜单
|
||||||
|
apiMenu[0] = cloneDeep(userRoutes.module[0])
|
||||||
|
}
|
||||||
|
const childrenApiMenu = apiMenu[0].children
|
||||||
|
apiMenu[0].children = [...(childrenApiMenu ? childrenApiMenu : []), ...userRoutes.menu]
|
||||||
|
let menuRouter = filterAsyncRouter(apiMenu)
|
||||||
|
menuRouter = flatAsyncRoutes(menuRouter)
|
||||||
|
menuData.value = menuRouter
|
||||||
|
// 初始化搜索
|
||||||
|
const search_store = searchStore()
|
||||||
|
search_store.init(menuRouter)
|
||||||
|
}
|
||||||
|
// 过滤异步路由
|
||||||
|
const filterAsyncRouter = (routerMap) => {
|
||||||
|
const accessedRouters = []
|
||||||
|
routerMap.forEach((item) => {
|
||||||
|
item.meta = item.meta ? item.meta : {}
|
||||||
|
// 处理外部链接特殊路由
|
||||||
|
if (item.meta.type === 'iframe') {
|
||||||
|
item.meta.url = item.path
|
||||||
|
item.path = `/${item.name}`
|
||||||
|
}
|
||||||
|
// MAP转路由对象
|
||||||
|
const route = {
|
||||||
|
path: item.path,
|
||||||
|
name: item.name,
|
||||||
|
meta: item.meta,
|
||||||
|
redirect: item.redirect,
|
||||||
|
children: item.children ? filterAsyncRouter(item.children) : null,
|
||||||
|
component: loadComponent(item.component)
|
||||||
|
}
|
||||||
|
accessedRouters.push(route)
|
||||||
|
})
|
||||||
|
return accessedRouters
|
||||||
|
}
|
||||||
|
// 将异步路由扁平化
|
||||||
|
const flatAsyncRoutes = (routes, breadcrumb = []) => {
|
||||||
|
const res = []
|
||||||
|
routes.forEach((route) => {
|
||||||
|
const tmp = { ...route }
|
||||||
|
if (tmp.children) {
|
||||||
|
const childrenBreadcrumb = [...breadcrumb]
|
||||||
|
childrenBreadcrumb.push(route)
|
||||||
|
const tmpRoute = { ...route }
|
||||||
|
tmpRoute.meta.breadcrumb = childrenBreadcrumb
|
||||||
|
delete tmpRoute.children
|
||||||
|
res.push(tmpRoute)
|
||||||
|
const childrenRoutes = flatAsyncRoutes(tmp.children, childrenBreadcrumb)
|
||||||
|
childrenRoutes.map((item) => {
|
||||||
|
res.push(item)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const tmpBreadcrumb = [...breadcrumb]
|
||||||
|
tmpBreadcrumb.push(tmp)
|
||||||
|
tmp.meta.breadcrumb = tmpBreadcrumb
|
||||||
|
res.push(tmp)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
// 动态加载组件
|
||||||
|
const loadComponent = (component) => {
|
||||||
|
if (component) {
|
||||||
|
if (component.includes('/')) {
|
||||||
|
return modules[`/src/views/${component}.vue`]
|
||||||
|
}
|
||||||
|
return modules[`/src/views/${component}/index.vue`]
|
||||||
|
} else {
|
||||||
|
return () => import(/* @vite-ignore */ `/src/layout/other/empty.vue`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 从路由中移除菜单
|
||||||
|
const removeFromRouter = () => {
|
||||||
|
const routes = router.getRoutes()
|
||||||
|
// 遍历所有路由
|
||||||
|
routes.forEach((route) => {
|
||||||
|
// 过滤白名单
|
||||||
|
if (
|
||||||
|
whiteList.filter((e) => e.path === route.path).length > 0 ||
|
||||||
|
routesData.filter((e) => e.path === route.path).length > 0
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (route.name && route.name !== 'layout') {
|
||||||
|
router.removeRoute(route.name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 获取用户菜单
|
||||||
|
const fetchMenu = async () => {
|
||||||
|
const menu = await userCenterApi.userLoginMenu()
|
||||||
|
tool.data.set('MENU', menu)
|
||||||
|
refreshMenu()
|
||||||
|
}
|
||||||
|
// 刷新菜单
|
||||||
|
const refreshMenu = () => {
|
||||||
|
loadMenu()
|
||||||
|
removeFromRouter()
|
||||||
|
addToRouter()
|
||||||
|
changeRefreshFlag(true)
|
||||||
|
}
|
||||||
|
// 将菜单添加到路由
|
||||||
|
const addToRouter = () => {
|
||||||
|
menuData.value.forEach((item) => {
|
||||||
|
router.addRoute('layout', item)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return { menuData, loadMenu, addToRouter, refreshMenu, changeRefreshFlag, refreshFlag, fetchMenu }
|
||||||
|
})
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* Copyright [2022] [https://www.xiaonuo.vip]
|
||||||
|
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||||
|
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||||
|
* 2.请不要删除和修改Snowy源码头部的版权声明。
|
||||||
|
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
|
||||||
|
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
|
||||||
|
* 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
|
||||||
|
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||||||
|
*/
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import loginApi from '@/api/auth/loginApi'
|
||||||
|
import { useGlobalStore } from '@/store'
|
||||||
|
import tool from '@/utils/tool'
|
||||||
|
export const userStore = defineStore('userStore', () => {
|
||||||
|
// 初始化用户信息
|
||||||
|
const initUserInfo = async () => {
|
||||||
|
const data = await loginApi.getLoginUser()
|
||||||
|
const globalStore = useGlobalStore()
|
||||||
|
globalStore.setUserInfo(data)
|
||||||
|
tool.data.set('USER_INFO', data)
|
||||||
|
}
|
||||||
|
// 刷新登录用户信息
|
||||||
|
const refreshUserLoginUserInfo = () => {
|
||||||
|
loginApi.getLoginUser().then((data) => {
|
||||||
|
const globalStore = useGlobalStore()
|
||||||
|
globalStore.setUserInfo(data)
|
||||||
|
tool.data.set('USER_INFO', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return { initUserInfo, refreshUserLoginUserInfo }
|
||||||
|
})
|
|
@ -45,6 +45,26 @@ export const viewTagsStore = defineStore('viewTags', () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 更新或删除视图标签
|
||||||
|
const updateOrRemoveViewTags = (routes) => {
|
||||||
|
if (routes && routes.length > 0) {
|
||||||
|
viewTags.value.forEach((item, index) => {
|
||||||
|
const target = routes.find((route) => route.path === item.fullPath)
|
||||||
|
if (!target) {
|
||||||
|
// 路由不存在,删除
|
||||||
|
viewTags.value.splice(index, 1)
|
||||||
|
} else {
|
||||||
|
// 路由存在,更新
|
||||||
|
viewTags.value = viewTags.value.map((item) => {
|
||||||
|
if (item.fullPath === target.path) {
|
||||||
|
return { ...item, meta: target.meta }
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
const updateViewTagsTitle = (title = '') => {
|
const updateViewTagsTitle = (title = '') => {
|
||||||
const nowFullPath = location.hash.substring(1)
|
const nowFullPath = location.hash.substring(1)
|
||||||
viewTags.value.forEach((item) => {
|
viewTags.value.forEach((item) => {
|
||||||
|
@ -63,6 +83,7 @@ export const viewTagsStore = defineStore('viewTags', () => {
|
||||||
removeViewTags,
|
removeViewTags,
|
||||||
updateViewTags,
|
updateViewTags,
|
||||||
updateViewTagsTitle,
|
updateViewTagsTitle,
|
||||||
clearViewTags
|
clearViewTags,
|
||||||
|
updateOrRemoveViewTags
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -258,7 +258,7 @@ a, button, input, textarea {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*页面最大化*/
|
/*页面最大化*/
|
||||||
.admin-ui.main-maximize {
|
.app-main.main-maximize {
|
||||||
.main-maximize-exit {
|
.main-maximize-exit {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,6 @@
|
||||||
* 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
|
* 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
|
||||||
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||||||
*/
|
*/
|
||||||
/**
|
|
||||||
* 全局代码错误捕捉
|
|
||||||
* 比如 null.length 就会被捕捉到
|
|
||||||
*/
|
|
||||||
import { notification } from 'ant-design-vue'
|
|
||||||
|
|
||||||
export default (error) => {
|
export default (error) => {
|
||||||
// 过滤HTTP请求错误
|
// 过滤HTTP请求错误
|
||||||
if (error.code) {
|
if (error.code) {
|
||||||
|
@ -30,10 +24,6 @@ export default (error) => {
|
||||||
}
|
}
|
||||||
const errorName = errorMap[error.name] || '未知错误'
|
const errorName = errorMap[error.name] || '未知错误'
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
notification.error({
|
console.error(errorName)
|
||||||
message: '错误',
|
|
||||||
description: errorName
|
|
||||||
})
|
|
||||||
console.error(error)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,22 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="login_background">
|
<div class="login-wrapper">
|
||||||
<div class="login_background_front"></div>
|
<div class="login_background">
|
||||||
|
<div class="logo_background">
|
||||||
|
<a
|
||||||
|
:class="{ 'no-link': !sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL }"
|
||||||
|
:href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL"
|
||||||
|
target="_blank"
|
||||||
|
@click="handleLink"
|
||||||
|
>
|
||||||
|
<img :alt="sysBaseConfig.SNOWY_SYS_NAME" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
|
||||||
|
<label>{{ sysBaseConfig.SNOWY_SYS_NAME }}</label>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="version">
|
||||||
|
<p>{{ sysBaseConfig.SNOWY_SYS_DEFAULT_DESCRRIPTION }}</p>
|
||||||
|
<p>{{ sysBaseConfig.SNOWY_SYS_COPYRIGHT }} {{ sysBaseConfig.SNOWY_SYS_VERSION }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="login_main">
|
<div class="login_main">
|
||||||
<div class="login-form">
|
<div class="login-form">
|
||||||
<a-card>
|
<a-card>
|
||||||
|
@ -22,46 +38,40 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import phoneFindForm from './phoneFindForm.vue'
|
import PhoneFindForm from './phoneFindForm.vue'
|
||||||
import emailFindForm from './emailFindForm.vue'
|
import EmailFindForm from './emailFindForm.vue'
|
||||||
|
import { globalStore } from '@/store'
|
||||||
|
|
||||||
|
const store = globalStore()
|
||||||
const activeKey = ref('userPhone')
|
const activeKey = ref('userPhone')
|
||||||
|
const sysBaseConfig = computed(() => {
|
||||||
|
return store.sysBaseConfig
|
||||||
|
})
|
||||||
|
// logo链接
|
||||||
|
const handleLink = (e) => {
|
||||||
|
if (!sysBaseConfig.value.SNOWY_SYS_COPYRIGHT_URL) {
|
||||||
|
e?.stopPropagation()
|
||||||
|
e?.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
.login-wrapper {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
.login_background {
|
.login_background {
|
||||||
width: 100%;
|
width: 50%;
|
||||||
min-height: 100vh;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-image: url(/img/login_background.png);
|
background-image: url(/img/login_background.png);
|
||||||
}
|
position: relative;
|
||||||
.login_background_front {
|
|
||||||
width: 450px;
|
|
||||||
height: 450px;
|
|
||||||
margin-left: 100px;
|
|
||||||
margin-top: 15%;
|
|
||||||
overflow: hidden;
|
|
||||||
/*position: relative;*/
|
|
||||||
background-size: cover;
|
|
||||||
background-position: center;
|
|
||||||
background-image: url(/img/login_background_front.png);
|
|
||||||
animation-name: myfirst;
|
|
||||||
animation-duration: 5s;
|
|
||||||
animation-timing-function: linear;
|
|
||||||
animation-delay: 1s;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
animation-direction: alternate;
|
|
||||||
animation-play-state: running;
|
|
||||||
/* Safari and Chrome: */
|
|
||||||
-webkit-animation-name: myfirst;
|
|
||||||
-webkit-animation-duration: 5s;
|
|
||||||
-webkit-animation-timing-function: linear;
|
|
||||||
-webkit-animation-delay: 1s;
|
|
||||||
-webkit-animation-iteration-count: infinite;
|
|
||||||
-webkit-animation-direction: alternate;
|
|
||||||
-webkit-animation-play-state: running;
|
|
||||||
}
|
}
|
||||||
@keyframes myfirst {
|
@keyframes myfirst {
|
||||||
0% {
|
0% {
|
||||||
|
@ -122,18 +132,15 @@
|
||||||
}
|
}
|
||||||
/*background-image:linear-gradient(transparent, #000);*/
|
/*background-image:linear-gradient(transparent, #000);*/
|
||||||
.login_main {
|
.login_main {
|
||||||
flex: 1;
|
width: 50%;
|
||||||
overflow: auto;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.login-form {
|
.login-form {
|
||||||
top: 15%;
|
|
||||||
right: 15%;
|
|
||||||
position: absolute;
|
|
||||||
width: 450px;
|
width: 450px;
|
||||||
margin-left: 10%;
|
position: absolute;
|
||||||
margin-top: 20px;
|
top: 21.8%;
|
||||||
padding: 10px 0;
|
|
||||||
}
|
}
|
||||||
.login-header {
|
.login-header {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
@ -154,7 +161,7 @@
|
||||||
.login-header h2 {
|
.login-header h2 {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-top: 40px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
.login-oauth {
|
.login-oauth {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -165,6 +172,62 @@
|
||||||
top: 20px;
|
top: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
}
|
}
|
||||||
|
.logo_background {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 56px;
|
||||||
|
height: 60px;
|
||||||
|
padding-left: 56px;
|
||||||
|
width: 100%;
|
||||||
|
background: -webkit-gradient(
|
||||||
|
linear,
|
||||||
|
right top,
|
||||||
|
left top,
|
||||||
|
from(rgba(67, 147, 250, 0.5)),
|
||||||
|
to(rgba(133, 182, 252, 0.5))
|
||||||
|
);
|
||||||
|
background: linear-gradient(120deg, rgb(255 255 255 / 90%), rgba(255, 255, 255, 0));
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.logo_background img {
|
||||||
|
height: 40px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.logo_background label {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.logo_background a {
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.logo_background a.no-link,
|
||||||
|
.logo_background a.no-link label {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.logo_background a label {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.login_background .version {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 300;
|
||||||
|
padding: 0 56px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 12px;
|
||||||
|
}
|
||||||
|
.login_background .version p {
|
||||||
|
line-height: 22px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
@media (max-width: 1200px) {
|
@media (max-width: 1200px) {
|
||||||
.login-form {
|
.login-form {
|
||||||
width: 340px;
|
width: 340px;
|
||||||
|
@ -172,16 +235,27 @@
|
||||||
}
|
}
|
||||||
@media (max-width: 1000px) {
|
@media (max-width: 1000px) {
|
||||||
.login_main {
|
.login_main {
|
||||||
display: block;
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
}
|
}
|
||||||
.login_background_front {
|
.login_background_front {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.logo_background{
|
||||||
|
padding-left:40px;
|
||||||
|
}
|
||||||
.login-form {
|
.login-form {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 20px 40px;
|
padding: 20px 40px;
|
||||||
right: 0 !important;
|
top: 15%;
|
||||||
top: 0 !important;
|
}
|
||||||
|
.login_background .version {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
.login_background .version p:first-child {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,22 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="login_background">
|
<div class="login-wrapper">
|
||||||
<div class="login_background_front"></div>
|
<div class="login_background">
|
||||||
|
<div class="logo_background">
|
||||||
|
<a
|
||||||
|
:class="{ 'no-link': !sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL }"
|
||||||
|
:href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL"
|
||||||
|
target="_blank"
|
||||||
|
@click="handleLink"
|
||||||
|
>
|
||||||
|
<img :alt="sysBaseConfig.SNOWY_SYS_NAME" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
|
||||||
|
<label>{{ sysBaseConfig.SNOWY_SYS_NAME }}</label>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="version">
|
||||||
|
<p>{{ sysBaseConfig.SNOWY_SYS_DEFAULT_DESCRRIPTION }}</p>
|
||||||
|
<p>{{ sysBaseConfig.SNOWY_SYS_COPYRIGHT }} {{ sysBaseConfig.SNOWY_SYS_VERSION }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="login_main">
|
<div class="login_main">
|
||||||
<div class="login-form">
|
<div class="login-form">
|
||||||
<a-card>
|
<a-card>
|
||||||
|
@ -26,6 +42,12 @@
|
||||||
import loginApi from '@/api/auth/loginApi'
|
import loginApi from '@/api/auth/loginApi'
|
||||||
import userCenterApi from '@/api/sys/userCenterApi'
|
import userCenterApi from '@/api/sys/userCenterApi'
|
||||||
import dictApi from '@/api/dev/dictApi'
|
import dictApi from '@/api/dev/dictApi'
|
||||||
|
import { globalStore } from '@/store'
|
||||||
|
|
||||||
|
const store = globalStore()
|
||||||
|
const sysBaseConfig = computed(() => {
|
||||||
|
return store.sysBaseConfig
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 获取当前url
|
// 获取当前url
|
||||||
|
@ -69,6 +91,13 @@
|
||||||
window.location.href = '/login'
|
window.location.href = '/login'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
// logo链接
|
||||||
|
const handleLink = (e) => {
|
||||||
|
if (!sysBaseConfig.value.SNOWY_SYS_COPYRIGHT_URL) {
|
||||||
|
e?.stopPropagation()
|
||||||
|
e?.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
@ -7,13 +7,21 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
.login-wrapper{
|
||||||
|
width: 100vw;
|
||||||
|
height:100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
.login_background {
|
.login_background {
|
||||||
width: 100%;
|
width: 50%;
|
||||||
min-height: 100vh;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-image: url(/img/login_background.png);
|
background-image: url(/img/login_background.png);
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.login_background_front {
|
.login_background_front {
|
||||||
width: 450px;
|
width: 450px;
|
||||||
|
@ -92,45 +100,74 @@
|
||||||
}
|
}
|
||||||
/*background-image:linear-gradient(transparent, #000);*/
|
/*background-image:linear-gradient(transparent, #000);*/
|
||||||
.login_main {
|
.login_main {
|
||||||
flex: 1;
|
width: 50%;
|
||||||
overflow: auto;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.login-form {
|
.login-form {
|
||||||
top: 15%;
|
|
||||||
right: 15%;
|
|
||||||
position: absolute;
|
|
||||||
width: 450px;
|
width: 450px;
|
||||||
margin-left: 10%;
|
position: absolute;
|
||||||
margin-top: 20px;
|
top:21.8%
|
||||||
padding: 10px 0;
|
|
||||||
}
|
}
|
||||||
.login-header {
|
.login-header {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
.login-header .logo {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.login-header .logo img {
|
|
||||||
width: 35px;
|
|
||||||
height: 35px;
|
|
||||||
vertical-align: bottom;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
.login-header .logo label {
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
.login-header h2 {
|
.login-header h2 {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-top: 40px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
.login_config {
|
.login_config {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
}
|
}
|
||||||
|
.logo_background{
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 56px;
|
||||||
|
height: 60px;
|
||||||
|
padding-left: 56px;
|
||||||
|
width: 100%;
|
||||||
|
background: linear-gradient(120deg, rgb(255 255 255 / 90%), rgba(255, 255, 255, 0));
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.logo_background a{
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.logo_background a.no-link,
|
||||||
|
.logo_background a.no-link label{
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.logo_background img{
|
||||||
|
height:40px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.logo_background a label{
|
||||||
|
font-size:24px;
|
||||||
|
color:#fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.login_background .version{
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
color:#fff;
|
||||||
|
font-weight: 300;
|
||||||
|
padding: 0 56px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: absolute;
|
||||||
|
bottom:12px;
|
||||||
|
}
|
||||||
|
.login_background .version p{
|
||||||
|
line-height: 22px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom:6px;
|
||||||
|
}
|
||||||
@media (max-width: 1200px) {
|
@media (max-width: 1200px) {
|
||||||
.login-form {
|
.login-form {
|
||||||
width: 340px;
|
width: 340px;
|
||||||
|
@ -138,7 +175,10 @@
|
||||||
}
|
}
|
||||||
@media (max-width: 1000px) {
|
@media (max-width: 1000px) {
|
||||||
.login_main {
|
.login_main {
|
||||||
display: block;
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
}
|
}
|
||||||
.login_background_front {
|
.login_background_front {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -146,7 +186,15 @@
|
||||||
.login-form {
|
.login-form {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 20px 40px;
|
padding: 20px 40px;
|
||||||
right: 0 !important;
|
top:15%
|
||||||
top: 0 !important;
|
}
|
||||||
|
.logo_background{
|
||||||
|
padding-left:40px;
|
||||||
|
}
|
||||||
|
.login_background .version{
|
||||||
|
padding:0 20px;
|
||||||
|
}
|
||||||
|
.login_background .version p:first-child{
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,22 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="login_background">
|
<div class="login-wrapper">
|
||||||
<div class="login_background_front"></div>
|
<div class="login_background">
|
||||||
|
<div class="logo_background">
|
||||||
|
<a
|
||||||
|
:class="{ 'no-link': !sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL }"
|
||||||
|
:href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL"
|
||||||
|
target="_blank"
|
||||||
|
@click="handleLink"
|
||||||
|
>
|
||||||
|
<img :alt="sysBaseConfig.SNOWY_SYS_NAME" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
|
||||||
|
<label>{{ sysBaseConfig.SNOWY_SYS_NAME }}</label>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="version">
|
||||||
|
<p>{{ sysBaseConfig.SNOWY_SYS_DEFAULT_DESCRRIPTION }}</p>
|
||||||
|
<p>{{ sysBaseConfig.SNOWY_SYS_COPYRIGHT }} {{ sysBaseConfig.SNOWY_SYS_VERSION }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="login_main">
|
<div class="login_main">
|
||||||
<div class="login_config">
|
<div class="login_config">
|
||||||
<a-dropdown>
|
<a-dropdown>
|
||||||
|
@ -23,11 +39,7 @@
|
||||||
<div class="login-form">
|
<div class="login-form">
|
||||||
<a-card>
|
<a-card>
|
||||||
<div class="login-header">
|
<div class="login-header">
|
||||||
<div class="logo">
|
<h2>{{ $t('login.signInTitle') }}</h2>
|
||||||
<img :alt="sysBaseConfig.SNOWY_SYS_NAME" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
|
|
||||||
<label>{{ sysBaseConfig.SNOWY_SYS_NAME }}</label>
|
|
||||||
</div>
|
|
||||||
<!--<h2>{{ $t('login.signInTitle') }}</h2>-->
|
|
||||||
</div>
|
</div>
|
||||||
<a-tabs v-model:activeKey="activeKey">
|
<a-tabs v-model:activeKey="activeKey">
|
||||||
<a-tab-pane key="userAccount" :tab="$t('login.accountPassword')">
|
<a-tab-pane key="userAccount" :tab="$t('login.accountPassword')">
|
||||||
|
@ -202,7 +214,6 @@
|
||||||
rules.validCode = [required(proxy.$t('login.validError'), 'blur')]
|
rules.validCode = [required(proxy.$t('login.validError'), 'blur')]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取验证码
|
// 获取验证码
|
||||||
const loginCaptcha = () => {
|
const loginCaptcha = () => {
|
||||||
loginApi.getPicCaptcha().then((data) => {
|
loginApi.getPicCaptcha().then((data) => {
|
||||||
|
@ -224,15 +235,6 @@
|
||||||
validCode: ruleForm.validCode,
|
validCode: ruleForm.validCode,
|
||||||
validCodeReqNo: ruleForm.validCodeReqNo
|
validCodeReqNo: ruleForm.validCodeReqNo
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取token
|
|
||||||
// loginApi.login(loginData).then((loginToken) => {
|
|
||||||
// afterLogin(loginToken)
|
|
||||||
// }).catch(() => {
|
|
||||||
// loading.value = false
|
|
||||||
// loginCaptcha()
|
|
||||||
// })
|
|
||||||
|
|
||||||
// 获取token
|
// 获取token
|
||||||
try {
|
try {
|
||||||
const loginToken = await loginApi.login(loginData)
|
const loginToken = await loginApi.login(loginData)
|
||||||
|
@ -249,6 +251,13 @@
|
||||||
const configLang = (key) => {
|
const configLang = (key) => {
|
||||||
config.value.lang = key
|
config.value.lang = key
|
||||||
}
|
}
|
||||||
|
// logo链接
|
||||||
|
const handleLink = (e) => {
|
||||||
|
if (!sysBaseConfig.value.SNOWY_SYS_COPYRIGHT_URL) {
|
||||||
|
e?.stopPropagation()
|
||||||
|
e?.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@import 'login';
|
@import 'login';
|
||||||
|
|
|
@ -1,24 +1,22 @@
|
||||||
import loginApi from '@/api/auth/loginApi'
|
|
||||||
import userCenterApi from '@/api/sys/userCenterApi'
|
import userCenterApi from '@/api/sys/userCenterApi'
|
||||||
import dictApi from '@/api/dev/dictApi'
|
import dictApi from '@/api/dev/dictApi'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import tool from '@/utils/tool'
|
import tool from '@/utils/tool'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
import { useGlobalStore } from '@/store'
|
|
||||||
import routerUtil from '@/utils/routerUtil'
|
import routerUtil from '@/utils/routerUtil'
|
||||||
|
import { useMenuStore } from '@/store/menu'
|
||||||
|
import { userStore } from '@/store/user'
|
||||||
|
|
||||||
export const afterLogin = async (loginToken) => {
|
export const afterLogin = async (loginToken) => {
|
||||||
|
const menuStore = useMenuStore()
|
||||||
tool.data.set('TOKEN', loginToken)
|
tool.data.set('TOKEN', loginToken)
|
||||||
// 获取登录的用户信息
|
// 初始化用户信息
|
||||||
const loginUser = await loginApi.getLoginUser()
|
await userStore().initUserInfo()
|
||||||
const globalStore = useGlobalStore()
|
|
||||||
globalStore.setUserInfo(loginUser)
|
|
||||||
tool.data.set('USER_INFO', loginUser)
|
|
||||||
|
|
||||||
// 获取用户的菜单
|
// 获取用户的菜单
|
||||||
const menu = await userCenterApi.userLoginMenu()
|
const menu = await userCenterApi.userLoginMenu()
|
||||||
let indexMenu = routerUtil.getIndexMenu(menu).path
|
let indexMenu = routerUtil.getIndexMenu(menu).path
|
||||||
tool.data.set('MENU', menu)
|
await menuStore.fetchMenu()
|
||||||
// 重置系统默认应用
|
// 重置系统默认应用
|
||||||
tool.data.set('SNOWY_MENU_MODULE_ID', menu[0].id)
|
tool.data.set('SNOWY_MENU_MODULE_ID', menu[0].id)
|
||||||
message.success('登录成功')
|
message.success('登录成功')
|
||||||
|
|
|
@ -123,6 +123,7 @@
|
||||||
|
|
||||||
<script setup name="sysResourceMenuForm">
|
<script setup name="sysResourceMenuForm">
|
||||||
import { required } from '@/utils/formRules'
|
import { required } from '@/utils/formRules'
|
||||||
|
import { cloneDeep } from 'lodash-es'
|
||||||
import SnowflakeId from 'snowflake-id'
|
import SnowflakeId from 'snowflake-id'
|
||||||
import tool from '@/utils/tool'
|
import tool from '@/utils/tool'
|
||||||
import menuApi from '@/api/sys/resource/menuApi'
|
import menuApi from '@/api/sys/resource/menuApi'
|
||||||
|
@ -141,7 +142,8 @@
|
||||||
// 模块ID
|
// 模块ID
|
||||||
const moduleId = ref('')
|
const moduleId = ref('')
|
||||||
// 打开抽屉
|
// 打开抽屉
|
||||||
const onOpen = (record, module) => {
|
const onOpen = (data, module) => {
|
||||||
|
const record = cloneDeep(data)
|
||||||
moduleId.value = module
|
moduleId.value = module
|
||||||
visible.value = true
|
visible.value = true
|
||||||
if (record) {
|
if (record) {
|
||||||
|
|
|
@ -111,8 +111,8 @@
|
||||||
</template>
|
</template>
|
||||||
</s-table>
|
</s-table>
|
||||||
</a-card>
|
</a-card>
|
||||||
<Form ref="formRef" @successful="tableRef.refresh(true)" />
|
<Form ref="formRef" @successful="handleSuccess" />
|
||||||
<changeModuleForm ref="changeModuleFormRef" @successful="tableRef.refresh(true)" />
|
<changeModuleForm ref="changeModuleFormRef" @successful="handleSuccess" />
|
||||||
<Button ref="buttonRef" />
|
<Button ref="buttonRef" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -121,6 +121,7 @@
|
||||||
import Form from './form.vue'
|
import Form from './form.vue'
|
||||||
import ChangeModuleForm from './changeModuleForm.vue'
|
import ChangeModuleForm from './changeModuleForm.vue'
|
||||||
import Button from '../button/index.vue'
|
import Button from '../button/index.vue'
|
||||||
|
import { useMenuStore } from '@/store/menu'
|
||||||
const searchFormState = ref({})
|
const searchFormState = ref({})
|
||||||
const tableRef = ref(null)
|
const tableRef = ref(null)
|
||||||
const formRef = ref()
|
const formRef = ref()
|
||||||
|
@ -242,12 +243,24 @@
|
||||||
]
|
]
|
||||||
menuApi.menuDelete(params).then(() => {
|
menuApi.menuDelete(params).then(() => {
|
||||||
tableRef.value.refresh(true)
|
tableRef.value.refresh(true)
|
||||||
|
refreshCacheMenu()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 批量删除
|
// 批量删除
|
||||||
const deleteBatchMenu = (params) => {
|
const deleteBatchMenu = (params) => {
|
||||||
menuApi.menuDelete(params).then(() => {
|
menuApi.menuDelete(params).then(() => {
|
||||||
tableRef.value.clearRefreshSelected()
|
tableRef.value.clearRefreshSelected()
|
||||||
|
refreshCacheMenu()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 成功回调
|
||||||
|
const handleSuccess = () => {
|
||||||
|
tableRef.value.refresh(true)
|
||||||
|
refreshCacheMenu()
|
||||||
|
}
|
||||||
|
// 刷新缓存的菜单
|
||||||
|
const refreshCacheMenu = () => {
|
||||||
|
const menuStore = useMenuStore()
|
||||||
|
menuStore.fetchMenu()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -108,6 +108,7 @@
|
||||||
import { SearchOutlined } from '@ant-design/icons-vue'
|
import { SearchOutlined } from '@ant-design/icons-vue'
|
||||||
import roleApi from '@/api/sys/roleApi'
|
import roleApi from '@/api/sys/roleApi'
|
||||||
import ScopeDefineOrg from './scopeDefineOrg.vue'
|
import ScopeDefineOrg from './scopeDefineOrg.vue'
|
||||||
|
import { userStore } from '@/store/user'
|
||||||
|
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const spinningLoading = ref(false)
|
const spinningLoading = ref(false)
|
||||||
|
@ -248,7 +249,7 @@
|
||||||
scopeDefineOrgModal.value.onOpen(data.id, checkKeysStr)
|
scopeDefineOrgModal.value.onOpen(data.id, checkKeysStr)
|
||||||
} else {
|
} else {
|
||||||
// 清理缓存中的结构,去掉就行
|
// 清理缓存中的结构,去掉就行
|
||||||
handleDatascope(false, record.id, null)
|
handleDatascope(false, data.id, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 自定义数据弹窗回调
|
// 自定义数据弹窗回调
|
||||||
|
@ -365,6 +366,10 @@
|
||||||
.then(() => {
|
.then(() => {
|
||||||
onClose()
|
onClose()
|
||||||
emit('successful')
|
emit('successful')
|
||||||
|
// 刷新权限
|
||||||
|
nextTick(() => {
|
||||||
|
userStore().refreshUserLoginUserInfo()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
submitLoading.value = false
|
submitLoading.value = false
|
||||||
|
|
|
@ -56,10 +56,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="grantResourceForm">
|
<script setup name="grantResourceForm">
|
||||||
import { nextTick } from 'vue'
|
|
||||||
import tool from '@/utils/tool'
|
|
||||||
import roleApi from '@/api/sys/roleApi'
|
import roleApi from '@/api/sys/roleApi'
|
||||||
import userCenterApi from '@/api/sys/userCenterApi'
|
import { useMenuStore } from '@/store/menu'
|
||||||
|
import { userStore } from '@/store/user'
|
||||||
const spinningLoading = ref(false)
|
const spinningLoading = ref(false)
|
||||||
const firstShowMap = ref({})
|
const firstShowMap = ref({})
|
||||||
const emit = defineEmits({ successful: null })
|
const emit = defineEmits({ successful: null })
|
||||||
|
@ -283,19 +282,17 @@
|
||||||
.then(() => {
|
.then(() => {
|
||||||
onClose()
|
onClose()
|
||||||
emit('successful')
|
emit('successful')
|
||||||
refreshCacheMenu()
|
refreshCache()
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
submitLoading.value = false
|
submitLoading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 刷新缓存的菜单
|
// 刷新缓存
|
||||||
const refreshCacheMenu = () => {
|
const refreshCache = () => {
|
||||||
nextTick(() => {
|
const menuStore = useMenuStore()
|
||||||
userCenterApi.userLoginMenu().then((res) => {
|
menuStore.fetchMenu()
|
||||||
tool.data.set('MENU', res)
|
userStore().refreshUserLoginUserInfo()
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
// 调用这个函数将子组件的一些数据和方法暴露出去
|
// 调用这个函数将子组件的一些数据和方法暴露出去
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
|
|
@ -109,6 +109,7 @@
|
||||||
import userApi from '@/api/sys/userApi'
|
import userApi from '@/api/sys/userApi'
|
||||||
import roleApi from '@/api/sys/roleApi'
|
import roleApi from '@/api/sys/roleApi'
|
||||||
import ScopeDefineOrg from './scopeDefineOrg.vue'
|
import ScopeDefineOrg from './scopeDefineOrg.vue'
|
||||||
|
import { userStore } from '@/store/user'
|
||||||
|
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const spinningLoading = ref(false)
|
const spinningLoading = ref(false)
|
||||||
|
@ -249,7 +250,7 @@
|
||||||
scopeDefineOrgModal.value.onOpen(data.id, checkKeysStr)
|
scopeDefineOrgModal.value.onOpen(data.id, checkKeysStr)
|
||||||
} else {
|
} else {
|
||||||
// 清理缓存中的结构,去掉就行
|
// 清理缓存中的结构,去掉就行
|
||||||
handleDatascope(false, record.id, null)
|
handleDatascope(false, data.id, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 自定义数据弹窗回调
|
// 自定义数据弹窗回调
|
||||||
|
@ -366,6 +367,10 @@
|
||||||
.then(() => {
|
.then(() => {
|
||||||
onClose()
|
onClose()
|
||||||
emit('successful')
|
emit('successful')
|
||||||
|
// 刷新权限
|
||||||
|
nextTick(() => {
|
||||||
|
userStore().refreshUserLoginUserInfo()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
submitLoading.value = false
|
submitLoading.value = false
|
||||||
|
|
|
@ -56,11 +56,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="grantResourceForm">
|
<script setup name="grantResourceForm">
|
||||||
import { nextTick } from 'vue'
|
|
||||||
import tool from '@/utils/tool'
|
|
||||||
import userApi from '@/api/sys/userApi'
|
import userApi from '@/api/sys/userApi'
|
||||||
import roleApi from '@/api/sys/roleApi'
|
import roleApi from '@/api/sys/roleApi'
|
||||||
import userCenterApi from '@/api/sys/userCenterApi'
|
import { useMenuStore } from '@/store/menu'
|
||||||
|
import { userStore } from '@/store/user'
|
||||||
const spinningLoading = ref(false)
|
const spinningLoading = ref(false)
|
||||||
const firstShowMap = ref({})
|
const firstShowMap = ref({})
|
||||||
const emit = defineEmits({ successful: null })
|
const emit = defineEmits({ successful: null })
|
||||||
|
@ -284,20 +283,19 @@
|
||||||
.then(() => {
|
.then(() => {
|
||||||
onClose()
|
onClose()
|
||||||
emit('successful')
|
emit('successful')
|
||||||
refreshCacheMenu()
|
refreshCache()
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
submitLoading.value = false
|
submitLoading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 刷新缓存的菜单
|
// 刷新缓存
|
||||||
const refreshCacheMenu = () => {
|
const refreshCache = () => {
|
||||||
nextTick(() => {
|
const menuStore = useMenuStore()
|
||||||
userCenterApi.userLoginMenu().then((res) => {
|
menuStore.fetchMenu()
|
||||||
tool.data.set('MENU', res)
|
userStore().refreshUserLoginUserInfo()
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用这个函数将子组件的一些数据和方法暴露出去
|
// 调用这个函数将子组件的一些数据和方法暴露出去
|
||||||
defineExpose({
|
defineExpose({
|
||||||
onOpen
|
onOpen
|
||||||
|
|
|
@ -46,14 +46,14 @@ public class AuthConfigure implements WebMvcConfigurer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册Sa-Token的注解拦截器,打开注解式鉴权功能
|
* 注册Sa-Token的注解拦截器,打开注解式鉴权功能
|
||||||
*
|
* <p>
|
||||||
* 注解的方式有以下几中,注解既可以加在接口方法上,也可加在Controller类上:
|
* 注解的方式有以下几中,注解既可以加在接口方法上,也可加在Controller类上:
|
||||||
* 1.@SaCheckLogin: 登录认证 —— 只有登录之后才能进入该方法(常用)
|
* 1.@SaCheckLogin: 登录认证 —— 只有登录之后才能进入该方法(常用)
|
||||||
* 2.@SaCheckRole("admin"): 角色认证 —— 必须具有指定角色标识才能进入该方法(常用)
|
* 2.@SaCheckRole("admin"): 角色认证 —— 必须具有指定角色标识才能进入该方法(常用)
|
||||||
* 3.@SaCheckPermission("user:add"): 权限认证 —— 必须具有指定权限才能进入该方法(常用)
|
* 3.@SaCheckPermission("user:add"): 权限认证 —— 必须具有指定权限才能进入该方法(常用)
|
||||||
* 4.@SaCheckSafe: 二级认证校验 —— 必须二级认证之后才能进入该方法
|
* 4.@SaCheckSafe: 二级认证校验 —— 必须二级认证之后才能进入该方法
|
||||||
* 5.@SaCheckBasic: HttpBasic认证 —— 只有通过 Basic 认证后才能进入该方法
|
* 5.@SaCheckBasic: HttpBasic认证 —— 只有通过 Basic 认证后才能进入该方法
|
||||||
*
|
* </p>
|
||||||
* 在Controller中创建一个接口,默认不需要登录也不需要任何权限都可以访问的,只有加了上述注解才会校验
|
* 在Controller中创建一个接口,默认不需要登录也不需要任何权限都可以访问的,只有加了上述注解才会校验
|
||||||
**/
|
**/
|
||||||
@Override
|
@Override
|
||||||
|
@ -75,10 +75,11 @@ public class AuthConfigure implements WebMvcConfigurer {
|
||||||
return new StpLogic(SaClientTypeEnum.C.getValue()).setConfig(saTokenConfig);
|
return new StpLogic(SaClientTypeEnum.C.getValue()).setConfig(saTokenConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("ALL")
|
||||||
@Autowired
|
@Autowired
|
||||||
public void rewriteSaStrategy() {
|
public void rewriteSaStrategy() {
|
||||||
// 重写Sa-Token的注解处理器,增加注解合并功能
|
// 重写Sa-Token的注解处理器,增加注解合并功能
|
||||||
SaStrategy.me.getAnnotation = AnnotatedElementUtils::getMergedAnnotation;
|
SaStrategy.instance.getAnnotation = AnnotatedElementUtils::getMergedAnnotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,17 +99,13 @@ public class AuthConfigure implements WebMvcConfigurer {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<String> getPermissionList(Object loginId, String loginType) {
|
public List<String> getPermissionList(Object loginId, String loginType) {
|
||||||
|
Object permissionListObject;
|
||||||
if (SaClientTypeEnum.B.getValue().equals(loginType)) {
|
if (SaClientTypeEnum.B.getValue().equals(loginType)) {
|
||||||
// return StpLoginUserUtil.getLoginUser().getPermissionCodeList();
|
permissionListObject = commonCacheOperator.get(CacheConstant.AUTH_B_PERMISSION_LIST_CACHE_KEY + loginId);
|
||||||
Object permissionListObject = commonCacheOperator.get(CacheConstant.AUTH_B_PERMISSION_LIST_CACHE_KEY+loginId);
|
|
||||||
List<String> permissionList = JSONUtil.parseArray(permissionListObject).toList(String.class);
|
|
||||||
return permissionList;
|
|
||||||
} else {
|
} else {
|
||||||
// return StpClientLoginUserUtil.getClientLoginUser().getPermissionCodeList();
|
permissionListObject = commonCacheOperator.get(CacheConstant.AUTH_C_PERMISSION_LIST_CACHE_KEY + loginId);
|
||||||
Object permissionListObject = commonCacheOperator.get(CacheConstant.AUTH_C_PERMISSION_LIST_CACHE_KEY+loginId);
|
|
||||||
List<String> permissionList = JSONUtil.parseArray(permissionListObject).toList(String.class);
|
|
||||||
return permissionList;
|
|
||||||
}
|
}
|
||||||
|
return JSONUtil.parseArray(permissionListObject).toList(String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -356,6 +356,19 @@ public class AuthServiceImpl implements AuthService {
|
||||||
}
|
}
|
||||||
// 执行登录
|
// 执行登录
|
||||||
StpUtil.login(saBaseLoginUser.getId(), new SaLoginModel().setDevice(device).setExtra("name", saBaseLoginUser.getName()));
|
StpUtil.login(saBaseLoginUser.getId(), new SaLoginModel().setDevice(device).setExtra("name", saBaseLoginUser.getName()));
|
||||||
|
// 填充B端用户信息并更新缓存
|
||||||
|
fillSaBaseLoginUserAndUpdateCache(saBaseLoginUser);
|
||||||
|
// 返回token
|
||||||
|
return StpUtil.getTokenInfo().tokenValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 填充B端用户信息并更新缓存
|
||||||
|
*
|
||||||
|
* @author xuyuxiang
|
||||||
|
* @date 2024/7/22 22:00
|
||||||
|
*/
|
||||||
|
private void fillSaBaseLoginUserAndUpdateCache(SaBaseLoginUser saBaseLoginUser) {
|
||||||
// 角色集合
|
// 角色集合
|
||||||
List<JSONObject> roleList = loginUserApi.getRoleListByUserId(saBaseLoginUser.getId());
|
List<JSONObject> roleList = loginUserApi.getRoleListByUserId(saBaseLoginUser.getId());
|
||||||
// 角色id集合
|
// 角色id集合
|
||||||
|
@ -374,16 +387,14 @@ public class AuthServiceImpl implements AuthService {
|
||||||
// 获取权限码
|
// 获取权限码
|
||||||
List<String> permissionCodeList = saBaseLoginUser.getDataScopeList().stream()
|
List<String> permissionCodeList = saBaseLoginUser.getDataScopeList().stream()
|
||||||
.map(SaBaseLoginUser.DataScope::getApiUrl).collect(Collectors.toList());
|
.map(SaBaseLoginUser.DataScope::getApiUrl).collect(Collectors.toList());
|
||||||
|
// 设置权限码
|
||||||
saBaseLoginUser.setPermissionCodeList(permissionCodeList);
|
saBaseLoginUser.setPermissionCodeList(permissionCodeList);
|
||||||
// 权限码列表存入缓存
|
// 权限码列表存入缓存
|
||||||
commonCacheOperator.put(CacheConstant.AUTH_B_PERMISSION_LIST_CACHE_KEY + saBaseLoginUser.getId(),permissionCodeList);
|
commonCacheOperator.put(CacheConstant.AUTH_B_PERMISSION_LIST_CACHE_KEY + saBaseLoginUser.getId(),permissionCodeList);
|
||||||
|
|
||||||
// 获取角色码
|
// 获取角色码
|
||||||
saBaseLoginUser.setRoleCodeList(roleCodeList);
|
saBaseLoginUser.setRoleCodeList(roleCodeList);
|
||||||
// 缓存用户信息,此处使用TokenSession为了指定时间内无操作则自动下线
|
// 缓存用户信息,此处使用TokenSession为了指定时间内无操作则自动下线
|
||||||
StpUtil.getTokenSession().set("loginUser", saBaseLoginUser);
|
StpUtil.getTokenSession().set("loginUser", saBaseLoginUser);
|
||||||
// 返回token
|
|
||||||
return StpUtil.getTokenInfo().tokenValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -399,6 +410,19 @@ public class AuthServiceImpl implements AuthService {
|
||||||
}
|
}
|
||||||
// 执行登录
|
// 执行登录
|
||||||
StpClientUtil.login(saBaseClientLoginUser.getId(), new SaLoginModel().setDevice(device).setExtra("name", saBaseClientLoginUser.getName()));
|
StpClientUtil.login(saBaseClientLoginUser.getId(), new SaLoginModel().setDevice(device).setExtra("name", saBaseClientLoginUser.getName()));
|
||||||
|
// 填充C端用户信息并更新缓存
|
||||||
|
fillSaBaseClientLoginUserAndUpdateCache(saBaseClientLoginUser);
|
||||||
|
// 返回token
|
||||||
|
return StpClientUtil.getTokenInfo().tokenValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 填充C端用户信息
|
||||||
|
*
|
||||||
|
* @author xuyuxiang
|
||||||
|
* @date 2024/7/22 22:00
|
||||||
|
*/
|
||||||
|
private void fillSaBaseClientLoginUserAndUpdateCache(SaBaseClientLoginUser saBaseClientLoginUser) {
|
||||||
// 角色集合
|
// 角色集合
|
||||||
List<JSONObject> roleList = loginUserApi.getRoleListByUserId(saBaseClientLoginUser.getId());
|
List<JSONObject> roleList = loginUserApi.getRoleListByUserId(saBaseClientLoginUser.getId());
|
||||||
// 角色id集合
|
// 角色id集合
|
||||||
|
@ -417,6 +441,7 @@ public class AuthServiceImpl implements AuthService {
|
||||||
// 获取权限码
|
// 获取权限码
|
||||||
List<String> permissionCodeList = saBaseClientLoginUser.getDataScopeList().stream()
|
List<String> permissionCodeList = saBaseClientLoginUser.getDataScopeList().stream()
|
||||||
.map(SaBaseClientLoginUser.DataScope::getApiUrl).collect(Collectors.toList());
|
.map(SaBaseClientLoginUser.DataScope::getApiUrl).collect(Collectors.toList());
|
||||||
|
// 设置权限码
|
||||||
saBaseClientLoginUser.setPermissionCodeList(permissionCodeList);
|
saBaseClientLoginUser.setPermissionCodeList(permissionCodeList);
|
||||||
// 权限码列表存入缓存
|
// 权限码列表存入缓存
|
||||||
commonCacheOperator.put(CacheConstant.AUTH_C_PERMISSION_LIST_CACHE_KEY + saBaseClientLoginUser.getId(),permissionCodeList);
|
commonCacheOperator.put(CacheConstant.AUTH_C_PERMISSION_LIST_CACHE_KEY + saBaseClientLoginUser.getId(),permissionCodeList);
|
||||||
|
@ -424,8 +449,6 @@ public class AuthServiceImpl implements AuthService {
|
||||||
saBaseClientLoginUser.setRoleCodeList(roleCodeList);
|
saBaseClientLoginUser.setRoleCodeList(roleCodeList);
|
||||||
// 缓存用户信息,此处使用TokenSession为了指定时间内无操作则自动下线
|
// 缓存用户信息,此处使用TokenSession为了指定时间内无操作则自动下线
|
||||||
StpClientUtil.getTokenSession().set("loginUser", saBaseClientLoginUser);
|
StpClientUtil.getTokenSession().set("loginUser", saBaseClientLoginUser);
|
||||||
// 返回token
|
|
||||||
return StpClientUtil.getTokenInfo().tokenValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -436,10 +459,19 @@ public class AuthServiceImpl implements AuthService {
|
||||||
**/
|
**/
|
||||||
@Override
|
@Override
|
||||||
public SaBaseLoginUser getLoginUser() {
|
public SaBaseLoginUser getLoginUser() {
|
||||||
|
// 获取当前缓存的用户信息
|
||||||
SaBaseLoginUser saBaseLoginUser = StpLoginUserUtil.getLoginUser();
|
SaBaseLoginUser saBaseLoginUser = StpLoginUserUtil.getLoginUser();
|
||||||
|
// 获取B端用户信息
|
||||||
|
saBaseLoginUser = loginUserApi.getUserById(saBaseLoginUser.getId());
|
||||||
|
// 填充B端用户信息并更新缓存
|
||||||
|
fillSaBaseLoginUserAndUpdateCache(saBaseLoginUser);
|
||||||
|
// 去掉密码
|
||||||
saBaseLoginUser.setPassword(null);
|
saBaseLoginUser.setPassword(null);
|
||||||
|
// 去掉权限码
|
||||||
saBaseLoginUser.setPermissionCodeList(null);
|
saBaseLoginUser.setPermissionCodeList(null);
|
||||||
|
// 去掉数据范围
|
||||||
saBaseLoginUser.setDataScopeList(null);
|
saBaseLoginUser.setDataScopeList(null);
|
||||||
|
// 返回
|
||||||
return saBaseLoginUser;
|
return saBaseLoginUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,10 +483,19 @@ public class AuthServiceImpl implements AuthService {
|
||||||
**/
|
**/
|
||||||
@Override
|
@Override
|
||||||
public SaBaseClientLoginUser getClientLoginUser() {
|
public SaBaseClientLoginUser getClientLoginUser() {
|
||||||
|
// 获取当前缓存的用户信息
|
||||||
SaBaseClientLoginUser saBaseClientLoginUser = StpClientLoginUserUtil.getClientLoginUser();
|
SaBaseClientLoginUser saBaseClientLoginUser = StpClientLoginUserUtil.getClientLoginUser();
|
||||||
|
// 获取C端用户信息
|
||||||
|
saBaseClientLoginUser = clientLoginUserApi.getClientUserById(saBaseClientLoginUser.getId());
|
||||||
|
// 填充C端用户信息并更新缓存
|
||||||
|
fillSaBaseClientLoginUserAndUpdateCache(saBaseClientLoginUser);
|
||||||
|
// 去掉密码
|
||||||
saBaseClientLoginUser.setPassword(null);
|
saBaseClientLoginUser.setPassword(null);
|
||||||
|
// 去掉权限码
|
||||||
saBaseClientLoginUser.setPermissionCodeList(null);
|
saBaseClientLoginUser.setPermissionCodeList(null);
|
||||||
|
// 去掉数据范围
|
||||||
saBaseClientLoginUser.setDataScopeList(null);
|
saBaseClientLoginUser.setDataScopeList(null);
|
||||||
|
// 返回
|
||||||
return saBaseClientLoginUser;
|
return saBaseClientLoginUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,16 +127,6 @@ public class DevSlideshowServiceImpl extends ServiceImpl<DevSlideshowMapper, Dev
|
||||||
List<JSONObject> resultList = CollectionUtil.newArrayList();
|
List<JSONObject> resultList = CollectionUtil.newArrayList();
|
||||||
List<DevSlideshow> slideshowList = this.list(new LambdaQueryWrapper<DevSlideshow>().eq(DevSlideshow::getStatus,
|
List<DevSlideshow> slideshowList = this.list(new LambdaQueryWrapper<DevSlideshow>().eq(DevSlideshow::getStatus,
|
||||||
DevSlideshowStatusEnum.ENABLE.getValue()).orderByDesc(DevSlideshow::getSortCode));
|
DevSlideshowStatusEnum.ENABLE.getValue()).orderByDesc(DevSlideshow::getSortCode));
|
||||||
if (slideshowList.size() == 0) {
|
|
||||||
// 如果库里未配置,则补充一条静态的,避免图片为空
|
|
||||||
JSONObject staticObj = new JSONObject();
|
|
||||||
staticObj.set("id", IdWorker.getIdStr());
|
|
||||||
staticObj.set("title", "静态文件");
|
|
||||||
staticObj.set("image", DevConstants.STATIC_SLIDESHOW_IMAGE);
|
|
||||||
staticObj.set("pathDetails", null);
|
|
||||||
resultList.add(staticObj);
|
|
||||||
return resultList;
|
|
||||||
}
|
|
||||||
slideshowList.forEach((item) -> {
|
slideshowList.forEach((item) -> {
|
||||||
JSONArray slideshowPlaceArray = JSONUtil.parseArray(item.getPlace());
|
JSONArray slideshowPlaceArray = JSONUtil.parseArray(item.getPlace());
|
||||||
slideshowPlaceArray.forEach((placeArray) -> {
|
slideshowPlaceArray.forEach((placeArray) -> {
|
||||||
|
@ -157,6 +147,16 @@ public class DevSlideshowServiceImpl extends ServiceImpl<DevSlideshowMapper, Dev
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
if (resultList.size() == 0) {
|
||||||
|
// 如果库里未配置,则补充一条静态的,避免图片为空
|
||||||
|
JSONObject staticObj = new JSONObject();
|
||||||
|
staticObj.set("id", IdWorker.getIdStr());
|
||||||
|
staticObj.set("title", "静态文件");
|
||||||
|
staticObj.set("image", DevConstants.STATIC_SLIDESHOW_IMAGE);
|
||||||
|
staticObj.set("pathDetails", null);
|
||||||
|
resultList.add(staticObj);
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
return resultList;
|
return resultList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,6 +212,9 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
|
||||||
|
|
||||||
private void checkParam(SysMenuAddParam sysMenuAddParam) {
|
private void checkParam(SysMenuAddParam sysMenuAddParam) {
|
||||||
SysResourceMenuTypeEnum.validate(sysMenuAddParam.getMenuType());
|
SysResourceMenuTypeEnum.validate(sysMenuAddParam.getMenuType());
|
||||||
|
if(sysMenuAddParam.getTitle().contains(StrUtil.DASHED)) {
|
||||||
|
throw new CommonException("title不可包含特殊字符【-】");
|
||||||
|
}
|
||||||
if(SysResourceMenuTypeEnum.MENU.getValue().equals(sysMenuAddParam.getMenuType())) {
|
if(SysResourceMenuTypeEnum.MENU.getValue().equals(sysMenuAddParam.getMenuType())) {
|
||||||
if(ObjectUtil.isEmpty(sysMenuAddParam.getName())) {
|
if(ObjectUtil.isEmpty(sysMenuAddParam.getName())) {
|
||||||
throw new CommonException("name不能为空");
|
throw new CommonException("name不能为空");
|
||||||
|
@ -227,7 +230,6 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
|
||||||
sysMenuAddParam.setName(null);
|
sysMenuAddParam.setName(null);
|
||||||
sysMenuAddParam.setComponent(null);
|
sysMenuAddParam.setComponent(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@ -284,6 +286,9 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
|
||||||
|
|
||||||
private void checkParam(SysMenuEditParam sysMenuEditParam) {
|
private void checkParam(SysMenuEditParam sysMenuEditParam) {
|
||||||
SysResourceMenuTypeEnum.validate(sysMenuEditParam.getMenuType());
|
SysResourceMenuTypeEnum.validate(sysMenuEditParam.getMenuType());
|
||||||
|
if(sysMenuEditParam.getTitle().contains(StrUtil.DASHED)) {
|
||||||
|
throw new CommonException("title不可包含特殊字符【-】");
|
||||||
|
}
|
||||||
if(SysResourceMenuTypeEnum.MENU.getValue().equals(sysMenuEditParam.getMenuType())) {
|
if(SysResourceMenuTypeEnum.MENU.getValue().equals(sysMenuEditParam.getMenuType())) {
|
||||||
if(ObjectUtil.isEmpty(sysMenuEditParam.getName())) {
|
if(ObjectUtil.isEmpty(sysMenuEditParam.getName())) {
|
||||||
throw new CommonException("name不能为空");
|
throw new CommonException("name不能为空");
|
||||||
|
|
Loading…
Reference in New Issue