@pubinfo/core 2.0.0-rc.3 → 2.0.0-rc.5

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 (130) hide show
  1. package/dist/{AppSetting-3wJKvibc.js → AppSetting-DqVYDIHj.js} +15 -15
  2. package/dist/{HCheckList.vue_vue_type_script_setup_true_lang-17EywJvs.js → HCheckList.vue_vue_type_script_setup_true_lang-SrNklW3P.js} +1 -1
  3. package/dist/{HToggle-B-ZjSh6S.js → HToggle-DGTP9jYA.js} +1 -1
  4. package/dist/{PreferencesContent-xT4paU7N.js → PreferencesContent-5NtwK9RQ.js} +4 -4
  5. package/dist/{SettingBreadcrumb-CYnO51Ek.js → SettingBreadcrumb-BudqQsuJ.js} +3 -3
  6. package/dist/{SettingCopyright-FOW5ObHK.js → SettingCopyright-VUberG4R.js} +2 -2
  7. package/dist/{SettingEnableTransition-Q5cvubmF.js → SettingEnableTransition-C6NYf021.js} +2 -2
  8. package/dist/SettingHome-BTaeKgwN.js +46 -0
  9. package/dist/{SettingMenu-BNAJ3el9.js → SettingMenu-D9Aon2LP.js} +3 -3
  10. package/dist/{SettingMode-LzlRsBL9.js → SettingMode-DaqVd9Mq.js} +1 -1
  11. package/dist/{SettingNavSearch-BA08vYuw.js → SettingNavSearch-N4JIheIk.js} +2 -2
  12. package/dist/{SettingOther-BE8dDCYD.js → SettingOther-tLulcors.js} +2 -2
  13. package/dist/{SettingPage-D061yXCv.js → SettingPage-CEjWB45R.js} +2 -2
  14. package/dist/{SettingTabbar-COwdPPKy.js → SettingTabbar-DyeLhcCT.js} +3 -3
  15. package/dist/{SettingThemes-BHaYERNp.js → SettingThemes-C2M3tsVl.js} +1 -1
  16. package/dist/{SettingToolbar-fSuzu6ND.js → SettingToolbar-DI7de6i0.js} +24 -31
  17. package/dist/{SettingTopbar-D7GgP0KB.js → SettingTopbar-BgIoXeAq.js} +3 -3
  18. package/dist/{SettingWidthMode-CNjzChe1.js → SettingWidthMode-DIAU4s5e.js} +1 -1
  19. package/dist/{TopThinMode-B-28sBJD.js → TopThinMode-JNUHrJI2.js} +1 -1
  20. package/dist/built-in/authentication/alova/helper.d.ts +34 -0
  21. package/dist/built-in/authentication/alova/token.d.ts +16 -0
  22. package/dist/built-in/authentication/helper.d.ts +10 -1
  23. package/dist/built-in/index.d.ts +1 -1
  24. package/dist/built-in/layout-component/components/Tools/SearchPanel.vue.d.ts +7 -2
  25. package/dist/built-in/layout-component/components/ui/HSlideover.vue.d.ts +1 -1
  26. package/dist/built-in/layout-component/composables/useContext.d.ts +1 -1
  27. package/dist/built-in/layout-component/composables/useGlobalSearch.d.ts +7 -0
  28. package/dist/built-in/layout-component/composables/useTitle.d.ts +1 -1
  29. package/dist/built-in/system-info/components/SystemInfo.vue.d.ts +2 -0
  30. package/dist/built-in/system-info/index.d.ts +5 -0
  31. package/dist/{colors-BIQSd520.js → colors-DxWfHM_v.js} +1 -1
  32. package/dist/core/interface.d.ts +14 -5
  33. package/dist/core/request.d.ts +2 -8
  34. package/dist/features/api/modules/auth/renzhengfuwu.d.ts +8 -8
  35. package/dist/features/api/modules/configData/heibaimingdanfuwu.d.ts +5 -5
  36. package/dist/features/api/modules/configData/xitongpeizhifuwu.d.ts +14 -14
  37. package/dist/features/api/modules/configData/zidifuwu.d.ts +10 -10
  38. package/dist/features/api/modules/rbac/gangweijiekou.d.ts +6 -6
  39. package/dist/features/api/modules/rbac/jiaosejiekou.d.ts +7 -7
  40. package/dist/features/api/modules/rbac/pubJiaosezukongzhiqi.d.ts +7 -7
  41. package/dist/features/api/modules/rbac/shujuquanxianzhubiaokongzhiqi.d.ts +9 -9
  42. package/dist/features/api/modules/rbac/yonghujiekou.d.ts +15 -15
  43. package/dist/features/api/modules/rbac/yonghushoucangbiaojiekou.d.ts +5 -5
  44. package/dist/features/api/modules/rbac/yonghuzuijinchangyongbiaojiekou.d.ts +4 -4
  45. package/dist/features/api/modules/rbac/ziyuanjiekou.d.ts +13 -13
  46. package/dist/features/api/modules/rbac/zuhuguanlijiekou.d.ts +5 -5
  47. package/dist/features/api/modules/rbac/zuzhijiaosebiaokongzhiqi.d.ts +4 -4
  48. package/dist/features/api/modules/rbac/zuzhijiekou.d.ts +9 -9
  49. package/dist/features/api/system/user.d.ts +4 -4
  50. package/dist/features/components/PubinfoIcon/PrismBox.vue.d.ts +21 -0
  51. package/dist/features/components/PubinfoIcon/SquareBox.vue.d.ts +17 -0
  52. package/dist/features/components/PubinfoIcon/index.vue.d.ts +13 -9
  53. package/dist/features/components/PubinfoIcon/props.d.ts +58 -0
  54. package/dist/features/components/index.d.ts +2 -0
  55. package/dist/{index-Dlf6GQBd.js → index-5fRpGyLW.js} +4 -4
  56. package/dist/{index-DNdH93AP.js → index-BFRIv97x.js} +2 -2
  57. package/dist/{index-WubcSL0v.js → index-BH-vHGvk.js} +1 -1
  58. package/dist/{index-YSjb6X1D.js → index-C7xIGcDc.js} +4 -7
  59. package/dist/{index-DYMBkmAp.js → index-CNVn3Ubv.js} +2 -2
  60. package/dist/{index-CPRiufg0.js → index-Cf-u1Zqh.js} +1 -1
  61. package/dist/{index-wxEEuQXu.js → index-D4v4g8FJ.js} +111 -97
  62. package/dist/{index-IscoZG-Y.js → index-DQGnbEGS.js} +2 -2
  63. package/dist/{index-Beb7_0-E.js → index-Dv7UUFkD.js} +24237 -23807
  64. package/dist/index.d.ts +1 -1
  65. package/dist/index.js +55 -48
  66. package/dist/{pick-D_XPbQHB.js → pick-VFuUwFn-.js} +1 -1
  67. package/dist/style.css +1 -1
  68. package/dist/utils/global.d.ts +33 -0
  69. package/dist/utils/index.d.ts +2 -1
  70. package/package.json +10 -7
  71. package/src/built-in/authentication/alova/helper.ts +158 -0
  72. package/src/built-in/authentication/alova/token.ts +122 -0
  73. package/src/built-in/authentication/helper.ts +7 -3
  74. package/src/built-in/authentication/index.ts +6 -20
  75. package/src/built-in/index.ts +1 -1
  76. package/src/built-in/layout-component/components/Header/TopMode/index.vue +30 -9
  77. package/src/built-in/layout-component/components/Menu/item.vue +44 -9
  78. package/src/built-in/layout-component/components/SettingBar/components/SettingHome.vue +1 -4
  79. package/src/built-in/layout-component/components/SettingBar/components/SettingToolbar.vue +0 -6
  80. package/src/built-in/layout-component/components/Sidebar/MainSidebar.vue +3 -3
  81. package/src/built-in/layout-component/components/Tools/SearchBar.vue +1 -3
  82. package/src/built-in/layout-component/components/Tools/SearchPanel.vue +125 -57
  83. package/src/built-in/layout-component/components/Tools/index.vue +9 -12
  84. package/src/built-in/layout-component/components/Topbar/Tabbar/MoreAction.vue +64 -11
  85. package/src/built-in/layout-component/components/Topbar/Tabbar/index.vue +73 -18
  86. package/src/built-in/layout-component/components/Topbar/Toolbar/Favorites.vue +4 -7
  87. package/src/built-in/layout-component/components/Topbar/Toolbar/index.vue +6 -6
  88. package/src/built-in/layout-component/composables/useContext.ts +1 -1
  89. package/src/built-in/layout-component/composables/useGlobalSearch.ts +40 -1
  90. package/src/built-in/layout-component/composables/useTitle.ts +8 -14
  91. package/src/built-in/layout-component/provider.ts +2 -2
  92. package/src/built-in/system-info/components/SystemInfo.vue +53 -0
  93. package/src/built-in/system-info/index.ts +16 -0
  94. package/src/core/ctx.ts +7 -1
  95. package/src/core/interface.ts +18 -5
  96. package/src/core/request.ts +35 -15
  97. package/src/core/resolver/icon.ts +9 -5
  98. package/src/features/components/PubinfoIcon/PrismBox.vue +203 -0
  99. package/src/features/components/PubinfoIcon/SquareBox.vue +59 -0
  100. package/src/features/components/PubinfoIcon/index.vue +128 -37
  101. package/src/features/components/PubinfoIcon/props.ts +54 -0
  102. package/src/features/components/index.ts +4 -1
  103. package/src/features/context/index.ts +1 -16
  104. package/src/features/router/systemRoutes.ts +0 -1
  105. package/src/features/settings/index.ts +0 -1
  106. package/src/features/stores/modules/favorites.ts +0 -1
  107. package/src/features/stores/modules/route.ts +2 -9
  108. package/src/features/stores/modules/tabbar.ts +0 -3
  109. package/src/features/stores/utils/routerHelper.ts +35 -4
  110. package/src/index.ts +7 -2
  111. package/src/utils/global.ts +161 -0
  112. package/src/utils/index.ts +2 -1
  113. package/src/utils/proxy.ts +7 -8
  114. package/types/global.d.ts +7 -0
  115. package/types/menu.d.ts +10 -0
  116. package/types/settings.d.ts +0 -7
  117. package/types/vue-router.d.ts +0 -3
  118. package/dist/SettingHome-Df7-AlWB.js +0 -55
  119. package/dist/built-in/locales/helpler.d.ts +0 -594
  120. package/dist/built-in/locales/index.d.ts +0 -5
  121. package/dist/built-in/locales/lang/en.json.d.ts +0 -99
  122. package/dist/built-in/locales/lang/zh-cn.json.d.ts +0 -100
  123. package/dist/built-in/locales/lang/zh-tw.json.d.ts +0 -100
  124. package/dist/built-in/locales/ui.d.ts +0 -3
  125. package/src/built-in/locales/helpler.ts +0 -76
  126. package/src/built-in/locales/index.ts +0 -20
  127. package/src/built-in/locales/lang/en.json +0 -96
  128. package/src/built-in/locales/lang/zh-cn.json +0 -97
  129. package/src/built-in/locales/lang/zh-tw.json +0 -97
  130. package/src/built-in/locales/ui.ts +0 -3
