Эх сурвалжийг харах

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

# Conflicts:
#	src/components/bpmnProcessDesigner/package/theme/index.scss
YunaiV 9 сар өмнө
parent
commit
2aa2b4609f

+ 2 - 2
README.md

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

+ 1 - 1
src/components/bpmnProcessDesigner/package/theme/element-variables.scss

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

+ 2 - 2
src/components/bpmnProcessDesigner/package/theme/index.scss

@@ -1,5 +1,5 @@
-@import './process-designer.scss';
-@import './process-panel.scss';
+@use './process-designer.scss';
+@use './process-panel.scss';
 
 
 $success-color: #4eb819;
 $success-color: #4eb819;
 $primary-color: #409EFF;
 $primary-color: #409EFF;

+ 3 - 3
src/components/bpmnProcessDesigner/package/theme/process-designer.scss

@@ -1,6 +1,6 @@
-@import 'bpmn-js-token-simulation/assets/css/bpmn-js-token-simulation.css';
-@import '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/bpmn-js-token-simulation.css';
+@use 'bpmn-js-token-simulation/assets/css/font-awesome.min.css';
+@use 'bpmn-js-token-simulation/assets/css/normalize.css';
 
 
 // 边框被 token-simulation 样式覆盖了
 // 边框被 token-simulation 样式覆盖了
 .djs-palette {
 .djs-palette {

+ 2 - 1
src/directives/permission/hasPermi.ts

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

+ 3 - 2
src/directives/permission/hasRole.ts

@@ -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 roles = wsCache.get(CACHE_KEY.USER).roles
+    const super_admin = 'super_admin'
+    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

+ 7 - 1
src/layout/components/Message/src/Message.vue

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

+ 6 - 7
src/layout/components/TagsView/src/TagsView.vue

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

+ 3 - 2
src/store/modules/permission.ts

@@ -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)) {
-          res = wsCache.get(CACHE_KEY.ROLE_ROUTERS) as AppCustomRouteRecordRaw[]
+        const roleRouters = wsCache.get(CACHE_KEY.ROLE_ROUTERS)
+        if (roleRouters) {
+          res = roleRouters as AppCustomRouteRecordRaw[]
         }
         }
         const routerMap: AppRouteRecordRaw[] = generateRoute(res)
         const routerMap: AppRouteRecordRaw[] = generateRoute(res)
         // 动态路由,404一定要放到最后面
         // 动态路由,404一定要放到最后面

+ 26 - 12
src/store/modules/tagsView.ts

@@ -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(
-        Object.assign({}, view, {
-          title: view.meta?.title || 'no-name'
+      const visitedView = 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 - 1
src/styles/global.module.scss

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

+ 4 - 4
src/styles/index.scss

@@ -1,7 +1,7 @@
-@import './var.css';
-@import './FormCreate/index.scss';
-@import './theme.scss';
-@import 'element-plus/theme-chalk/dark/css-vars.css';
+@use './var.css';
+@use './FormCreate/index.scss';
+@use './theme.scss';
+@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;

+ 2 - 1
src/utils/auth.ts

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

+ 2 - 1
src/utils/is.ts

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

+ 7 - 5
src/utils/permission.ts

@@ -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 hasPermission = permissions.some((permission) => {
+    const userInfo = wsCache.get(CACHE_KEY.USER)
+    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 roles = wsCache.get(CACHE_KEY.USER).roles
-    const hasRole = roles.some((role) => {
+    const super_admin = 'super_admin'
+    const userInfo = wsCache.get(CACHE_KEY.USER)
+    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

+ 1 - 0
src/views/mall/promotion/article/index.vue

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

+ 2 - 2
src/views/pay/refund/index.vue

@@ -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 - 0
types/router.d.ts

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

+ 1 - 1
vite.config.ts

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