zhou zhou
17 小时以前 cd95f8f1b8a4c3e00eae763714c9542319885cca
#前端
7个文件已修改
118 ■■■■■ 已修改文件
rsf-design/package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/pnpm-lock.yaml 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/components/core/layouts/art-header-bar/index.vue 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/components/core/layouts/art-menus/art-sidebar-menu/index.vue 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/components/core/layouts/art-menus/art-sidebar-menu/style.scss 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/components/core/layouts/art-settings-panel/composables/useSettingsState.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/main.js 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/package.json
@@ -57,6 +57,7 @@
  },
  "devDependencies": {
    "@eslint/js": "^9.9.1",
    "@playwright/test": "^1.58.2",
    "@types/node": "^24.0.5",
    "@vitejs/plugin-vue": "^6.0.1",
    "@vue/compiler-sfc": "^3.0.5",
rsf-design/pnpm-lock.yaml
@@ -117,6 +117,9 @@
      '@eslint/js':
        specifier: ^9.9.1
        version: 9.36.0
      '@playwright/test':
        specifier: ^1.58.2
        version: 1.58.2
      '@types/node':
        specifier: ^24.0.5
        version: 24.8.1
@@ -788,6 +791,11 @@
  '@pkgr/core@0.2.9':
    resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==}
    engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
  '@playwright/test@1.58.2':
    resolution: {integrity: sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==}
    engines: {node: '>=18'}
    hasBin: true
  '@polka/url@1.0.0-next.29':
    resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
@@ -1829,6 +1837,11 @@
    resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==}
    engines: {node: '>=14.14'}
  fsevents@2.3.2:
    resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
    os: [darwin]
  fsevents@2.3.3:
    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -2437,6 +2450,16 @@
  pkg-types@2.3.0:
    resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
  playwright-core@1.58.2:
    resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==}
    engines: {node: '>=18'}
    hasBin: true
  playwright@1.58.2:
    resolution: {integrity: sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==}
    engines: {node: '>=18'}
    hasBin: true
  postcss-html@1.8.0:
    resolution: {integrity: sha512-5mMeb1TgLWoRKxZ0Xh9RZDfwUUIqRrcxO2uXO+Ezl1N5lqpCiSU5Gk6+1kZediBfBHFtPCdopr2UZ2SgUsKcgQ==}
@@ -3654,6 +3677,10 @@
  '@pkgr/core@0.2.9': {}
  '@playwright/test@1.58.2':
    dependencies:
      playwright: 1.58.2
  '@polka/url@1.0.0-next.29': {}
  '@rolldown/pluginutils@1.0.0-beta.29': {}
@@ -4752,6 +4779,9 @@
      jsonfile: 6.2.0
      universalify: 2.0.1
  fsevents@2.3.2:
    optional: true
  fsevents@2.3.3:
    optional: true
@@ -5246,6 +5276,14 @@
      exsolve: 1.0.7
      pathe: 2.0.3
  playwright-core@1.58.2: {}
  playwright@1.58.2:
    dependencies:
      playwright-core: 1.58.2
    optionalDependencies:
      fsevents: 2.3.2
  postcss-html@1.8.0:
    dependencies:
      htmlparser2: 8.0.2
rsf-design/src/components/core/layouts/art-header-bar/index.vue
@@ -54,10 +54,10 @@
        />
        <!-- 顶部菜单 -->
        <ArtHorizontalMenu v-if="isTopMenu" :list="menuList" />
        <ArtHorizontalMenu v-if="isTopMenu" :key="topMenuRenderKey" :list="menuList" />
        <!-- 混合菜单-顶部 -->
        <ArtMixedMenu v-if="isTopLeftMenu" :list="menuList" />
        <ArtMixedMenu v-if="isTopLeftMenu" :key="topMenuRenderKey" :list="menuList" />
      </div>
      <div class="flex-c gap-2.5">
@@ -175,7 +175,7 @@
  import { themeAnimation } from '@/utils/ui/animation'
  import { useI18n } from 'vue-i18n'
  import { useRouter } from 'vue-router'
  import { useRoute, useRouter } from 'vue-router'
  import { useFullscreen, useWindowSize } from '@vueuse/core'
  import { MenuTypeEnum } from '@/enums/appEnum'
  import { useSettingStore } from '@/store/modules/setting'
@@ -186,6 +186,7 @@
  import { useHeaderBar } from '@/hooks/core/useHeaderBar'
  defineOptions({ name: 'ArtHeaderBar' })
  const isWindows = navigator.userAgent.includes('Windows')
  const route = useRoute()
  const router = useRouter()
  const { locale } = useI18n()
  const { width } = useWindowSize()