@@ -1,5 +1,4 @@
1
1
  <script setup lang="ts">
2
- import { useI18n } from 'vue-i18n';
3
2
  import IconamoonSearch from '~icons/iconamoon/search';
4
3
  import { useContext } from '../../composables/useContext';
5
4
  import { useGlobalSearch } from '../../composables/useGlobalSearch';
@@ -10,7 +9,6 @@ defineOptions({
10
9
 
11
10
  const { settingsStore } = useContext();
12
11
  const { toggle: toggleSearch } = useGlobalSearch();
13
- const { t } = useI18n();
14
12
 
15
13
  const searchComponentsClass = computed(() => {
16
14
  const componentsClass = {
@@ -33,7 +31,7 @@ const searchComponentsClass = computed(() => {
33
31
  @click="toggleSearch('menu')"
34
32
  >
35
33
  <IconamoonSearch text="14px" />
36
- <span class="text-sm transition ">{{ t('app.search.text') }}</span>
34
+ <span class="text-sm transition ">{{ '搜索' }}</span>
37
35
  <HKbd
38
36
  v-if="settingsStore.settings.navSearch.enableHotkeys"
39
37
  class="ml-2"
@@ -6,7 +6,7 @@ import { Dialog, DialogDescription, DialogPanel, TransitionChild, TransitionRoot
6
6
  import hotkeys from 'hotkeys-js';
7
7
  import { cloneDeep } from 'lodash-es';
8
8
  import { OverlayScrollbarsComponent } from 'overlayscrollbars-vue';
9
- import { useI18n } from 'vue-i18n';
9
+ import { computed, onBeforeUpdate, onUnmounted, ref, watch } from 'vue';
10
10
  import AntDesignCaretDownFilled from '~icons/ant-design/caret-down-filled';
11
11
  import AntDesignCaretUpFilled from '~icons/ant-design/caret-up-filled';
12
12
  import EpSearch from '~icons/ep/search';
@@ -25,6 +25,10 @@ defineOptions({
25
25
  name: 'SearchPanel',
26
26
  });
27
27
 
28
+ const props = withDefaults(defineProps<{ priority?: number }>(), {
29
+ priority: 0,
30
+ });
31
+
28
32
  const overlayTransitionClass = ref({
29
33
  enter: 'ease-in-out duration-500',
30
34
  enterFrom: 'opacity-0',
@@ -45,22 +49,35 @@ const transitionClass = computed(() => {
45
49
  };
46
50
  });
47
51
 
48
- const { t } = useI18n();
49
-
50
52
  const router = useRouter();
51
- const { settingsStore, routeStore, tabbarStore, generateI18nTitle } = useContext();
53
+ const { settingsStore, routeStore, tabbarStore, generateTitle } = useContext();
52
54
 
53
55
  type searchTypes = 'menu' | 'tab';
54
56
  interface listTypes {
55
57
  path: string
56
58
  icon?: string
57
59
  title?: string | (() => string)
58
- i18n?: string
59
60
  link?: string
60
61
  breadcrumb: any[]
61
62
  }
62
63
 
63
- const { isShow, searchType, toggle: globalToggle } = useGlobalSearch();
64
+ const { isShow, searchType, activePanelId, toggle: globalToggle, close: globalClose, registerPanel, unregisterPanel, setPanelPriority } = useGlobalSearch();
65
+ const panelId = Symbol('global-search-panel');
66
+ const hasRegisteredGlobalHotkeys = ref(false);
67
+ registerPanel(panelId, props.priority);
68
+ onUnmounted(() => {
69
+ unregisterPanel(panelId);
70
+ if (hasRegisteredGlobalHotkeys.value) {
71
+ hotkeys.unbind('alt+s', handleOpenHotkey);
72
+ hotkeys.unbind('esc', handleCloseHotkey);
73
+ hasRegisteredGlobalHotkeys.value = false;
74
+ }
75
+ hotkeys.unbind('up', keyUp);
76
+ hotkeys.unbind('down', keyDown);
77
+ hotkeys.unbind('enter', keyEnter);
78
+ });
79
+ watch(() => props.priority, val => setPanelPriority(panelId, val));
80
+ const isActivePanel = computed(() => activePanelId.value === panelId);
64
81
  const searchInput = ref('');
65
82
  const sourceList = ref<listTypes[]>([]);
66
83
  const actived = ref(-1);
@@ -76,13 +93,13 @@ const resultList = computed(() => {
76
93
  let result = [];
77
94
  result = sourceList.value.filter((item) => {
78
95
  let flag = false;
79
- if (generateI18nTitle(item.i18n, item.title).toString().includes(searchInput.value)) {
96
+ if (generateTitle(item.title).toString().includes(searchInput.value)) {
80
97
  flag = true;
81
98
  }
82
99
  if (item.path.includes(searchInput.value)) {
83
100
  flag = true;
84
101
  }
85
- if (item.breadcrumb.some((b: { i18n: any, title: any }) => generateI18nTitle(b.i18n, b.title).toString().includes(searchInput.value))) {
102
+ if (item.breadcrumb.some((b: { title: any }) => generateTitle(b.title).toString().includes(searchInput.value))) {
86
103
  flag = true;
87
104
  }
88
105
  return flag;
@@ -90,44 +107,79 @@ const resultList = computed(() => {
90
107
  return result;
91
108
  });
92
109
 
93
- watch(() => isShow.value, (val) => {
94
- if (val) {
95
- searchInput.value = '';
110
+ watch(
111
+ [() => isShow.value, () => isActivePanel.value],
112
+ ([show, active]) => {
113
+ if (!active) {
114
+ hotkeys.unbind('up', keyUp);
115
+ hotkeys.unbind('down', keyDown);
116
+ hotkeys.unbind('enter', keyEnter);
117
+ return;
118
+ }
119
+ if (show) {
120
+ searchInput.value = '';
121
+ actived.value = -1;
122
+ // 当搜索显示的时候绑定上、下、回车快捷键,隐藏的时候再解绑。另外当 input 处于 focus 状态时,采用 vue 来绑定键盘事件
123
+ hotkeys('up', keyUp);
124
+ hotkeys('down', keyDown);
125
+ hotkeys('enter', keyEnter);
126
+ }
127
+ else {
128
+ hotkeys.unbind('up', keyUp);
129
+ hotkeys.unbind('down', keyDown);
130
+ hotkeys.unbind('enter', keyEnter);
131
+ }
132
+ },
133
+ { immediate: true },
134
+ );
135
+ watch(
136
+ () => resultList.value,
137
+ () => {
138
+ if (!isActivePanel.value || !isShow.value) {
139
+ return;
140
+ }
96
141
  actived.value = -1;
97
- // 当搜索显示的时候绑定上、下、回车快捷键,隐藏的时候再解绑。另外当 input 处于 focus 状态时,采用 vue 来绑定键盘事件
98
- hotkeys('up', keyUp);
99
- hotkeys('down', keyDown);
100
- hotkeys('enter', keyEnter);
142
+ handleScroll();
143
+ },
144
+ );
145
+
146
+ function handleOpenHotkey(e: KeyboardEvent) {
147
+ if (settingsStore.settings.navSearch.enable && settingsStore.settings.navSearch.enableHotkeys) {
148
+ e.preventDefault();
149
+ initSourceList();
150
+ isShow.value = true;
101
151
  }
102
- else {
103
- hotkeys.unbind('up', keyUp);
104
- hotkeys.unbind('down', keyDown);
105
- hotkeys.unbind('enter', keyEnter);
152
+ }
153
+
154
+ function handleCloseHotkey(e: KeyboardEvent) {
155
+ if (settingsStore.settings.navSearch.enable && settingsStore.settings.navSearch.enableHotkeys) {
156
+ e.preventDefault();
157
+ isShow.value = false;
106
158
  }
107
- });
108
- watch(() => resultList.value, () => {
109
- actived.value = -1;
110
- handleScroll();
111
- });
159
+ }
112
160
 
113
- onMounted(() => {
114
- hotkeys('alt+s', (e) => {
115
- if (settingsStore.settings.navSearch.enable && settingsStore.settings.navSearch.enableHotkeys) {
116
- e.preventDefault();
161
+ watch(
162
+ () => isActivePanel.value,
163
+ (active) => {
164
+ if (active && !hasRegisteredGlobalHotkeys.value) {
165
+ hotkeys('alt+s', handleOpenHotkey);
166
+ hotkeys('esc', handleCloseHotkey);
167
+ hasRegisteredGlobalHotkeys.value = true;
117
168
  initSourceList();
118
- isShow.value = true;
119
169
  }
120
- });
121
- hotkeys('esc', (e) => {
122
- if (settingsStore.settings.navSearch.enable && settingsStore.settings.navSearch.enableHotkeys) {
123
- e.preventDefault();
124
- isShow.value = false;
170
+ else if (!active && hasRegisteredGlobalHotkeys.value) {
171
+ hotkeys.unbind('alt+s', handleOpenHotkey);
172
+ hotkeys.unbind('esc', handleCloseHotkey);
173
+ hasRegisteredGlobalHotkeys.value = false;
125
174
  }
126
- });
127
- initSourceList();
128
- });
175
+ },
176
+ { immediate: true },
177
+ );
129
178
 
130
179
  function switchType(type: any) {
180
+ if (!isActivePanel.value) {
181
+ return;
182
+ }
131
183
  searchInputRef.value.focus();
132
184
  initSourceList(type);
133
185
  }
@@ -155,27 +207,24 @@ function hasChildren(item: RouteRecordRaw) {
155
207
  }
156
208
  return flag;
157
209
  }
158
- function getSourceList(arr: RouteRecordRaw[], basePath?: string, icon?: string, breadcrumb?: { title?: string | (() => string), i18n?: string }[]) {
210
+ function getSourceList(arr: RouteRecordRaw[], basePath?: string, icon?: string, breadcrumb?: { title?: string | (() => string) }[]) {
159
211
  arr.forEach((item) => {
160
212
  if (item.meta?.sidebar !== false) {
161
213
  const breadcrumbTemp = cloneDeep(breadcrumb) || [];
162
214
  if (item.children && hasChildren(item)) {
163
215
  breadcrumbTemp.push({
164
216
  title: item.meta?.title,
165
- i18n: item.meta?.i18n,
166
217
  });
167
218
  getSourceList(item.children, resolveRoutePath(basePath, item.path), item.meta?.icon ?? icon, breadcrumbTemp);
168
219
  }
169
220
  else {
170
221
  breadcrumbTemp.push({
171
222
  title: item.meta?.title,
172
- i18n: item.meta?.i18n,
173
223
  });
174
224
  sourceList.value.push({
175
225
  path: resolveRoutePath(basePath, item.path),
176
226
  icon: item.meta?.icon ?? icon,
177
227
  title: item.meta?.title,
178
- i18n: item.meta?.i18n,
179
228
  link: item.meta?.link,
180
229
  breadcrumb: breadcrumbTemp,
181
230
  });
@@ -190,13 +239,15 @@ function getSourceListByTabs(arr: Tabbar.recordRaw[]) {
190
239
  icon: item.icon,
191
240
  title: item.title,
192
241
  path: item.fullPath,
193
- i18n: item.i18n,
194
242
  breadcrumb: [],
195
243
  });
196
244
  });
197
245
  }
198
246
 
199
247
  function keyUp() {
248
+ if (!isActivePanel.value) {
249
+ return;
250
+ }
200
251
  if (resultList.value.length) {
201
252
  actived.value -= 1;
202
253
  if (actived.value < 0) {
@@ -206,6 +257,9 @@ function keyUp() {
206
257
  }
207
258
  }
208
259
  function keyDown() {
260
+ if (!isActivePanel.value) {
261
+ return;
262
+ }
209
263
  if (resultList.value.length) {
210
264
  actived.value += 1;
211
265
  if (actived.value > resultList.value.length - 1) {
@@ -215,11 +269,17 @@ function keyDown() {
215
269
  }
216
270
  }
217
271
  function keyEnter() {
272
+ if (!isActivePanel.value) {
273
+ return;
274
+ }
218
275
  if (actived.value !== -1) {
219
276
  searchResultItemRef.value.find(item => Number.parseInt(item.dataset.index!) === actived.value)?.click();
220
277
  }
221
278
  }
222
279
  function handleScroll() {
280
+ if (!isActivePanel.value) {
281
+ return;
282
+ }
223
283
  if (searchResultRef.value) {
224
284
  const contentDom = searchResultRef.value.osInstance()!.elements().content;
225
285
  let scrollTo = 0;
@@ -249,7 +309,9 @@ function pageJump(path: listTypes['path'], link: listTypes['link']) {
249
309
  else {
250
310
  router.push(path);
251
311
  }
252
- isShow.value = false;
312
+ if (isActivePanel.value) {
313
+ globalClose();
314
+ }
253
315
  }
254
316
 
255
317
  function toggle(type?: 'menu' | 'tab') {
@@ -260,11 +322,17 @@ function toggle(type?: 'menu' | 'tab') {
260
322
  }
261
323
 
262
324
  // 初始化本地 searchTypeLocal 与全局 searchType 同步
263
- watch(() => searchType.value, (val) => {
264
- if (val) {
265
- initSourceList(val as searchTypes);
266
- }
267
- });
325
+ watch(
326
+ () => searchType.value,
327
+ (val) => {
328
+ if (!isActivePanel.value) {
329
+ return;
330
+ }
331
+ if (val) {
332
+ initSourceList(val as searchTypes);
333
+ }
334
+ },
335
+ );
268
336
 
269
337
  defineExpose({
270
338
  toggle,
@@ -272,7 +340,7 @@ defineExpose({
272
340
  </script>
273
341
 
274
342
  <template>
275
- <TransitionRoot as="template" :show="isShow">
343
+ <TransitionRoot v-if="isActivePanel" as="template" :show="isShow">
276
344
  <Dialog :initial-focus="searchInputRef" class="fixed inset-0 z-2000 flex" @close="isShow && toggle()">
277
345
  <TransitionChild as="template" v-bind="overlayTransitionClass">
278
346
  <div class="fixed inset-0 bg-stone-200/75 backdrop-blur-sm transition-opacity dark:bg-stone-8/75" />
@@ -285,8 +353,8 @@ defineExpose({
285
353
  v-if="settingsStore.settings.tabbar.enable"
286
354
  v-model="searchType"
287
355
  :options="[
288
- { label: t('app.search.type.menu'), value: 'menu' },
289
- { label: t('app.search.type.tab'), value: 'tab' },
356
+ { label: '搜索导航菜单', value: 'menu' },
357
+ { label: '搜索标签页', value: 'tab' },
290
358
  ]"
291
359
  class="mb-4 flex!"
292
360
  @click.stop
@@ -298,7 +366,7 @@ defineExpose({
298
366
  <input
299
367
  ref="searchInputRef"
300
368
  v-model="searchInput"
301
- :placeholder="t('app.search.input')"
369
+ placeholder="搜索页面,支持标题、URL模糊查询"
302
370
  class="w-full border-0 rounded-md bg-transparent px-3 text-base text-dark dark:text-white focus:outline-none placeholder-stone-4 dark:placeholder-stone-5"
303
371
  @keydown.esc="toggle()"
304
372
  @keydown.up.prevent="keyUp"
@@ -332,10 +400,10 @@ defineExpose({
332
400
  :class="{ 'scale-120 text-ui-primary': index === actived }"
333
401
  />
334
402
  <div class="flex flex-1 flex-col gap-1 truncate px-4 py-3" border-l="~ solid stone-2 dark:stone-7">
335
- <div class="truncate text-base font-bold">{{ generateI18nTitle(item.i18n, item.title) }}</div>
403
+ <div class="truncate text-base font-bold">{{ generateTitle(item.title) }}</div>
336
404
  <Breadcrumb v-if="item.breadcrumb.length" class="truncate">
337
405
  <BreadcrumbItem v-for="(bc, bcIndex) in item.breadcrumb" :key="bcIndex" class="text-xs">
338
- {{ generateI18nTitle(bc.i18n, bc.title) }}
406
+ {{ generateTitle(bc.title) }}
339
407
  </BreadcrumbItem>
340
408
  </Breadcrumb>
341
409
  </div>
@@ -357,7 +425,7 @@ defineExpose({
357
425
  <HKbd>
358
426
  <IonMdReturnLeft text="14px" />
359
427
  </HKbd>
360
- <span>{{ t('app.search.enter') }}</span>
428
+ <span>{{ '访问' }}</span>
361
429
  </div>
362
430
  <div class="inline-flex items-center gap-1 text-xs">
363
431
  <HKbd>
@@ -366,14 +434,14 @@ defineExpose({
366
434
  <HKbd>
367
435
  <AntDesignCaretDownFilled text="14px" />
368
436
  </HKbd>
369
- <span>{{ t('app.search.up_down') }}</span>
437
+ <span>{{ '切换' }}</span>
370
438
  </div>
371
439
  </div>
372
440
  <div v-if="settingsStore.settings.navSearch.enableHotkeys" class="inline-flex items-center gap-1 text-xs">
373
441
  <HKbd>
374
442
  ESC
375
443
  </HKbd>
376
- <span>{{ t('app.search.esc') }}</span>
444
+ <span>{{ '退出' }}</span>
377
445
  </div>
378
446
  </div>
379
447
  </div>
@@ -1,6 +1,5 @@
1
1
  <script setup lang="ts">
2
2
  import type { DropdownMenuRender } from './interface';
3
- import { useI18n } from 'vue-i18n';
4
3
  import CarbonUserAvatarFilledAlt from '~icons/carbon/user-avatar-filled-alt';
5
4
  import MaterialSymbolsExpandMoreRounded from '~icons/material-symbols/expand-more-rounded';
6
5
 
@@ -31,9 +30,7 @@ const props = withDefaults(
31
30
  );
32
31
 
33
32
  const router = useRouter();
34
- const { settingsStore, userStore, generateI18nTitle } = useContext();
35
-
36
- const { t } = useI18n();
33
+ const { settingsStore, userStore, generateTitle } = useContext();
37
34
 
38
35
  const hotkeysIntroRef = ref();
39
36
  const preferencesRef = ref();
@@ -42,28 +39,28 @@ const userMenu = computed(() => {
42
39
  return {
43
40
  Home: {
44
41
  key: 'home',
45
- label: generateI18nTitle('route.home', settingsStore.settings.home.title),
42
+ label: generateTitle(settingsStore.settings.home.title),
46
43
  icon: 'i-ant-design:home-twotone',
47
44
  onClick: () => router.push({ name: 'Home' }),
48
45
  hide: !settingsStore.settings.home.enable,
49
46
  },
50
47
  Preferences: {
51
48
  key: 'preferences',
52
- label: t('app.preferences'),
49
+ label: '个人偏好设置',
53
50
  icon: 'i-iconamoon-star-duotone',
54
51
  onClick: () => preferencesRef.value?.open?.(),
55
52
  hide: !settingsStore.settings.app.enableUserPreferences,
56
53
  },
57
54
  Hotkeys: {
58
55
  key: 'hotkeys',
59
- label: t('app.hotkeys'),
56
+ label: '快捷键介绍',
60
57
  icon: 'i-iconamoon-lightning-2-duotone',
61
58
  onClick: () => hotkeysIntroRef.value?.open?.(),
62
59
  hide: settingsStore.mode !== 'pc',
63
60
  },
64
61
  Org: {
65
62
  key: 'org',
66
- label: t('app.changeOrg'),
63
+ label: '切换组织',
67
64
  icon: 'i-iconamoon-synchronize-duotone',
68
65
  onClick: () => router.push({
69
66
  name: 'ChangeOrganization',
@@ -73,13 +70,13 @@ const userMenu = computed(() => {
73
70
  },
74
71
  Profile: {
75
72
  key: 'profile',
76
- label: t('route.personal.profile'),
73
+ label: '个人中心',
77
74
  icon: 'i-iconamoon-profile-duotone',
78
75
  onClick: () => router.push({ name: 'Profile' }),
79
76
  },
80
77
  Password: {
81
78
  key: 'password',
82
- label: t('app.changePassword'),
79
+ label: '修改密码',
83
80
  icon: 'i-iconamoon-lock-duotone',
84
81
  onClick: () => router.push({
85
82
  name: 'ChangePassword',
@@ -90,7 +87,7 @@ const userMenu = computed(() => {
90
87
  },
91
88
  Logout: {
92
89
  key: 'logout',
93
- label: t('app.logout'),
90
+ label: '退出登录',
94
91
  icon: 'i-iconamoon-arrow-left-3-square-duotone',
95
92
  onClick: () => userStore.logout(),
96
93
  },
@@ -146,7 +143,7 @@ watch(() => userStore.user.avatar, () => {
146
143
  </div>
147
144
 
148
145
  <HotkeysIntro ref="hotkeysIntroRef" />
149
- <SearchPanel />
146
+ <SearchPanel :priority="10" />
150
147
  <Preferences v-if="settingsStore.settings.app.enableUserPreferences" ref="preferencesRef" />
151
148
  </div>
152
149
  </template>
@@ -2,7 +2,6 @@
2
2
  import type { Tabbar } from '#/tabbar';
3
3
  import { OverlayScrollbarsComponent } from 'overlayscrollbars-vue';
4
4
  import Sortable from 'sortablejs';
5
- import { useI18n } from 'vue-i18n';
6
5
  import EpClose from '~icons/ep/close';
7
6
  import EpSearch from '~icons/ep/search';
8
7
  import PhArrowLineLeft from '~icons/ph/arrow-line-left';
@@ -22,12 +21,10 @@ defineOptions({
22
21
 
23
22
  const router = useRouter();
24
23
 
25
- const { settingsStore, tabbarStore, generateI18nTitle } = useContext();
24
+ const { settingsStore, tabbarStore, generateTitle, routeStore } = useContext();
26
25
 
27
26
  const tabbar = useTabbar();
28
27
 
29
- const { t } = useI18n();
30
-
31
28
  const activedTabId = computed(() => tabbar.getId());
32
29
 
33
30
  const dropdownTabContainerRef = ref();
@@ -88,6 +85,44 @@ function iconName(isActive: boolean, icon: Tabbar.recordRaw['icon'], activeIcon:
88
85
  }
89
86
  return name;
90
87
  }
88
+
89
+ // 解析 fullPath 的纯路径部分(去掉 query/hash)
90
+ function stripPath(fullPath: string) {
91
+ return fullPath.split(/[?#]/)[0];
92
+ }
93
+
94
+ // 查找与 tab 对应的路由记录
95
+ function findRouteRecordByElement(element: Tabbar.recordRaw) {
96
+ const pathOnly = stripPath(element.fullPath);
97
+ const all = [...routeStore.flatSystemRoutes, ...routeStore.flatRoutes] as any[];
98
+ return all.find(r => r.path === pathOnly);
99
+ }
100
+
101
+ // 解析该 tab 的 iconOptions(优先当前路由,其次面包屑链路上最近的一个)
102
+ function resolveIconOptions(element: Tabbar.recordRaw): undefined | {
103
+ boxType?: 'square' | 'prism' | 'null'
104
+ angle?: number | string
105
+ background?: any
106
+ radius?: number | string
107
+ iconColor?: string
108
+ } {
109
+ const r: any = findRouteRecordByElement(element);
110
+ let options = (r?.meta as any)?.iconOptions;
111
+ if (!options && r?.meta?.breadcrumbNeste?.length) {
112
+ const found = [...r.meta.breadcrumbNeste].reverse().find((it: any) => it?.iconOptions);
113
+ options = found?.iconOptions;
114
+ }
115
+ return options;
116
+ }
117
+
118
+ function computeBoxType(options: ReturnType<typeof resolveIconOptions>) {
119
+ const bt = (options as any)?.boxType as any;
120
+ return bt && bt !== 'null' ? bt : 'prism';
121
+ }
122
+
123
+ function getSafeIconColor(options: ReturnType<typeof resolveIconOptions>): string | undefined {
124
+ return (options as any)?.iconColor || undefined;
125
+ }
91
126
  </script>
92
127
 
93
128
  <template>
@@ -99,22 +134,22 @@ function iconName(isActive: boolean, icon: Tabbar.recordRaw['icon'], activeIcon:
99
134
  <template #dropdown>
100
135
  <div class="quick-button">
101
136
  <button v-if="settingsStore.settings.navSearch.enable" class="button" @click="actionCommand('search-tabs')">
102
- <HTooltip :text="t('app.tabbar.searchTabs')">
137
+ <HTooltip text="搜索标签页">
103
138
  <EpSearch />
104
139
  </HTooltip>
105
140
  </button>
106
141
  <button class="button" :disabled="!tabbar.checkCloseOtherSide()" @click="actionCommand('other-side')">
107
- <HTooltip :text="t('app.tabbar.closeOtherSide')">
142
+ <HTooltip text="关闭其它标签页">
108
143
  <EpClose />
109
144
  </HTooltip>
110
145
  </button>
111
146
  <button class="button" :disabled="!tabbar.checkCloseLeftSide()" @click="actionCommand('left-side')">
112
- <HTooltip :text="t('app.tabbar.closeLeftSide')">
147
+ <HTooltip text="关闭左侧标签页">
113
148
  <PhArrowLineLeft />
114
149
  </HTooltip>
115
150
  </button>
116
151
  <button class="button" :disabled="!tabbar.checkCloseRightSide()" @click="actionCommand('right-side')">
117
- <HTooltip :text="t('app.tabbar.closeRightSide')">
152
+ <HTooltip text="关闭右侧标签页">
118
153
  <PhArrowLineRight />
119
154
  </HTooltip>
120
155
  </button>
@@ -127,9 +162,27 @@ function iconName(isActive: boolean, icon: Tabbar.recordRaw['icon'], activeIcon:
127
162
  'no-drag': element.isPermanent || element.isPin,
128
163
  }"
129
164
  >
130
- <div :key="element.tabId" class="title" :title="element.customTitleList.find(item => item.fullPath === element.fullPath)?.title || generateI18nTitle(element.title)" @click="router.push(element.fullPath)">
131
- <PubinfoIcon v-if="settingsStore.settings.tabbar.enableIcon && iconName(element.tabId === activedTabId, element.icon, element.activeIcon)" :name="iconName(element.tabId === activedTabId, element.icon, element.activeIcon)!" />
132
- {{ element.customTitleList.find(item => item.fullPath === element.fullPath)?.title || generateI18nTitle(element.i18n, element.title) }}
165
+ <div :key="element.tabId" class="title" :title="element.customTitleList.find(item => item.fullPath === element.fullPath)?.title || generateTitle(element.title)" @click="router.push(element.fullPath)">
166
+ <template v-if="settingsStore.settings.tabbar.enableIcon && iconName(element.tabId === activedTabId, element.icon, element.activeIcon)">
167
+ <PubinfoIcon
168
+ v-if="resolveIconOptions(element)"
169
+ small
170
+ :name="iconName(element.tabId === activedTabId, element.icon, element.activeIcon)!"
171
+ :box="computeBoxType(resolveIconOptions(element)) as any"
172
+ :size="16"
173
+ :angle="resolveIconOptions(element)?.angle"
174
+ :background="resolveIconOptions(element)?.background"
175
+ :radius="resolveIconOptions(element)?.radius"
176
+ :color="(iconName(element.tabId === activedTabId, element.icon, element.activeIcon) || '').startsWith('antd:') ? (getSafeIconColor(resolveIconOptions(element)) || '#ffffff') : undefined"
177
+ />
178
+ <PubinfoIcon
179
+ v-else
180
+ :name="iconName(element.tabId === activedTabId, element.icon, element.activeIcon)!"
181
+ :size="16"
182
+ :color="(iconName(element.tabId === activedTabId, element.icon, element.activeIcon) || '').startsWith('antd:') ? getSafeIconColor(resolveIconOptions(element)) : undefined"
183
+ />
184
+ </template>
185
+ {{ element.customTitleList.find(item => item.fullPath === element.fullPath)?.title || generateTitle(element.title) }}
133
186
  </div>
134
187
  <div v-if="!element.isPermanent && element.isPin" class="action-icon" @click.stop="tabbarStore.unPin(element.tabId)">
135
188
  <RiPushpin2Fill />