befly-admin 3.4.4 → 3.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/.env +4 -0
  2. package/.env.development +2 -0
  3. package/.env.production +2 -0
  4. package/bunfig.toml +4 -0
  5. package/package.json +12 -6
  6. package/src/config/internal/index.ts +20 -0
  7. package/src/layouts/internal/0.vue +3 -2
  8. package/src/plugins/internal/global.ts +27 -0
  9. package/src/plugins/internal/router.ts +2 -2
  10. package/src/types/auto-imports.d.ts +111 -17
  11. package/src/types/components.d.ts +27 -0
  12. package/src/views/internal/admin/index.vue +13 -6
  13. package/src/views/internal/dict/index.vue +4 -4
  14. package/src/views/internal/index/components/addonList.vue +2 -2
  15. package/src/views/internal/index/components/environmentInfo.vue +1 -1
  16. package/src/views/internal/index/components/operationLogs.vue +1 -1
  17. package/src/views/internal/index/components/performanceMetrics.vue +6 -6
  18. package/src/views/internal/index/components/quickActions.vue +1 -1
  19. package/src/views/internal/index/components/serviceStatus.vue +11 -23
  20. package/src/views/internal/index/components/systemNotifications.vue +6 -12
  21. package/src/views/internal/index/components/systemOverview.vue +4 -4
  22. package/src/views/internal/index/components/systemResources.vue +4 -4
  23. package/src/views/internal/index/components/userInfo.vue +5 -5
  24. package/src/views/internal/login/components/emailLoginForm.vue +2 -2
  25. package/src/views/internal/login/components/registerForm.vue +4 -4
  26. package/src/views/internal/menu/index.vue +5 -5
  27. package/src/views/internal/role/index.vue +6 -6
  28. package/src/views/internal/user/user.vue +3 -3
  29. package/vite.config.ts +37 -42
  30. package/src/components/internal/Icon.vue +0 -41
  31. package/src/plugins/internal/store.ts +0 -19
package/.env ADDED
@@ -0,0 +1,4 @@
1
+ # 所有环境共享的基础配置
2
+
3
+ # 应用标题
4
+ VITE_APP_TITLE=野蜂飞舞后台管理
package/.env.development CHANGED
@@ -2,4 +2,6 @@
2
2
 
3
3
  # 接口请求地址
4
4
  VITE_API_BASE_URL=http://localhost:3000/api
5
+
6
+ # 存储命名空间
5
7
  VITE_STORAGE_NAMESPACE=befly_admin_dev
package/.env.production CHANGED
@@ -2,4 +2,6 @@
2
2
 
3
3
  # 接口请求地址(部署时修改为实际的生产环境地址)
4
4
  VITE_API_BASE_URL=https://api.your-domain.com/api
5
+
6
+ # 存储命名空间
5
7
  VITE_STORAGE_NAMESPACE=befly_admin_prod
package/bunfig.toml ADDED
@@ -0,0 +1,4 @@
1
+ [install]
2
+ linker = "isolated"
3
+
4
+ publicHoistPattern = ["@types*", "*eslint*", "@opentiny/*"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "befly-admin",
3
- "version": "3.4.4",
3
+ "version": "3.4.6",
4
4
  "description": "Befly Admin - 基于 Vue3 + OpenTiny Vue 的后台管理系统",
5
5
  "type": "module",
6
6
  "private": false,
@@ -14,9 +14,11 @@
14
14
  "index.html",
15
15
  "vite.config.ts",
16
16
  "tsconfig.json",
17
+ ".env",
17
18
  ".env.development",
18
19
  ".env.production",
19
20
  ".gitignore",
21
+ "bunfig.toml",
20
22
  "README.md"
21
23
  ],
