Merge branch 'master' of https://gitee.com/yudaocode/yudao-ui-admin-vue3 into feature/bpm

# Conflicts:
#	src/components/bpmnProcessDesigner/package/theme/index.scss
pull/583/MERGE
YunaiV 2024-11-09 19:01:12 +08:00
commit 2aa2b4609f
19 changed files with 78 additions and 48 deletions

View File

@ -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)

View File

@ -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 {

View File

@ -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;

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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
) )

View File

@ -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"

View File

@ -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一定要放到最后面

View File

@ -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
} }

View File

@ -1,4 +1,4 @@
@import './variables.scss'; @use './variables.scss' as *;
// //
:export { :export {
namespace: $namespace; namespace: $namespace;

View File

@ -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;

View File

@ -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

View File

@ -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)
} }

View File

@ -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

View File

@ -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)" />

View File

@ -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>

3
types/router.d.ts vendored
View File

@ -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

View File

@ -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
} }
} }