@@ -216,6 +217,9 @@
  const isDualMenu = computed(() => menuType.value === MenuTypeEnum.DUAL_MENU)
  const isTopMenu = computed(() => menuType.value === MenuTypeEnum.TOP)
  const isTopLeftMenu = computed(() => menuType.value === MenuTypeEnum.TOP_LEFT)
  const topMenuRenderKey = computed(() => {
    return `${menuType.value}:${String(route.meta.activePath || route.path)}`
  })
  const { isFullscreen, toggle: toggleFullscreen } = useFullscreen()
  onMounted(() => {
    initLanguage()
rsf-design/src/components/core/layouts/art-menus/art-sidebar-menu/index.vue
@@ -88,6 +88,7 @@
      </div>
      <ElScrollbar :style="scrollbarStyle">
        <ElMenu
          :key="menuRenderKey"
          :class="'el-menu-' + getMenuTheme.theme"
          :collapse="!menuOpen"
          :default-active="routerPath"
@@ -161,8 +162,35 @@
  )
  const isDualMenu = computed(() => menuType.value === MenuTypeEnum.DUAL_MENU)
  const isMobileScreen = computed(() => width.value < MOBILE_BREAKPOINT)
  const firstLevelMenuPath = computed(() => route.matched[0]?.path)
  const routerPath = computed(() => String(route.meta.activePath || route.path))
  const normalizeRoutePath = (path) => {
    if (!path) {
      return ''
    }
    return `/${String(path).replace(/^\/+/, '').replace(/\/+$/, '')}`
  }
  const findTopLevelMenuByPath = (menus, targetPath) => {
    const normalizedTargetPath = normalizeRoutePath(targetPath)
    const containsPath = (menu) => {
      if (!menu) {
        return false
      }
      if (normalizeRoutePath(menu.path) === normalizedTargetPath) {
        return true
      }
      if (!Array.isArray(menu.children) || menu.children.length === 0) {
        return false
      }
      return menu.children.some((child) => containsPath(child))
    }
    return menus.find((menu) => containsPath(menu)) || null
  }
  const currentTopLevelMenu = computed(() => {
    return findTopLevelMenuByPath(useMenuStore().menuList, routerPath.value)
  })
  const firstLevelMenuPath = computed(
    () => currentTopLevelMenu.value?.path || route.matched[0]?.path
  )
  const firstLevelMenus = computed(() => {
    return useMenuStore().menuList.filter((menu) => !menu.meta.isHide)
  })
@@ -178,9 +206,10 @@
    if (route.meta.isFirstLevel) {
      return []
    }
    const currentTopPath = `/${route.path.split('/')[1]}`
    const currentMenu = allMenus.find((menu) => menu.path === currentTopPath)
    return currentMenu?.children ?? []
    return currentTopLevelMenu.value?.children ?? []
  })
  const menuRenderKey = computed(() => {
    return `${menuType.value}:${firstLevelMenuPath.value || 'root'}`
  })
  const scrollbarStyle = computed(() => {
    const isCollapsed = isDualMenu.value && !menuOpen.value
rsf-design/src/components/core/layouts/art-menus/art-sidebar-menu/style.scss
@@ -49,8 +49,13 @@
          border-radius: 5px;
          .art-svg-icon {
            display: block;
            margin: 0 auto;
            display: flex !important;
            align-items: center;
            justify-content: center;
            width: 100%;
            margin: 0 auto !important;
            margin-right: auto !important;
            margin-left: auto !important;
            font-size: 20px;
          }
rsf-design/src/components/core/layouts/art-settings-panel/composables/useSettingsState.js
@@ -1,3 +1,4 @@
import { nextTick } from 'vue'
import { useSettingStore } from '@/store/modules/setting'
import { MenuThemeEnum, MenuTypeEnum } from '@/enums/appEnum'
function useSettingsState() {
@@ -11,6 +12,9 @@
    }
  }
  const switchMenuLayouts = (type) => {
    if (settingStore.menuType === type) {
      return
    }
    if (type === MenuTypeEnum.LEFT || type === MenuTypeEnum.TOP_LEFT) {
      settingStore.setMenuOpen(true)
    }
@@ -19,6 +23,9 @@
      settingStore.switchMenuStyles(MenuThemeEnum.DESIGN)
      settingStore.setMenuOpen(true)
    }
    nextTick(() => {
      settingStore.reload()
    })
  }
  return {
    // 方法
rsf-design/src/main.js
@@ -12,6 +12,22 @@
document.addEventListener('touchstart', function () {}, { passive: false })
registerLocalIconCollections()
const app = createApp(App)
// 注入错误日志面板用于调试
app.config.errorHandler = (err, vm, info) => {
  console.error("Vue Error:", err, info);
  const div = document.createElement("div");
  div.style = "position:fixed;top:0;left:0;z-index:99999;background:red;color:white;padding:20px;font-size:16px;white-space:pre-wrap;width:100vw;height:100vh;overflow:auto;";
  div.innerText = "Error: " + (err.message || err) + "\n\nStack:\n" + err.stack + "\n\nInfo: " + info;
  document.body.appendChild(div);
};
window.addEventListener("error", (event) => {
  const div = document.createElement("div");
  div.style = "position:fixed;top:0;left:0;z-index:99999;background:red;color:white;padding:20px;font-size:16px;white-space:pre-wrap;width:100vw;height:100vh;overflow:auto;";
  div.innerText = "Global Error: " + event.message + "\n\n" + event.error?.stack;
  document.body.appendChild(div);
});
initStore(app)
initRouter(app)
setupGlobDirectives(app)