22
24
  "scripts": {
@@ -29,26 +31,30 @@
29
31
  "dependencies": {
30
32
  "@opentiny/vue": "^3.27.0",
31
33
  "axios": "^1.13.2",
32
- "befly-auto-routes": "^1.1.0",
33
- "lucide-vue-next": "^0.552.0",
34
34
  "pinia": "^3.0.4",
35
35
  "vue": "^3.5.22",
36
36
  "vue-router": "^4.6.3"
37
37
  },
38
38
  "devDependencies": {
39
+ "@iconify-json/lucide": "^1.2.72",
40
+ "@iconify/json": "^2.2.280",
39
41
  "@opentiny/unplugin-tiny-vue": "^1.0.0",
40
42
  "@vitejs/plugin-vue": "^6.0.1",
41
43
  "@vue-macros/reactivity-transform": "^3.1.1",
44
+ "@vue/compiler-sfc": "^3.5.22",
45
+ "befly-auto-routes": "1.1.0",
46
+ "merge-anything": "^6.0.6",
42
47
  "sass": "^1.93.3",
43
48
  "typescript": "^5.9.3",
44
49
  "unplugin-auto-import": "^20.2.0",
50
+ "unplugin-icons": "^0.22.0",
45
51
  "unplugin-vue-components": "^30.0.0",
46
52
  "vite": "^7.2.0",
47
53
  "vue-tsc": "^3.1.3"
48
54
  },
49
55
  "engines": {
50
- "node": ">=22.0.0",
51
- "pnpm": ">=9.0.0"
56
+ "node": ">=24.0.0",
57
+ "pnpm": ">=10.0.0"
52
58
  },
53
- "gitHead": "89c8192543fa32a6fccac3d092265de45e00aabb"
59
+ "gitHead": "c0844203f8fee734d2a8742f3b77b67bf0874681"
54
60
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 内部配置
3
+ * 存放框架内置的配置变量,不建议修改
4
+ */
5
+
6
+ /**
7
+ * 内置配置对象
8
+ */
9
+ export const $ConfigInternal = {
10
+ /** 应用标题 */
11
+ appTitle: import.meta.env.VITE_APP_TITLE || '管理后台',
12
+ /** API 基础地址 */
13
+ apiBaseUrl: import.meta.env.VITE_API_BASE_URL || '',
14
+ /** 存储命名空间 */
15
+ storageNamespace: import.meta.env.VITE_STORAGE_NAMESPACE || 'befly_admin',
16
+ /** 是否开发环境 */
17
+ isDev: import.meta.env.DEV,
18
+ /** 是否生产环境 */
19
+ isProd: import.meta.env.PROD
20
+ };
@@ -3,7 +3,7 @@
3
3
  <!-- 顶部导航栏 -->
4
4
  <div class="layout-header">
5
5
  <div class="logo">
6
- <h2>野蜂飞舞后台管理</h2>
6
+ <h2>{{ global.data.appTitle }}</h2>
7
7
  </div>
8
8
  <div class="header-right">
9
9
  <tiny-dropdown title="管理员" trigger="click" border type="info" @item-click="$Method.handleUserMenu">
@@ -21,7 +21,7 @@
21
21
  <tiny-tree-menu :data="$Data.userMenus" :props="{ label: 'name' }" node-key="id" :node-height="40" :show-filter="false" :default-expanded-keys="$Data.expandedKeys" :default-expanded-keys-highlight="$Data.currentNodeKey" style="height: 100%" only-check-children width-adapt @node-click="$Method.onMenuClick">
22
22
  <template #default="{ data }">
23
23
  <span class="menu-item">
24
- <Icon :name="data.icon || 'Squircle'" :size="16" style="margin-right: 8px; vertical-align: middle" />
24
+ <i-lucide:square style="width: 16px; height: 16px; margin-right: 8px; vertical-align: middle" />
25
25
  <span>{{ data.name }}</span>
26
26
  </span>
27
27
  </template>
@@ -40,6 +40,7 @@ import { arrayToTree } from '@/utils';
40
40
 
41
41
  const router = useRouter();
42
42
  const route = useRoute();
43
+ const global = useGlobal();
43
44
 
44
45
  // 响应式数据
45
46
  const $Data = $ref({
@@ -0,0 +1,27 @@
1
+ import { defineStore } from 'pinia';
2
+
3
+ /**
4
+ * 全局状态管理
5
+ * 集中管理所有全局数据,避免分散到多个 store 文件
6
+ */
7
+ export const useGlobal = defineStore('global', () => {
8
+ // ==================== 全局数据 ====================
9
+ const data = $ref({});
10
+
11
+ // ==================== 全局方法 ====================
12
+ const method = {
13
+ /**
14
+ * 设置页面标题
15
+ * @param title 标题文本
16
+ */
17
+ setPageTitle: (title?: string) => {
18
+ document.title = title ? `${title} - ${$ConfigInternal.appTitle}` : $ConfigInternal.appTitle;
19
+ }
20
+ };
21
+
22
+ // ==================== 返回 ====================
23
+ return {
24
+ data,
25
+ method
26
+ };
27
+ });
@@ -28,11 +28,11 @@ router.beforeEach(async (to, from, next) => {
28
28
 
29
29
  // 1. 未登录且访问受保护路由 → 跳转登录
30
30
  if (!token && isProtectedRoute) {
31
- return next('/login');
31
+ return next('/internal/login');
32
32
  }
33
33
 
34
34
  // 2. 已登录访问登录页 → 跳转首页
35
- if (token && to.path === '/login') {
35
+ if (token && to.path === '/internal/login') {
36
36
  return next('/');
37
37
  }
38
38
 
@@ -6,28 +6,29 @@
6
6
  // biome-ignore lint: disable
7
7
  export {}
8
8
  declare global {
9
+ const $ConfigInternal: typeof import('../config/internal/index')['$ConfigInternal']
9
10
  const $Http: typeof import('../plugins/internal/http')['$Http']
10
- const $Session: typeof import('../plugins/storage')['$Session']
11
+ const $Session: (typeof import('../plugins/storage'))['$Session']
11
12
  const $Storage: typeof import('../plugins/internal/storage')['$Storage']
12
- const AppIcon: typeof import('tdesign-icons-vue-next')['AppIcon']
13
- const DashboardIcon: typeof import('tdesign-icons-vue-next')['DashboardIcon']
14
- const DialogPlugin: typeof import('tdesign-vue-next')['DialogPlugin']
13
+ const AppIcon: (typeof import('tdesign-icons-vue-next'))['AppIcon']
14
+ const DashboardIcon: (typeof import('tdesign-icons-vue-next'))['DashboardIcon']
15
+ const DialogPlugin: (typeof import('tdesign-vue-next'))['DialogPlugin']
15
16
  const EffectScope: typeof import('vue')['EffectScope']
16
- const FileIcon: typeof import('tdesign-icons-vue-next')['FileIcon']
17
- const FolderOpenIcon: typeof import('tdesign-icons-vue-next')['FolderOpenIcon']
18
- const HomeIcon: typeof import('tdesign-icons-vue-next')['HomeIcon']
17
+ const FileIcon: (typeof import('tdesign-icons-vue-next'))['FileIcon']
18
+ const FolderOpenIcon: (typeof import('tdesign-icons-vue-next'))['FolderOpenIcon']
19
+ const HomeIcon: (typeof import('tdesign-icons-vue-next'))['HomeIcon']
19
20
  const Loading: typeof import('@opentiny/vue')['Loading']
20
- const LoadingPlugin: typeof import('tdesign-vue-next')['LoadingPlugin']
21
+ const LoadingPlugin: (typeof import('tdesign-vue-next'))['LoadingPlugin']
21
22
  const Message: typeof import('@opentiny/vue')['Message']
22
- const MessagePlugin: typeof import('tdesign-vue-next')['MessagePlugin']
23
+ const MessagePlugin: (typeof import('tdesign-vue-next'))['MessagePlugin']
23
24
  const Modal: typeof import('@opentiny/vue')['Modal']
24
25
  const Notify: typeof import('@opentiny/vue')['Notify']
25
- const NotifyPlugin: typeof import('tdesign-vue-next')['NotifyPlugin']
26
- const RootListIcon: typeof import('tdesign-icons-vue-next')['RootListIcon']
27
- const SettingIcon: typeof import('tdesign-icons-vue-next')['SettingIcon']
26
+ const NotifyPlugin: (typeof import('tdesign-vue-next'))['NotifyPlugin']
27
+ const RootListIcon: (typeof import('tdesign-icons-vue-next'))['RootListIcon']
28
+ const SettingIcon: (typeof import('tdesign-icons-vue-next'))['SettingIcon']
28
29
  const TinyMessage: typeof import('@opentiny/vue-message')['default']
29
- const UserIcon: typeof import('tdesign-icons-vue-next')['UserIcon']
30
- const ViewListIcon: typeof import('tdesign-icons-vue-next')['ViewListIcon']
30
+ const UserIcon: (typeof import('tdesign-icons-vue-next'))['UserIcon']
31
+ const ViewListIcon: (typeof import('tdesign-icons-vue-next'))['ViewListIcon']
31
32
  const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
32
33
  const computed: typeof import('vue')['computed']
33
34
  const createApp: typeof import('vue')['createApp']
@@ -41,7 +42,7 @@ declare global {
41
42
  const getCurrentInstance: typeof import('vue')['getCurrentInstance']
42
43
  const getCurrentScope: typeof import('vue')['getCurrentScope']
43
44
  const getCurrentWatcher: typeof import('vue')['getCurrentWatcher']
44
- const getIcon: typeof import('tdesign-icons-vue-next')['getIcon']
45
+ const getIcon: (typeof import('tdesign-icons-vue-next'))['getIcon']
45
46
  const h: typeof import('vue')['h']
46
47
  const iconAcceptance: typeof import('@opentiny/vue-icon').iconAcceptance
47
48
  const iconActivation: typeof import('@opentiny/vue-icon').iconActivation
@@ -618,7 +619,7 @@ declare global {
618
619
  const shallowReactive: typeof import('vue')['shallowReactive']
619
620
  const shallowReadonly: typeof import('vue')['shallowReadonly']
620
621
  const shallowRef: typeof import('vue')['shallowRef']
621
- const storage: typeof import('../plugins/storage')['default']
622
+ const storage: (typeof import('../plugins/storage'))['default']
622
623
  const storeToRefs: typeof import('pinia')['storeToRefs']
623
624
  const toRaw: typeof import('vue')['toRaw']
624
625
  const toRef: typeof import('vue')['toRef']
@@ -629,7 +630,7 @@ declare global {
629
630
  const useAttrs: typeof import('vue')['useAttrs']
630
631
  const useCssModule: typeof import('vue')['useCssModule']
631
632
  const useCssVars: typeof import('vue')['useCssVars']
632
- const useGlobal: typeof import('../plugins/internal/store')['useGlobal']
633
+ const useGlobal: typeof import('../plugins/internal/global')['useGlobal']
633
634
  const useGlobalStore: typeof import('../plugins/store').useGlobalStore
634
635
  const useId: typeof import('vue')['useId']
635
636
  const useLink: typeof import('vue-router')['useLink']
@@ -650,3 +651,96 @@ declare global {
650
651
  export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
651
652
  import('vue')
652
653
  }
654
+
655
+ // for vue template auto import
656
+ import { UnwrapRef } from 'vue'
657
+ declare module 'vue' {
658
+ interface GlobalComponents {}
659
+ interface ComponentCustomProperties {
660
+ readonly $ConfigInternal: UnwrapRef<typeof import('../config/internal/index')['$ConfigInternal']>
661
+ readonly $Http: UnwrapRef<typeof import('../plugins/internal/http')['$Http']>
662
+ readonly $Storage: UnwrapRef<typeof import('../plugins/internal/storage')['$Storage']>
663
+ readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
664
+ readonly Loading: UnwrapRef<typeof import('@opentiny/vue')['Loading']>
665
+ readonly Message: UnwrapRef<typeof import('@opentiny/vue')['Message']>
666
+ readonly Modal: UnwrapRef<typeof import('@opentiny/vue')['Modal']>
667
+ readonly Notify: UnwrapRef<typeof import('@opentiny/vue')['Notify']>
668
+ readonly TinyMessage: UnwrapRef<typeof import('@opentiny/vue-message')['default']>
669
+ readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
670
+ readonly computed: UnwrapRef<typeof import('vue')['computed']>
671
+ readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
672
+ readonly createPinia: UnwrapRef<typeof import('pinia')['createPinia']>
673
+ readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
674
+ readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
675
+ readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
676
+ readonly defineStore: UnwrapRef<typeof import('pinia')['defineStore']>
677
+ readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
678
+ readonly getActivePinia: UnwrapRef<typeof import('pinia')['getActivePinia']>
679
+ readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
680
+ readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
681
+ readonly getCurrentWatcher: UnwrapRef<typeof import('vue')['getCurrentWatcher']>
682
+ readonly h: UnwrapRef<typeof import('vue')['h']>
683
+ readonly inject: UnwrapRef<typeof import('vue')['inject']>
684
+ readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
685
+ readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
686
+ readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
687
+ readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
688
+ readonly isShallow: UnwrapRef<typeof import('vue')['isShallow']>
689
+ readonly mapActions: UnwrapRef<typeof import('pinia')['mapActions']>
690
+ readonly mapGetters: UnwrapRef<typeof import('pinia')['mapGetters']>
691
+ readonly mapState: UnwrapRef<typeof import('pinia')['mapState']>
692
+ readonly mapStores: UnwrapRef<typeof import('pinia')['mapStores']>
693
+ readonly mapWritableState: UnwrapRef<typeof import('pinia')['mapWritableState']>
694
+ readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
695
+ readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
696
+ readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
697
+ readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
698
+ readonly onBeforeRouteLeave: UnwrapRef<typeof import('vue-router')['onBeforeRouteLeave']>
699
+ readonly onBeforeRouteUpdate: UnwrapRef<typeof import('vue-router')['onBeforeRouteUpdate']>
700
+ readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
701
+ readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
702
+ readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
703
+ readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
704
+ readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
705
+ readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
706
+ readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
707
+ readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
708
+ readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
709
+ readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
710
+ readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
711
+ readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
712
+ readonly provide: UnwrapRef<typeof import('vue')['provide']>
713
+ readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
714
+ readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
715
+ readonly ref: UnwrapRef<typeof import('vue')['ref']>
716
+ readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
717
+ readonly router: UnwrapRef<typeof import('../plugins/internal/router')['router']>
718
+ readonly setActivePinia: UnwrapRef<typeof import('pinia')['setActivePinia']>
719
+ readonly setMapStoreSuffix: UnwrapRef<typeof import('pinia')['setMapStoreSuffix']>
720
+ readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
721
+ readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
722
+ readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
723
+ readonly storeToRefs: UnwrapRef<typeof import('pinia')['storeToRefs']>
724
+ readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
725
+ readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
726
+ readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
727
+ readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
728
+ readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
729
+ readonly unref: UnwrapRef<typeof import('vue')['unref']>
730
+ readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
731
+ readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
732
+ readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
733
+ readonly useGlobal: UnwrapRef<typeof import('../plugins/internal/global')['useGlobal']>
734
+ readonly useId: UnwrapRef<typeof import('vue')['useId']>
735
+ readonly useLink: UnwrapRef<typeof import('vue-router')['useLink']>
736
+ readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
737
+ readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']>
738
+ readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']>
739
+ readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
740
+ readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
741
+ readonly watch: UnwrapRef<typeof import('vue')['watch']>
742
+ readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
743
+ readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
744
+ readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
745
+ }
746
+ }
@@ -12,6 +12,33 @@ export {}
12
12
  declare module 'vue' {
13
13
  export interface GlobalComponents {
14
14
  Icon: typeof import('./../components/internal/Icon.vue')['default']
15
+ 'ILucide:activity': typeof import('~icons/lucide/activity')['default']
16
+ 'ILucide:alertCircle': typeof import('~icons/lucide/alert-circle')['default']
17
+ 'ILucide:alertTriangle': typeof import('~icons/lucide/alert-triangle')['default']
18
+ 'ILucide:box': typeof import('~icons/lucide/box')['default']
19
+ 'ILucide:checkCircle': typeof import('~icons/lucide/check-circle')['default']
20
+ 'ILucide:circle': typeof import('~icons/lucide/circle')['default']
21
+ 'ILucide:clock': typeof import('~icons/lucide/clock')['default']
22
+ 'ILucide:cloud': typeof import('~icons/lucide/cloud')['default']
23
+ 'ILucide:cpu': typeof import('~icons/lucide/cpu')['default']
24
+ 'ILucide:database': typeof import('~icons/lucide/database')['default']
25
+ 'ILucide:disc': typeof import('~icons/lucide/disc')['default']
26
+ 'ILucide:hardDrive': typeof import('~icons/lucide/hard-drive')['default']
27
+ 'ILucide:info': typeof import('~icons/lucide/info')['default']
28
+ 'ILucide:mail': typeof import('~icons/lucide/mail')['default']
29
+ 'ILucide:menu': typeof import('~icons/lucide/menu')['default']
30
+ 'ILucide:package': typeof import('~icons/lucide/package')['default']
31
+ 'ILucide:phone': typeof import('~icons/lucide/phone')['default']
32
+ 'ILucide:rotateCw': typeof import('~icons/lucide/rotate-cw')['default']
33
+ 'ILucide:server': typeof import('~icons/lucide/server')['default']
34
+ 'ILucide:settings': typeof import('~icons/lucide/settings')['default']
35
+ 'ILucide:square': typeof import('~icons/lucide/square')['default']
36
+ 'ILucide:trendingUp': typeof import('~icons/lucide/trending-up')['default']
37
+ 'ILucide:user': typeof import('~icons/lucide/user')['default']
38
+ 'ILucide:users': typeof import('~icons/lucide/users')['default']
39
+ 'ILucide:webhook': typeof import('~icons/lucide/webhook')['default']
40
+ 'ILucide:xCircle': typeof import('~icons/lucide/x-circle')['default']
41
+ 'ILucide:zap': typeof import('~icons/lucide/zap')['default']
15
42
  RouterLink: typeof import('vue-router')['RouterLink']
16
43
  RouterView: typeof import('vue-router')['RouterView']
17
44
  TinyButton: typeof import('@opentiny/vue-button')['default']
@@ -1,10 +1,10 @@
1
- <template>
1
+ <template>
2
2
  <div class="page-admin page-table">
3
3
  <div class="main-tool">
4
4
  <div class="left">
5
5
  <tiny-button type="primary" @click="$Method.onAction('add', {})">
6
6
  <template #icon>
7
- <Icon name="Plus" :size="16" />
7
+ <i-lucide:plus style="width: 16px; height: 16px" />
8
8
  </template>
9
9
  添加管理员
10
10
  </tiny-button>
@@ -12,7 +12,14 @@
12
12
  <div class="right">
13
13
  <tiny-button @click="$Method.handleRefresh">
14
14
  <template #icon>
15
- <Icon name="RotateCw" :size="16" />
15
+ <i-lucide:rotate-cw style="width: 16px; height: 16px" />
16
+ </template>
17
+ </tiny-button>
18
+ </div>
19
+ <div class="right">
20
+ <tiny-button @click="$Method.handleRefresh">
21
+ <template #icon>
22
+ <i-lucide:rotate-cw style="width: 16px; height: 16px" />
16
23
  </template>
17
24
  刷新
18
25
  </tiny-button>
@@ -39,15 +46,15 @@
39
46
  <template #dropdown>
40
47
  <tiny-dropdown-menu>
41
48
  <tiny-dropdown-item :item-data="{ command: 'role' }">
42
- <Icon name="User" />
49
+ <i-lucide:user style="width: 14px; height: 14px; margin-right: 6px" />
43
50
  分配角色
44
51
  </tiny-dropdown-item>
45
52
  <tiny-dropdown-item :item-data="{ command: 'upd' }">
46
- <Icon name="Edit" />
53
+ <i-lucide:pencil style="width: 14px; height: 14px; margin-right: 6px" />
47
54
  编辑
48
55
  </tiny-dropdown-item>
49
56
  <tiny-dropdown-item :item-data="{ command: 'del' }" divided>
50
- <Icon name="Trash2" />
57
+ <i-lucide:trash-2 style="width: 14px; height: 14px; margin-right: 6px" />
51
58
  删除
52
59
  </tiny-dropdown-item>
53
60
  </tiny-dropdown-menu>
@@ -4,7 +4,7 @@
4
4
  <div class="left">
5
5
  <tiny-button type="primary" @click="$Method.onAction('add', {})">
6
6
  <template #icon>
7
- <Icon name="Plus" :size="16" />
7
+ <i-lucide:plus style="width: 16px; height: 16px" />
8
8
  </template>
9
9
  添加字典
10
10
  </tiny-button>
@@ -12,7 +12,7 @@
12
12
  <div class="right">
13
13
  <tiny-button @click="$Method.handleRefresh">
14
14
  <template #icon>
15
- <Icon name="RotateCw" :size="16" />
15
+ <i-lucide:rotate-cw style="width: 16px; height: 16px" />
16
16
  </template>
17
17
  刷新
18
18
  </tiny-button>
@@ -40,11 +40,11 @@
40
40
  <template #dropdown>
41
41
  <tiny-dropdown-menu>
42
42
  <tiny-dropdown-item :item-data="{ command: 'upd' }">
43
- <Icon name="Edit" />
43
+ <i-lucide:pencil style="width: 14px; height: 14px; margin-right: 6px" />
44
44
  编辑
45
45
  </tiny-dropdown-item>
46
46
  <tiny-dropdown-item :item-data="{ command: 'del' }" divided>
47
- <Icon name="Trash2" />
47
+ <i-lucide:trash-2 style="width: 14px; height: 14px; margin-right: 6px" />
48
48
  删除
49
49
  </tiny-dropdown-item>
50
50
  </tiny-dropdown-menu>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="section-block">
3
3
  <div class="section-header">
4
- <Icon name="Package" :size="20" />
4
+ <i-lucide:package style="width: 20px; height: 20px" />
5
5
  <h2>已安装插件</h2>
6
6
  </div>
7
7
  <div class="section-content">
@@ -9,7 +9,7 @@
9
9
  <div v-for="addon in addonList" :key="addon.name" class="addon-item">
10
10
  <div class="addon-status-badge" :class="{ active: addon.enabled }"></div>
11
11
  <div class="addon-icon">
12
- <Icon name="Box" :size="20" />
12
+ <i-lucide:box style="width: 20px; height: 20px" />
13
13
  </div>
14
14
  <div class="addon-info">
15
15
  <div class="addon-title">
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="section-block">
3
3
  <div class="section-header">
4
- <Icon name="Server" :size="20" />
4
+ <i-lucide:server style="width: 20px; height: 20px" />
5
5
  <h2>运行环境</h2>
6
6
  </div>
7
7
  <div class="section-content">
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="section-block">
3
3
  <div class="section-header">
4
- <Icon name="List" :size="20" />
4
+ <i-lucide:list style="width: 20px; height: 20px" />
5
5
  <h2>操作日志</h2>
6
6
  </div>
7
7
  <div class="section-content">
@@ -1,14 +1,14 @@
1
1
  <template>
2
2
  <div class="section-block">
3
3
  <div class="section-header">
4
- <Icon name="Zap" :size="20" />
4
+ <i-lucide:zap style="width: 20px; height: 20px" />
5
5
  <h2>性能指标</h2>
6
6
  </div>
7
7
  <div class="section-content">
8
8
  <div class="performance-grid">
9
9
  <div class="perf-metric">
10
10
  <div class="perf-icon">
11
- <Icon name="Clock" :size="18" />
11
+ <i-lucide:clock style="width: 18px; height: 18px" />
12
12
  </div>
13
13
  <div class="perf-info">
14
14
  <div class="perf-label">平均响应</div>
@@ -17,7 +17,7 @@
17
17
  </div>
18
18
  <div class="perf-metric">
19
19
  <div class="perf-icon">
20
- <Icon name="TrendingUp" :size="18" />
20
+ <i-lucide:trending-up style="width: 18px; height: 18px" />
21
21
  </div>
22
22
  <div class="perf-info">
23
23
  <div class="perf-label">QPS</div>
@@ -26,7 +26,7 @@
26
26
  </div>
27
27
  <div class="perf-metric">
28
28
  <div class="perf-icon">
29
- <Icon name="AlertCircle" :size="18" />
29
+ <i-lucide:alert-circle style="width: 18px; height: 18px" />
30
30
  </div>
31
31
  <div class="perf-info">
32
32
  <div class="perf-label">错误率</div>
@@ -35,7 +35,7 @@
35
35
  </div>
36
36
  <div class="perf-metric">
37
37
  <div class="perf-icon">
38
- <Icon name="Activity" :size="18" />
38
+ <i-lucide:activity style="width: 18px; height: 18px" />
39
39
  </div>
40
40
  <div class="perf-info">
41
41
  <div class="perf-label">活跃连接</div>
@@ -45,7 +45,7 @@
45
45
  </div>
46
46
  <!-- 最慢接口提示 -->
47
47
  <div v-if="performanceMetrics.slowestApi" class="perf-slowest">
48
- <Icon name="AlertTriangle" :size="14" />
48
+ <i-lucide:alert-triangle style="width: 14px; height: 14px" />
49
49
  <span>最慢接口: {{ performanceMetrics.slowestApi.path }} ({{ performanceMetrics.slowestApi.time }}ms)</span>
50
50
  </div>
51
51
  </div>
@@ -3,7 +3,7 @@
3
3
  <div class="section-content">
4
4
  <tiny-button type="primary" size="large" @click="handleClearCache">
5
5
  <template #prefix>
6
- <Icon name="RotateCw" :size="18" />
6
+ <i-lucide:rotate-cw style="width: 18px; height: 18px" />
7
7
  </template>
8
8
  刷新缓存
9
9
  </tiny-button>
@@ -1,14 +1,19 @@
1
1
  <template>
2
2
  <div class="section-block">
3
3
  <div class="section-header">
4
- <Icon name="Settings" :size="20" />
4
+ <i-lucide:settings style="width: 20px; height: 20px" />
5
5
  <h2>服务状态</h2>
6
6
  </div>
7
7
  <div class="section-content">
8
8
  <div class="config-grid">
9
9
  <div v-for="service in services" :key="service.name" class="config-card" :class="`config-${service.status}`">
10
10
  <div class="config-icon">
11
- <Icon :name="getServiceIcon(service.name)" :size="20" />
11
+ <i-lucide:database v-if="service.name === '数据库'" style="width: 20px; height: 20px" />
12
+ <i-lucide:zap v-else-if="service.name === 'Redis'" style="width: 20px; height: 20px" />
13
+ <i-lucide:hard-drive v-else-if="service.name === '文件系统'" style="width: 20px; height: 20px" />
14
+ <i-lucide:mail v-else-if="service.name === '邮件服务'" style="width: 20px; height: 20px" />
15
+ <i-lucide:cloud v-else-if="service.name === 'OSS存储'" style="width: 20px; height: 20px" />
16
+ <i-lucide:circle v-else style="width: 20px; height: 20px" />
12
17
  </div>
13
18
  <div class="config-info">
14
19
  <div class="config-name">{{ service.name }}</div>
@@ -18,7 +23,10 @@
18
23
  </div>
19
24
  </div>
20
25
  <div class="config-badge">
21
- <Icon :name="getStatusIcon(service.status)" :size="32" />
26
+ <i-lucide:check-circle v-if="service.status === 'running'" style="width: 32px; height: 32px" />
27
+ <i-lucide:x-circle v-else-if="service.status === 'stopped'" style="width: 32px; height: 32px" />
28
+ <i-lucide:alert-circle v-else-if="service.status === 'unconfigured'" style="width: 32px; height: 32px" />
29
+ <i-lucide:circle v-else style="width: 32px; height: 32px" />
22
30
  </div>
23
31
  </div>
24
32
  </div>
@@ -60,26 +68,6 @@ const getStatusText = (status) => {
60
68
  };
61
69
  return texts[status] || status;
62
70
  };
63
-
64
- const getServiceIcon = (name) => {
65
- const icons = {
66
- 数据库: 'Database',
67
- Redis: 'Zap',
68
- 文件系统: 'HardDrive',
69
- 邮件服务: 'Mail',
70
- OSS存储: 'Cloud'
71
- };
72
- return icons[name] || 'Circle';
73
- };
74
-
75
- const getStatusIcon = (status) => {
76
- const icons = {
77
- running: 'CheckCircle',
78
- stopped: 'XCircle',
79
- unconfigured: 'AlertCircle'
80
- };
81
- return icons[status] || 'Circle';
82
- };
83
71
  </script>
84
72
 
85
73
  <style scoped lang="scss">
@@ -1,14 +1,18 @@
1
1
  <template>
2
2
  <div class="section-block">
3
3
  <div class="section-header">
4
- <Icon name="Bell" :size="20" />
4
+ <i-lucide:bell style="width: 20px; height: 20px" />
5
5
  <h2>系统通知</h2>
6
6
  </div>
7
7
  <div class="section-content">
8
8
  <div class="notification-compact-list">
9
9
  <div v-for="notification in notifications" :key="notification.id" class="notification-compact-item">
10
10
  <div class="notification-icon" :class="`type-${notification.type}`">
11
- <Icon :name="getNotificationIcon(notification.type)" :size="16" />
11
+ <i-lucide:info v-if="notification.type === 'info'" style="width: 16px; height: 16px" />
12
+ <i-lucide:check-circle v-else-if="notification.type === 'success'" style="width: 16px; height: 16px" />
13
+ <i-lucide:alert-triangle v-else-if="notification.type === 'warning'" style="width: 16px; height: 16px" />
14
+ <i-lucide:x-circle v-else-if="notification.type === 'error'" style="width: 16px; height: 16px" />
15
+ <i-lucide:bell v-else style="width: 16px; height: 16px" />
12
16
  </div>
13
17
  <div class="notification-content">
14
18
  <span class="notification-title">{{ notification.title }}</span>
@@ -30,16 +34,6 @@ const notifications = $ref([
30
34
  { id: 4, type: 'success', title: '性能优化完成 - 响应速度提升30%', isRead: true, createdAt: Date.now() - 172800000 }
31
35
  ]);
32
36
 
33
- const getNotificationIcon = (type) => {
34
- const iconMap = {
35
- info: 'Info',
36
- success: 'CheckCircle',
37
- warning: 'AlertTriangle',
38
- error: 'XCircle'
39
- };
40
- return iconMap[type] || 'Bell';
41
- };
42
-
43
37
  const formatTime = (timestamp) => {
44
38
  const date = new Date(timestamp);
45
39
  const now = Date.now();
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="section-block">
3
3
  <div class="section-header">
4
- <Icon name="Info" :size="20" />
4
+ <i-lucide:info style="width: 20px; height: 20px" />
5
5
  <h2>系统概览</h2>
6
6
  </div>
7
7
  <div class="section-content">
@@ -10,21 +10,21 @@
10
10
  <div class="info-block">
11
11
  <div class="stats-grid">
12
12
  <div class="stat-box stat-primary">
13
- <Icon name="Menu" :size="24" />
13
+ <i-lucide:menu style="width: 24px; height: 24px" />
14
14
  <div class="stat-content">
15
15
  <div class="stat-value">{{ permissionStats.menuCount }}</div>
16
16
  <div class="stat-label">菜单总数</div>
17
17
  </div>
18
18
  </div>
19
19
  <div class="stat-box stat-success">
20
- <Icon name="Webhook" :size="24" />
20
+ <i-lucide:webhook style="width: 24px; height: 24px" />
21
21
  <div class="stat-content">
22
22
  <div class="stat-value">{{ permissionStats.apiCount }}</div>
23
23
  <div class="stat-label">接口总数</div>
24
24
  </div>
25
25
  </div>
26
26
  <div class="stat-box stat-warning">
27
- <Icon name="Users" :size="24" />
27
+ <i-lucide:users style="width: 24px; height: 24px" />
28
28
  <div class="stat-content">
29
29
  <div class="stat-value">{{ permissionStats.roleCount }}</div>
30
30
  <div class="stat-label">角色总数</div>
@@ -1,14 +1,14 @@
1
1
  <template>
2
2
  <div class="section-block">
3
3
  <div class="section-header">
4
- <Icon name="Activity" :size="20" />
4
+ <i-lucide:activity style="width: 20px; height: 20px" />
5
5
  <h2>系统资源</h2>
6
6
  </div>
7
7
  <div class="section-content">
8
8
  <div class="resource-compact-list">
9
9
  <div class="resource-compact-item">
10
10
  <div class="resource-compact-header">
11
- <Icon name="Cpu" :size="16" />
11
+ <i-lucide:cpu style="width: 16px; height: 16px" />
12
12
  <span class="resource-label">CPU</span>
13
13
  <span class="resource-value">{{ systemResources.cpu.usage }}%</span>
14
14
  <span class="resource-desc">{{ systemResources.cpu.cores }}核心</span>
@@ -17,7 +17,7 @@
17
17
  </div>
18
18
  <div class="resource-compact-item">
19
19
  <div class="resource-compact-header">
20
- <Icon name="HardDrive" :size="16" />
20
+ <i-lucide:hard-drive style="width: 16px; height: 16px" />
21
21
  <span class="resource-label">内存</span>
22
22
  <span class="resource-value">{{ systemResources.memory.percentage }}%</span>
23
23
  <span class="resource-desc">{{ systemResources.memory.used }}GB / {{ systemResources.memory.total }}GB</span>
@@ -26,7 +26,7 @@
26
26
  </div>
27
27
  <div class="resource-compact-item">
28
28
  <div class="resource-compact-header">
29
- <Icon name="Disc" :size="16" />
29
+ <i-lucide:disc style="width: 16px; height: 16px" />
30
30
  <span class="resource-label">磁盘</span>
31
31
  <span class="resource-value">{{ systemResources.disk.percentage }}%</span>
32
32
  <span class="resource-desc">{{ systemResources.disk.used }}GB / {{ systemResources.disk.total }}GB</span>
@@ -2,7 +2,7 @@
2
2
  <div class="section-block user-info-card">
3
3
  <div class="user-header">
4
4
  <div class="user-avatar">
5
- <Icon name="User" :size="32" />
5
+ <i-lucide:user style="width: 32px; height: 32px" />
6
6
  </div>
7
7
  <div class="user-basic">
8
8
  <div class="user-name">{{ $Data.userInfo.nickname || $Data.userInfo.name || $Data.userInfo.username || '未设置' }}</div>
@@ -11,15 +11,15 @@
11
11
  </div>
12
12
  <div class="user-details">
13
13
  <div class="detail-item">
14
- <Icon name="Mail" :size="14" />
14
+ <i-lucide:mail style="width: 14px; height: 14px" />
15
15
  <span>{{ $Data.userInfo.email || '未设置' }}</span>
16
16
  </div>
17
17
  <div v-if="$Data.userInfo.phone" class="detail-item">
18
- <Icon name="Phone" :size="14" />
18
+ <i-lucide:phone style="width: 14px; height: 14px" />
19
19
  <span>{{ $Data.userInfo.phone }}</span>
20
20
  </div>
21
21
  <div v-if="$Data.userInfo.lastLoginTime" class="detail-item">
22
- <Icon name="Clock" :size="14" />
22
+ <i-lucide:clock style="width: 14px; height: 14px" />
23
23
  <span>{{ $Method.formatTime($Data.userInfo.lastLoginTime) }}</span>
24
24
  </div>
25
25
  </div>
@@ -28,7 +28,7 @@
28
28
  <div v-if="$Data.userInfo.roleCode === 'dev'" class="user-actions">
29
29
  <tiny-button type="primary" size="mini" :loading="$Data.refreshing" @click="$Method.handleRefreshCache">
30
30
  <template #icon>
31
- <Icon name="RotateCw" :size="14" />
31
+ <i-lucide:rotate-cw style="width: 14px; height: 14px" />
32
32
  </template>
33
33
  刷新缓存
34
34
  </tiny-button>
@@ -3,7 +3,7 @@
3
3
  <tiny-form-item prop="account" label="账号">
4
4
  <tiny-input v-model="$Data.formData.account" placeholder="请输入用户名或邮箱" size="large" clearable>
5
5
  <template #prefix-icon>
6
- <Icon name="User" :size="18" />
6
+ <i-lucide:user style="width: 18px; height: 18px" />
7
7
  </template>
8
8
  </tiny-input>
9
9
  </tiny-form-item>
@@ -11,7 +11,7 @@
11
11
  <tiny-form-item prop="password" label="密码">
12
12
  <tiny-input v-model="$Data.formData.password" type="password" placeholder="请输入密码" size="large" clearable>
13
13
  <template #prefix-icon>
14
- <Icon name="Lock" :size="18" />
14
+ <i-lucide:lock style="width: 18px; height: 18px" />
15
15
  </template>
16
16
  </tiny-input>
17
17
  </tiny-form-item>
@@ -3,7 +3,7 @@
3
3
  <tiny-form-item prop="username" label="用户名">
4
4
  <tiny-input v-model="$Data.formData.username" placeholder="请输入用户名" size="large" clearable>
5
5
  <template #prefix-icon>
6
- <Icon name="User" :size="18" />
6
+ <i-lucide:user style="width: 18px; height: 18px" />
7
7
  </template>
8
8
  </tiny-input>
9
9
  </tiny-form-item>
@@ -11,7 +11,7 @@
11
11
  <tiny-form-item prop="email" label="邮箱">
12
12
  <tiny-input v-model="$Data.formData.email" placeholder="请输入邮箱" size="large" clearable>
13
13
  <template #prefix-icon>
14
- <Icon name="Mail" :size="18" />
14
+ <i-lucide:mail style="width: 18px; height: 18px" />
15
15
  </template>
16
16
  </tiny-input>
17
17
  </tiny-form-item>
@@ -19,7 +19,7 @@
19
19
  <tiny-form-item prop="password" label="密码">
20
20
  <tiny-input v-model="$Data.formData.password" type="password" placeholder="请输入密码" size="large" clearable>
21
21
  <template #prefix-icon>
22
- <Icon name="Lock" :size="18" />
22
+ <i-lucide:lock style="width: 18px; height: 18px" />
23
23
  </template>
24
24
  </tiny-input>
25
25
  </tiny-form-item>
@@ -27,7 +27,7 @@
27
27
  <tiny-form-item prop="nickname" label="昵称">
28
28
  <tiny-input v-model="$Data.formData.nickname" placeholder="请输入昵称(选填)" size="large" clearable>
29
29
  <template #prefix-icon>
30
- <Icon name="Smile" :size="18" />
30
+ <i-lucide:smile style="width: 18px; height: 18px" />
31
31
  </template>
32
32
  </tiny-input>
33
33
  </tiny-form-item>
@@ -4,7 +4,7 @@
4
4
  <div class="left">
5
5
  <tiny-button type="primary" @click="$Method.onAction('add', {})">
6
6
  <template #icon>
7
- <Icon name="Plus" :size="16" />
7
+ <i-lucide:plus style="width: 16px; height: 16px" />
8
8
  </template>
9
9
  添加菜单
10
10
  </tiny-button>
@@ -12,7 +12,7 @@
12
12
  <div class="right">
13
13
  <tiny-button @click="$Method.handleRefresh">
14
14
  <template #icon>
15
- <Icon name="RotateCw" :size="16" />
15
+ <i-lucide:rotate-cw style="width: 16px; height: 16px" />
16
16
  </template>
17
17
  刷新
18
18
  </tiny-button>
@@ -25,7 +25,7 @@
25
25
  <tiny-grid-column field="path" title="路径" :width="200" />
26
26
  <tiny-grid-column field="icon" title="图标" :width="100">
27
27
  <template #default="{ row }">
28
- <Icon v-if="row.icon" :name="row.icon" :size="16" />
28
+ <i-lucide:square v-if="row.icon" style="width: 16px; height: 16px" />
29
29
  <span v-else>-</span>
30
30
  </template>
31
31
  </tiny-grid-column>
@@ -49,11 +49,11 @@
49
49
  <template #dropdown>
50
50
  <tiny-dropdown-menu>
51
51
  <tiny-dropdown-item :item-data="{ command: 'upd' }">
52
- <Icon name="Edit" />
52
+ <i-lucide:pencil style="width: 14px; height: 14px; margin-right: 6px" />
53
53
  编辑
54
54
  </tiny-dropdown-item>
55
55
  <tiny-dropdown-item :item-data="{ command: 'del' }" divided>
56
- <Icon name="Trash2" />
56
+ <i-lucide:trash-2 style="width: 14px; height: 14px; margin-right: 6px" />
57
57
  删除
58
58
  </tiny-dropdown-item>
59
59
  </tiny-dropdown-menu>
@@ -4,7 +4,7 @@
4
4
  <div class="left">
5
5
  <tiny-button type="primary" @click="$Method.onAction('add', {})">
6
6
  <template #icon>
7
- <Icon name="Plus" :size="16" />
7
+ <i-lucide:plus style="width: 16px; height: 16px" />
8
8
  </template>
9
9
  添加角色
10
10
  </tiny-button>
@@ -12,7 +12,7 @@
12
12
  <div class="right">
13
13
  <tiny-button @click="$Method.handleRefresh">
14
14
  <template #icon>
15
- <Icon name="RotateCw" :size="16" />
15
+ <i-lucide:rotate-cw style="width: 16px; height: 16px" />
16
16
  </template>
17
17
  刷新
18
18
  </tiny-button>
@@ -38,19 +38,19 @@
38
38
  <template #dropdown>
39
39
  <tiny-dropdown-menu>
40
40
  <tiny-dropdown-item :item-data="{ command: 'upd' }">
41
- <Icon name="Edit" />
41
+ <i-lucide:pencil style="width: 14px; height: 14px; margin-right: 6px" />
42
42
  编辑
43
43
  </tiny-dropdown-item>
44
44
  <tiny-dropdown-item :item-data="{ command: 'menu' }">
45
- <Icon name="Settings" />
45
+ <i-lucide:settings style="width: 14px; height: 14px; margin-right: 6px" />
46
46
  菜单权限
47
47
  </tiny-dropdown-item>
48
48
  <tiny-dropdown-item :item-data="{ command: 'api' }">
49
- <Icon name="Code" />
49
+ <i-lucide:code style="width: 14px; height: 14px; margin-right: 6px" />
50
50
  接口权限
51
51
  </tiny-dropdown-item>
52
52
  <tiny-dropdown-item :item-data="{ command: 'del' }" divided>
53
- <Icon name="Trash2" />
53
+ <i-lucide:trash-2 style="width: 14px; height: 14px; margin-right: 6px" />
54
54
  删除
55
55
  </tiny-dropdown-item>
56
56
  </tiny-dropdown-menu>
@@ -5,7 +5,7 @@
5
5
  <div class="toolbar-left">
6
6
  <t-button theme="primary" @click="$Method.handleAdd">
7
7
  <template #icon>
8
- <add-icon />
8
+ <i-lucide:plus style="width: 16px; height: 16px" />
9
9
  </template>
10
10
  添加管理员
11
11
  </t-button>
@@ -16,13 +16,13 @@
16
16
  <t-select v-model="$Data.searchState" placeholder="状态" clearable style="width: 120px" :options="$Data.stateOptions" @change="$Method.handleSearch" />
17
17
  <t-button theme="default" @click="$Method.handleSearch">
18
18
  <template #icon>
19
- <search-icon />
19
+ <i-lucide:search style="width: 16px; height: 16px" />
20
20
  </template>
21
21
  搜索
22
22
  </t-button>
23
23
  <t-button theme="default" @click="$Method.handleReset">
24
24
  <template #icon>
25
- <refresh-icon />
25
+ <i-lucide:rotate-cw style="width: 16px; height: 16px" />
26
26
  </template>
27
27
  重置
28
28
  </t-button>
package/vite.config.ts CHANGED
@@ -1,21 +1,27 @@
1
- import { fileURLToPath, URL } from 'node:url';
2
1
  import { defineConfig } from 'vite';
3
2
  import vue from '@vitejs/plugin-vue';
4
3
  import ReactivityTransform from '@vue-macros/reactivity-transform/vite';
5
4
  import AutoImport from 'unplugin-auto-import/vite';
6
5
  import Components from 'unplugin-vue-components/vite';
6
+ import Icons from 'unplugin-icons/vite';
7
+ import IconsResolver from 'unplugin-icons/resolver';
7
8
  import { TinyVueSingleResolver } from '@opentiny/unplugin-tiny-vue';
8
9
  import autoRoutes from 'befly-auto-routes';
10
+ import { fileURLToPath } from 'node:url';
9
11
 
10
- // https://vite.dev/config/
11
12
  export default defineConfig({
13
+ root: process.cwd(),
14
+ base: './',
12
15
  plugins: [
13
16
  vue(),
14
- // Vue 响应式语法糖
15
17
  ReactivityTransform(),
16
- // 自动路由插件
17
18
  autoRoutes({ debug: true }),
18
- // 自动导入 Vue3 API 和组合式函数
19
+ Icons({
20
+ compiler: 'vue3',
21
+ autoInstall: true,
22
+ defaultClass: 'icon-befly',
23
+ defaultStyle: 'margin-right: 8px; vertical-align: middle;'
24
+ }),
19
25
  AutoImport({
20
26
  imports: [
21
27
  'vue',
@@ -25,18 +31,22 @@ export default defineConfig({
25
31
  '@opentiny/vue': ['Modal', 'Notify', 'Loading', 'Message']
26
32
  }
27
33
  ],
28
- resolvers: [TinyVueSingleResolver],
29
- // 自动导入 plugins 目录下的所有导出(internal 优先)
30
- dirs: ['./src/plugins/internal', './src/plugins'],
34
+ resolvers: [TinyVueSingleResolver, IconsResolver({})],
35
+ vueTemplate: true,
36
+ dirsScanOptions: {
37
+ filePatterns: ['*.ts'],
38
+ fileFilter: (file) => file.endsWith('.ts'),
39
+ types: true
40
+ },
41
+ dirs: ['./src/plugins/**', './src/config/**'],
31
42
  dts: 'src/types/auto-imports.d.ts',
32
- eslintrc: {
33
- enabled: false
34
- }
43
+ eslintrc: { enabled: false }
35
44
  }),
36
- // 自动导入 OpenTiny 组件
37
45
  Components({
38
- resolvers: [TinyVueSingleResolver],
39
- dirs: ['src/components/internal', 'src/components'],
46
+ resolvers: [TinyVueSingleResolver, IconsResolver({})],
47
+ dirs: ['src/components'],
48
+ deep: true,
49
+ version: 3,
40
50
  dts: 'src/types/components.d.ts'
41
51
  })
42
52
  ],
@@ -46,53 +56,38 @@ export default defineConfig({
46
56
  }
47
57
  },
48
58
  define: {
49
- 'process.env': { TINY_MODE: 'pc' } // OpenTiny 需要的环境变量
59
+ __DEV__: JSON.stringify(process.env.NODE_ENV !== 'production')
50
60
  },
51
61
  css: {
52
62
  preprocessorOptions: {
53
63
  scss: {
54
- api: 'modern-compiler',
55
- additionalData: `@use "@/styles/internal/variables.scss" as *;`
64
+ additionalData: `@use "@/styles/internal/variables.scss" as *;`,
65
+ api: 'modern-compiler'
56
66
  }
57
67
  }
58
68
  },
59
69
  server: {
60
- port: 5173,
61
- host: true,
70
+ host: '0.0.0.0',
71
+ port: 5600,
72
+ strictPort: true,
62
73
  open: false
63
74
  },
64
75
  logLevel: 'info',
65
- customLogger: {
66
- info: (msg) => {
67
- // 过滤掉频繁的依赖优化信息
68
- if (msg.includes('new dependencies optimized')) {
69
- return;
70
- }
71
- console.info(msg);
72
- },
73
- warn: console.warn,
74
- error: console.error
75
- },
76
76
  optimizeDeps: {
77
- include: ['vue', 'vue-router', 'pinia', 'lucide-vue-next', 'axios', '@opentiny/vue'],
78
- exclude: [],
79
- // 禁用自动发现,减少频繁优化提示
80
- noDiscovery: true,
81
- // 增加缓存时间,避免重复优化
82
- force: false,
83
- esbuildOptions: {
84
- target: 'esnext'
85
- }
77
+ include: ['vue', 'vue-router', 'pinia', '@opentiny/vue', 'axios']
86
78
  },
87
79
  build: {
80
+ target: 'esnext',
88
81
  outDir: 'dist',
82
+ assetsDir: 'assets',
89
83
  sourcemap: false,
90
- chunkSizeWarningLimit: 1500,
84
+ minify: 'esbuild',
85
+ chunkSizeWarningLimit: 1000,
91
86
  rollupOptions: {
92
87
  output: {
93
88
  manualChunks: {
94
- 'vue-vendor': ['vue', 'vue-router', 'pinia'],
95
- 'opentiny-vendor': ['@opentiny/vue']
89
+ vue: ['vue', 'vue-router', 'pinia'],
90
+ opentiny: ['@opentiny/vue']
96
91
  }
97
92
  }
98
93
  }
@@ -1,41 +0,0 @@
1
- <template>
2
- <component :is="iconComponent" :size="size" :color="color" :stroke-width="strokeWidth" style="margin-right: 8px; vertical-align: middle" v-bind="$attrs" />
3
- </template>
4
-
5
- <script setup>
6
- import * as LucideIcons from 'lucide-vue-next';
7
- import { computed, markRaw } from 'vue';
8
-
9
- const props = defineProps({
10
- name: {
11
- type: String,
12
- required: true
13
- },
14
- size: {
15
- type: Number,
16
- default: 16
17
- },
18
- color: {
19
- type: String,
20
- default: 'currentColor'
21
- },
22
- strokeWidth: {
23
- type: Number,
24
- default: 2
25
- }
26
- });
27
-
28
- // 动态获取图标组件
29
- const iconComponent = computed(() => {
30
- const iconName = props.name;
31
- const icon = LucideIcons[iconName];
32
-
33
- if (!icon) {
34
- console.warn(`Icon "${props.name}" not found in lucide-vue-next`);
35
- return null;
36
- }
37
-
38
- // 使用 markRaw 避免响应式包装
39
- return markRaw(icon);
40
- });
41
- </script>
@@ -1,19 +0,0 @@
1
- import { defineStore } from 'pinia';
2
-
3
- /**
4
- * 全局状态管理
5
- * 集中管理所有全局数据,避免分散到多个 store 文件
6
- */
7
- export const useGlobal = defineStore('global', () => {
8
- // ==================== 全局状态 ====================
9
-
10
- // 可以在这里添加全局状态,例如:
11
- // - 用户信息
12
- // - 主题配置
13
- // - 应用设置
14
- // - 等等
15
-
16
- return {
17
- // 暂时没有状态和方法
18
- };
19
- });