Merge branch 'master' of https://gitee.com/yudaocode/yudao-ui-admin-vue3 into feature/bpm
# Conflicts: # src/components/bpmnProcessDesigner/package/theme/index.scsspull/583/MERGE
commit
2aa2b4609f
|
@ -69,11 +69,11 @@
|
||||||
|
|
||||||
支持 Spring Boot、Spring Cloud 两种架构:
|
支持 Spring Boot、Spring Cloud 两种架构:
|
||||||
|
|
||||||
① Spring Boot 单体架构:<https://github.com/YunaiV/ruoyi-vue-pro>
|
① Spring Boot 单体架构:<https://doc.iocoder.cn>
|
||||||
|
|
||||||
![架构图](/.image/common/ruoyi-vue-pro-architecture.png)
|
![架构图](/.image/common/ruoyi-vue-pro-architecture.png)
|
||||||
|
|
||||||
② Spring Cloud 微服务架构:<https://github.com/YunaiV/yudao-cloud>
|
② Spring Cloud 微服务架构:<https://cloud.iocoder.cn>
|
||||||
|
|
||||||
![架构图](/.image/common/yudao-cloud-architecture.png)
|
![架构图](/.image/common/yudao-cloud-architecture.png)
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ $--color-danger: #ff4d4f;
|
||||||
/* 改变 icon 字体路径变量,必需 */
|
/* 改变 icon 字体路径变量,必需 */
|
||||||
$--font-path: '~element-ui/lib/theme-chalk/fonts';
|
$--font-path: '~element-ui/lib/theme-chalk/fonts';
|
||||||
|
|
||||||
@import '~element-ui/packages/theme-chalk/src/index';
|
@use '~element-ui/packages/theme-chalk/src/index';
|
||||||
|
|
||||||
.el-table td,
|
.el-table td,
|
||||||
.el-table th {
|
.el-table th {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@import './process-designer.scss';
|
@use './process-designer.scss';
|
||||||
@import './process-panel.scss';
|
@use './process-panel.scss';
|
||||||
|
|
||||||
$success-color: #4eb819;
|
$success-color: #4eb819;
|
||||||
$primary-color: #409EFF;
|
$primary-color: #409EFF;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@import 'bpmn-js-token-simulation/assets/css/bpmn-js-token-simulation.css';
|
@use 'bpmn-js-token-simulation/assets/css/bpmn-js-token-simulation.css';
|
||||||
@import 'bpmn-js-token-simulation/assets/css/font-awesome.min.css';
|
@use 'bpmn-js-token-simulation/assets/css/font-awesome.min.css';
|
||||||
@import 'bpmn-js-token-simulation/assets/css/normalize.css';
|
@use 'bpmn-js-token-simulation/assets/css/normalize.css';
|
||||||
|
|
||||||
// 边框被 token-simulation 样式覆盖了
|
// 边框被 token-simulation 样式覆盖了
|
||||||
.djs-palette {
|
.djs-palette {
|
||||||
|
|
|
@ -8,7 +8,8 @@ export function hasPermi(app: App<Element>) {
|
||||||
const { wsCache } = useCache()
|
const { wsCache } = useCache()
|
||||||
const { value } = binding
|
const { value } = binding
|
||||||
const all_permission = '*:*:*'
|
const all_permission = '*:*:*'
|
||||||
const permissions = wsCache.get(CACHE_KEY.USER).permissions
|
const userInfo = wsCache.get(CACHE_KEY.USER)
|
||||||
|
const permissions = userInfo?.permissions || []
|
||||||
|
|
||||||
if (value && value instanceof Array && value.length > 0) {
|
if (value && value instanceof Array && value.length > 0) {
|
||||||
const permissionFlag = value
|
const permissionFlag = value
|
||||||
|
|
|
@ -7,8 +7,9 @@ export function hasRole(app: App<Element>) {
|
||||||
app.directive('hasRole', (el, binding) => {
|
app.directive('hasRole', (el, binding) => {
|
||||||
const { wsCache } = useCache()
|
const { wsCache } = useCache()
|
||||||
const { value } = binding
|
const { value } = binding
|
||||||
const super_admin = 'admin'
|
const super_admin = 'super_admin'
|
||||||
const roles = wsCache.get(CACHE_KEY.USER).roles
|
const userInfo = wsCache.get(CACHE_KEY.USER)
|
||||||
|
const roles = userInfo?.roles || []
|
||||||
|
|
||||||
if (value && value instanceof Array && value.length > 0) {
|
if (value && value instanceof Array && value.length > 0) {
|
||||||
const roleFlag = value
|
const roleFlag = value
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { formatDate } from '@/utils/formatTime'
|
import { formatDate } from '@/utils/formatTime'
|
||||||
import * as NotifyMessageApi from '@/api/system/notify/message'
|
import * as NotifyMessageApi from '@/api/system/notify/message'
|
||||||
|
import { useUserStoreWithOut } from '@/store/modules/user'
|
||||||
|
|
||||||
defineOptions({ name: 'Message' })
|
defineOptions({ name: 'Message' })
|
||||||
|
|
||||||
const { push } = useRouter()
|
const { push } = useRouter()
|
||||||
|
const userStore = useUserStoreWithOut()
|
||||||
const activeName = ref('notice')
|
const activeName = ref('notice')
|
||||||
const unreadCount = ref(0) // 未读消息数量
|
const unreadCount = ref(0) // 未读消息数量
|
||||||
const list = ref<any[]>([]) // 消息列表
|
const list = ref<any[]>([]) // 消息列表
|
||||||
|
@ -37,7 +39,11 @@ onMounted(() => {
|
||||||
// 轮询刷新小红点
|
// 轮询刷新小红点
|
||||||
setInterval(
|
setInterval(
|
||||||
() => {
|
() => {
|
||||||
getUnreadCount()
|
if (userStore.getIsSetUser) {
|
||||||
|
getUnreadCount()
|
||||||
|
} else {
|
||||||
|
unreadCount.value = 0
|
||||||
|
}
|
||||||
},
|
},
|
||||||
1000 * 60 * 2
|
1000 * 60 * 2
|
||||||
)
|
)
|
||||||
|
|
|
@ -127,12 +127,8 @@ const toLastView = () => {
|
||||||
const moveToCurrentTag = async () => {
|
const moveToCurrentTag = async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
for (const v of unref(visitedViews)) {
|
for (const v of unref(visitedViews)) {
|
||||||
if (v.fullPath === unref(currentRoute).path) {
|
if (v.fullPath === unref(currentRoute).fullPath) {
|
||||||
moveToTarget(v)
|
moveToTarget(v)
|
||||||
if (v.fullPath !== unref(currentRoute).fullPath) {
|
|
||||||
tagsViewStore.updateVisitedView(unref(currentRoute))
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,7 +203,7 @@ const moveToTarget = (currentTag: RouteLocationNormalizedLoaded) => {
|
||||||
|
|
||||||
// 是否是当前tag
|
// 是否是当前tag
|
||||||
const isActive = (route: RouteLocationNormalizedLoaded): boolean => {
|
const isActive = (route: RouteLocationNormalizedLoaded): boolean => {
|
||||||
return route.path === unref(currentRoute).path
|
return route.fullPath === unref(currentRoute).fullPath
|
||||||
}
|
}
|
||||||
|
|
||||||
// 所有右键菜单组件的元素
|
// 所有右键菜单组件的元素
|
||||||
|
@ -373,7 +369,10 @@ watch(
|
||||||
:size="12"
|
:size="12"
|
||||||
class="mr-5px"
|
class="mr-5px"
|
||||||
/>
|
/>
|
||||||
{{ t(item?.meta?.title as string) }}
|
{{
|
||||||
|
t(item?.meta?.title as string) +
|
||||||
|
(item?.meta?.titleSuffix ? ` (${item?.meta?.titleSuffix})` : '')
|
||||||
|
}}
|
||||||
<Icon
|
<Icon
|
||||||
:class="`${prefixCls}__item--close`"
|
:class="`${prefixCls}__item--close`"
|
||||||
:size="12"
|
:size="12"
|
||||||
|
|
|
@ -35,8 +35,9 @@ export const usePermissionStore = defineStore('permission', {
|
||||||
return new Promise<void>(async (resolve) => {
|
return new Promise<void>(async (resolve) => {
|
||||||
// 获得菜单列表,它在登录的时候,setUserInfoAction 方法中已经进行获取
|
// 获得菜单列表,它在登录的时候,setUserInfoAction 方法中已经进行获取
|
||||||
let res: AppCustomRouteRecordRaw[] = []
|
let res: AppCustomRouteRecordRaw[] = []
|
||||||
if (wsCache.get(CACHE_KEY.ROLE_ROUTERS)) {
|
const roleRouters = wsCache.get(CACHE_KEY.ROLE_ROUTERS)
|
||||||
res = wsCache.get(CACHE_KEY.ROLE_ROUTERS) as AppCustomRouteRecordRaw[]
|
if (roleRouters) {
|
||||||
|
res = roleRouters as AppCustomRouteRecordRaw[]
|
||||||
}
|
}
|
||||||
const routerMap: AppRouteRecordRaw[] = generateRoute(res)
|
const routerMap: AppRouteRecordRaw[] = generateRoute(res)
|
||||||
// 动态路由,404一定要放到最后面
|
// 动态路由,404一定要放到最后面
|
||||||
|
|
|
@ -31,13 +31,27 @@ export const useTagsViewStore = defineStore('tagsView', {
|
||||||
},
|
},
|
||||||
// 新增tag
|
// 新增tag
|
||||||
addVisitedView(view: RouteLocationNormalizedLoaded) {
|
addVisitedView(view: RouteLocationNormalizedLoaded) {
|
||||||
if (this.visitedViews.some((v) => v.path === view.path)) return
|
if (this.visitedViews.some((v) => v.fullPath === view.fullPath)) return
|
||||||
if (view.meta?.noTagsView) return
|
if (view.meta?.noTagsView) return
|
||||||
this.visitedViews.push(
|
const visitedView = Object.assign({}, view, { title: view.meta?.title || 'no-name' })
|
||||||
Object.assign({}, view, {
|
|
||||||
title: view.meta?.title || 'no-name'
|
if (visitedView.meta) {
|
||||||
|
const titleSuffixList: string[] = []
|
||||||
|
this.visitedViews.forEach((v) => {
|
||||||
|
if (v.path === visitedView.path && v.meta?.title === visitedView.meta?.title) {
|
||||||
|
titleSuffixList.push(v.meta?.titleSuffix || '1')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
)
|
if (titleSuffixList.length) {
|
||||||
|
let titleSuffix = 1
|
||||||
|
while (titleSuffixList.includes(`${titleSuffix}`)) {
|
||||||
|
titleSuffix += 1
|
||||||
|
}
|
||||||
|
visitedView.meta.titleSuffix = titleSuffix === 1 ? undefined : `${titleSuffix}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.visitedViews.push(visitedView)
|
||||||
},
|
},
|
||||||
// 新增缓存
|
// 新增缓存
|
||||||
addCachedView() {
|
addCachedView() {
|
||||||
|
@ -63,7 +77,7 @@ export const useTagsViewStore = defineStore('tagsView', {
|
||||||
// 删除tag
|
// 删除tag
|
||||||
delVisitedView(view: RouteLocationNormalizedLoaded) {
|
delVisitedView(view: RouteLocationNormalizedLoaded) {
|
||||||
for (const [i, v] of this.visitedViews.entries()) {
|
for (const [i, v] of this.visitedViews.entries()) {
|
||||||
if (v.path === view.path) {
|
if (v.fullPath === view.fullPath) {
|
||||||
this.visitedViews.splice(i, 1)
|
this.visitedViews.splice(i, 1)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -95,18 +109,18 @@ export const useTagsViewStore = defineStore('tagsView', {
|
||||||
// 删除其他tag
|
// 删除其他tag
|
||||||
delOthersVisitedViews(view: RouteLocationNormalizedLoaded) {
|
delOthersVisitedViews(view: RouteLocationNormalizedLoaded) {
|
||||||
this.visitedViews = this.visitedViews.filter((v) => {
|
this.visitedViews = this.visitedViews.filter((v) => {
|
||||||
return v?.meta?.affix || v.path === view.path
|
return v?.meta?.affix || v.fullPath === view.fullPath
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// 删除左侧
|
// 删除左侧
|
||||||
delLeftViews(view: RouteLocationNormalizedLoaded) {
|
delLeftViews(view: RouteLocationNormalizedLoaded) {
|
||||||
const index = findIndex<RouteLocationNormalizedLoaded>(
|
const index = findIndex<RouteLocationNormalizedLoaded>(
|
||||||
this.visitedViews,
|
this.visitedViews,
|
||||||
(v) => v.path === view.path
|
(v) => v.fullPath === view.fullPath
|
||||||
)
|
)
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this.visitedViews = this.visitedViews.filter((v, i) => {
|
this.visitedViews = this.visitedViews.filter((v, i) => {
|
||||||
return v?.meta?.affix || v.path === view.path || i > index
|
return v?.meta?.affix || v.fullPath === view.fullPath || i > index
|
||||||
})
|
})
|
||||||
this.addCachedView()
|
this.addCachedView()
|
||||||
}
|
}
|
||||||
|
@ -115,18 +129,18 @@ export const useTagsViewStore = defineStore('tagsView', {
|
||||||
delRightViews(view: RouteLocationNormalizedLoaded) {
|
delRightViews(view: RouteLocationNormalizedLoaded) {
|
||||||
const index = findIndex<RouteLocationNormalizedLoaded>(
|
const index = findIndex<RouteLocationNormalizedLoaded>(
|
||||||
this.visitedViews,
|
this.visitedViews,
|
||||||
(v) => v.path === view.path
|
(v) => v.fullPath === view.fullPath
|
||||||
)
|
)
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this.visitedViews = this.visitedViews.filter((v, i) => {
|
this.visitedViews = this.visitedViews.filter((v, i) => {
|
||||||
return v?.meta?.affix || v.path === view.path || i < index
|
return v?.meta?.affix || v.fullPath === view.fullPath || i < index
|
||||||
})
|
})
|
||||||
this.addCachedView()
|
this.addCachedView()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateVisitedView(view: RouteLocationNormalizedLoaded) {
|
updateVisitedView(view: RouteLocationNormalizedLoaded) {
|
||||||
for (let v of this.visitedViews) {
|
for (let v of this.visitedViews) {
|
||||||
if (v.path === view.path) {
|
if (v.fullPath === view.fullPath) {
|
||||||
v = Object.assign(v, view)
|
v = Object.assign(v, view)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
@import './variables.scss';
|
@use './variables.scss' as *;
|
||||||
// 导出变量
|
// 导出变量
|
||||||
:export {
|
:export {
|
||||||
namespace: $namespace;
|
namespace: $namespace;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
@import './var.css';
|
@use './var.css';
|
||||||
@import './FormCreate/index.scss';
|
@use './FormCreate/index.scss';
|
||||||
@import './theme.scss';
|
@use './theme.scss';
|
||||||
@import 'element-plus/theme-chalk/dark/css-vars.css';
|
@use 'element-plus/theme-chalk/dark/css-vars.css';
|
||||||
|
|
||||||
.reset-margin [class*='el-icon'] + span {
|
.reset-margin [class*='el-icon'] + span {
|
||||||
margin-left: 2px !important;
|
margin-left: 2px !important;
|
||||||
|
|
|
@ -10,7 +10,8 @@ const RefreshTokenKey = 'REFRESH_TOKEN'
|
||||||
// 获取token
|
// 获取token
|
||||||
export const getAccessToken = () => {
|
export const getAccessToken = () => {
|
||||||
// 此处与TokenKey相同,此写法解决初始化时Cookies中不存在TokenKey报错
|
// 此处与TokenKey相同,此写法解决初始化时Cookies中不存在TokenKey报错
|
||||||
return wsCache.get(AccessTokenKey) ? wsCache.get(AccessTokenKey) : wsCache.get('ACCESS_TOKEN')
|
const accessToken = wsCache.get(AccessTokenKey)
|
||||||
|
return accessToken ? accessToken : wsCache.get('ACCESS_TOKEN')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 刷新token
|
// 刷新token
|
||||||
|
|
|
@ -98,8 +98,9 @@ export const isServer = typeof window === 'undefined'
|
||||||
export const isClient = !isServer
|
export const isClient = !isServer
|
||||||
|
|
||||||
export const isUrl = (path: string): boolean => {
|
export const isUrl = (path: string): boolean => {
|
||||||
|
// fix:修复hash路由无法跳转的问题
|
||||||
const reg =
|
const reg =
|
||||||
/(((^https?:(?:\/\/)?)(?:[-:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&%@.\w_]*)#?(?:[\w]*))?)$/
|
/(((^https?:(?:\/\/)?)(?:[-:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%#\/.\w-_]*)?\??(?:[-\+=&%@.\w_]*)#?(?:[\w]*))?)$/
|
||||||
return reg.test(path)
|
return reg.test(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,9 @@ export function checkPermi(value: string[]) {
|
||||||
const { wsCache } = useCache()
|
const { wsCache } = useCache()
|
||||||
const permissionDatas = value
|
const permissionDatas = value
|
||||||
const all_permission = '*:*:*'
|
const all_permission = '*:*:*'
|
||||||
const permissions = wsCache.get(CACHE_KEY.USER).permissions
|
const userInfo = wsCache.get(CACHE_KEY.USER)
|
||||||
const hasPermission = permissions.some((permission) => {
|
const permissions = userInfo?.permissions || []
|
||||||
|
const hasPermission = permissions.some((permission: string) => {
|
||||||
return all_permission === permission || permissionDatas.includes(permission)
|
return all_permission === permission || permissionDatas.includes(permission)
|
||||||
})
|
})
|
||||||
return !!hasPermission
|
return !!hasPermission
|
||||||
|
@ -32,9 +33,10 @@ export function checkRole(value: string[]) {
|
||||||
if (value && value instanceof Array && value.length > 0) {
|
if (value && value instanceof Array && value.length > 0) {
|
||||||
const { wsCache } = useCache()
|
const { wsCache } = useCache()
|
||||||
const permissionRoles = value
|
const permissionRoles = value
|
||||||
const super_admin = 'admin'
|
const super_admin = 'super_admin'
|
||||||
const roles = wsCache.get(CACHE_KEY.USER).roles
|
const userInfo = wsCache.get(CACHE_KEY.USER)
|
||||||
const hasRole = roles.some((role) => {
|
const roles = userInfo?.roles || []
|
||||||
|
const hasRole = roles.some((role: string) => {
|
||||||
return super_admin === role || permissionRoles.includes(role)
|
return super_admin === role || permissionRoles.includes(role)
|
||||||
})
|
})
|
||||||
return !!hasRole
|
return !!hasRole
|
||||||
|
|
|
@ -80,6 +80,7 @@
|
||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<ContentWrap>
|
<ContentWrap>
|
||||||
<el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
|
<el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true">
|
||||||
|
<el-table-column align="center" label="ID" min-width="180" prop="id" />
|
||||||
<el-table-column align="center" label="封面" min-width="80" prop="picUrl">
|
<el-table-column align="center" label="封面" min-width="80" prop="picUrl">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-image :src="row.picUrl" class="h-30px w-30px" @click="imagePreview(row.picUrl)" />
|
<el-image :src="row.picUrl" class="h-30px w-30px" @click="imagePreview(row.picUrl)" />
|
||||||
|
|
|
@ -121,7 +121,7 @@
|
||||||
label="创建时间"
|
label="创建时间"
|
||||||
align="center"
|
align="center"
|
||||||
prop="createTime"
|
prop="createTime"
|
||||||
width="180"
|
width="170"
|
||||||
:formatter="dateFormatter"
|
:formatter="dateFormatter"
|
||||||
/>
|
/>
|
||||||
<el-table-column label="支付金额" align="center" prop="payPrice" width="100">
|
<el-table-column label="支付金额" align="center" prop="payPrice" width="100">
|
||||||
|
@ -157,7 +157,7 @@
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="退款状态" align="center" prop="status">
|
<el-table-column label="退款状态" align="center" prop="status" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="scope.row.status" />
|
<dict-tag :type="DICT_TYPE.PAY_REFUND_STATUS" :value="scope.row.status" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -15,6 +15,8 @@ import { defineComponent } from 'vue'
|
||||||
|
|
||||||
title: 'title' 设置该路由在侧边栏和面包屑中展示的名字
|
title: 'title' 设置该路由在侧边栏和面包屑中展示的名字
|
||||||
|
|
||||||
|
titleSuffix: '2' 当 path 和 title 重复时的后缀或备注
|
||||||
|
|
||||||
icon: 'svg-name' 设置该路由的图标
|
icon: 'svg-name' 设置该路由的图标
|
||||||
|
|
||||||
noCache: true 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
|
noCache: true 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
|
||||||
|
@ -37,6 +39,7 @@ declare module 'vue-router' {
|
||||||
hidden?: boolean
|
hidden?: boolean
|
||||||
alwaysShow?: boolean
|
alwaysShow?: boolean
|
||||||
title?: string
|
title?: string
|
||||||
|
titleSuffix?: string
|
||||||
icon?: string
|
icon?: string
|
||||||
noCache?: boolean
|
noCache?: boolean
|
||||||
breadcrumb?: boolean
|
breadcrumb?: boolean
|
||||||
|
|
|
@ -43,7 +43,7 @@ export default ({command, mode}: ConfigEnv): UserConfig => {
|
||||||
css: {
|
css: {
|
||||||
preprocessorOptions: {
|
preprocessorOptions: {
|
||||||
scss: {
|
scss: {
|
||||||
additionalData: '@import "./src/styles/variables.scss";',
|
additionalData: '@use "@/styles/variables.scss" as *;',
|
||||||
javascriptEnabled: true
|
javascriptEnabled: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue