generator-mico-cli 0.2.13 → 0.2.15

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 (99) hide show
  1. package/README.md +1 -1
  2. package/generators/micro-react/index.js +34 -10
  3. package/generators/micro-react/templates/.commitlintrc.js +1 -0
  4. package/generators/micro-react/templates/.cursor/rules/coding-conventions.mdc +1 -1
  5. package/generators/micro-react/templates/.cursor/rules/development-guide.mdc +1 -1
  6. package/generators/micro-react/templates/.cursor/rules/layout-app.mdc +2 -5
  7. package/generators/micro-react/templates/.cursor/rules/project-overview.mdc +2 -2
  8. package/generators/micro-react/templates/.cursor/rules/theme-system.mdc +10 -12
  9. package/generators/micro-react/templates/AGENTS.md +2 -2
  10. package/generators/micro-react/templates/CLAUDE.md +1 -2
  11. package/generators/micro-react/templates/README.md +2 -2
  12. package/generators/micro-react/templates/_npmrc +3 -0
  13. package/generators/micro-react/templates/apps/layout/config/config.dev.ts +15 -0
  14. package/generators/micro-react/templates/apps/layout/config/config.ts +4 -3
  15. package/generators/micro-react/templates/apps/layout/docs/common-intl.md +370 -0
  16. package/generators/micro-react/templates/apps/layout/docs/feature-404/351/241/265/351/235/242.md +2 -2
  17. package/generators/micro-react/templates/apps/layout/docs/feature-/344/270/273/351/242/230/350/211/262/345/210/207/346/215/242.md +21 -25
  18. package/generators/micro-react/templates/apps/layout/docs/feature-/345/276/256/345/211/215/347/253/257/346/250/241/345/274/217.md +15 -16
  19. package/generators/micro-react/templates/apps/layout/docs/feature-/350/217/234/345/215/225/346/235/203/351/231/220/346/216/247/345/210/266.md +1 -1
  20. package/generators/micro-react/templates/apps/layout/docs/utils-timezone.md +322 -0
  21. package/generators/micro-react/templates/apps/layout/mock/menus.ts +39 -1
  22. package/generators/micro-react/templates/apps/layout/package.json +5 -2
  23. package/generators/micro-react/templates/apps/layout/src/app.tsx +22 -10
  24. package/generators/micro-react/templates/apps/layout/src/common/auth/index.ts +3 -0
  25. package/generators/micro-react/templates/apps/layout/src/common/helpers.ts +177 -0
  26. package/generators/micro-react/templates/apps/layout/src/common/locale.ts +56 -4
  27. package/generators/micro-react/templates/apps/layout/src/common/menu/parser.ts +84 -5
  28. package/generators/micro-react/templates/apps/layout/src/common/menu/types.ts +13 -1
  29. package/generators/micro-react/templates/apps/layout/src/common/request/interceptors.ts +1 -1
  30. package/generators/micro-react/templates/apps/layout/src/common/request/sso.ts +7 -1
  31. package/generators/micro-react/templates/apps/layout/src/common/theme.ts +1 -1
  32. package/generators/micro-react/templates/apps/layout/src/common/upload/oss.ts +2 -3
  33. package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.less +8 -2
  34. package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.tsx +23 -6
  35. package/generators/micro-react/templates/apps/layout/src/components/HeaderDropdown/index.tsx +22 -0
  36. package/generators/micro-react/templates/apps/layout/src/components/IconFont/index.tsx +1 -1
  37. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +1 -1
  38. package/generators/micro-react/templates/apps/layout/src/components/RightContent/AvatarDropdown.tsx +388 -0
  39. package/generators/micro-react/templates/apps/layout/src/components/RightContent/avatar-dropdown.less +35 -0
  40. package/generators/micro-react/templates/apps/layout/src/components/RightContent/index.ts +2 -0
  41. package/generators/micro-react/templates/apps/layout/src/constants/index.ts +2 -0
  42. package/generators/micro-react/templates/apps/layout/src/global.less +3 -6
  43. package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.less +3 -1
  44. package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.tsx +8 -53
  45. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +3 -1
  46. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +4 -4
  47. package/generators/micro-react/templates/apps/layout/src/layouts/index.less +83 -13
  48. package/generators/micro-react/templates/apps/layout/src/layouts/index.tsx +40 -25
  49. package/generators/micro-react/templates/apps/layout/src/locales/en-US.ts +9 -0
  50. package/generators/micro-react/templates/apps/layout/src/locales/zh-CN.ts +9 -0
  51. package/generators/micro-react/templates/apps/layout/src/pages/403/index.tsx +2 -1
  52. package/generators/micro-react/templates/apps/layout/src/pages/404/index.tsx +1 -1
  53. package/generators/micro-react/templates/apps/layout/src/pages/Home/index.less +3 -0
  54. package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.less +1 -1
  55. package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.tsx +3 -3
  56. package/generators/micro-react/templates/apps/layout/src/requestErrorConfig.ts +1 -1
  57. package/generators/micro-react/templates/apps/layout/src/services/config/index.ts +63 -0
  58. package/generators/micro-react/templates/apps/layout/src/services/config/type.ts +32 -0
  59. package/generators/micro-react/templates/apps/layout/src/services/user.ts +23 -1
  60. package/generators/micro-react/templates/package.json +4 -1
  61. package/generators/micro-react/templates/packages/common-intl/.turbo/turbo-build.log +13 -0
  62. package/generators/micro-react/templates/packages/common-intl/README.md +427 -0
  63. package/generators/micro-react/templates/packages/common-intl/dist/index.d.ts +3 -0
  64. package/generators/micro-react/templates/packages/common-intl/dist/index.js +4388 -0
  65. package/generators/micro-react/templates/packages/common-intl/dist/indexedDBUtils.d.ts +13 -0
  66. package/generators/micro-react/templates/packages/common-intl/dist/intl.d.ts +1022 -0
  67. package/generators/micro-react/templates/packages/common-intl/dist/utils.d.ts +122 -0
  68. package/generators/micro-react/templates/packages/common-intl/package.json +34 -0
  69. package/generators/micro-react/templates/packages/common-intl/src/index.ts +7 -0
  70. package/generators/micro-react/templates/packages/common-intl/src/indexedDBUtils.ts +51 -0
  71. package/generators/micro-react/templates/packages/common-intl/src/intl.ts +5709 -0
  72. package/generators/micro-react/templates/packages/common-intl/src/utils.ts +481 -0
  73. package/generators/micro-react/templates/packages/common-intl/tsconfig.json +22 -0
  74. package/generators/micro-react/templates/packages/common-intl/vite.config.ts +25 -0
  75. package/generators/micro-react/templates/turbo.json +3 -0
  76. package/generators/subapp-react/index.js +13 -18
  77. package/generators/subapp-react/templates/homepage/README.md +3 -3
  78. package/generators/subapp-react/templates/homepage/config/config.dev.ts +8 -7
  79. package/generators/subapp-react/templates/homepage/config/config.prod.development.ts +2 -3
  80. package/generators/subapp-react/templates/homepage/config/config.prod.testing.ts +2 -3
  81. package/generators/subapp-react/templates/homepage/config/config.prod.ts +4 -5
  82. package/generators/subapp-react/templates/homepage/package.json +3 -2
  83. package/generators/subapp-react/templates/homepage/src/global.less +3 -3
  84. package/generators/subapp-react/templates/homepage/src/pages/index.less +2 -2
  85. package/generators/subapp-react/templates/homepage/src/pages/index.tsx +72 -33
  86. package/generators/subapp-react/templates/homepage/src/styles/theme.less +1 -1
  87. package/lib/utils.js +43 -0
  88. package/package.json +8 -11
  89. package/generators/micro-react/templates/packages/shared-styles/README.md +0 -124
  90. package/generators/micro-react/templates/packages/shared-styles/arco-design-mobile-override.less +0 -91
  91. package/generators/micro-react/templates/packages/shared-styles/arco-override.less +0 -119
  92. package/generators/micro-react/templates/packages/shared-styles/index.d.ts +0 -44
  93. package/generators/micro-react/templates/packages/shared-styles/index.less +0 -13
  94. package/generators/micro-react/templates/packages/shared-styles/package.json +0 -30
  95. package/generators/micro-react/templates/packages/shared-styles/theme-inject.less +0 -10
  96. package/generators/micro-react/templates/packages/shared-styles/themes/dark/custom-var.less +0 -290
  97. package/generators/micro-react/templates/packages/shared-styles/themes/normal/custom-var.less +0 -269
  98. package/generators/micro-react/templates/packages/shared-styles/variables-only.less +0 -433
  99. package/generators/micro-react/templates/packages/shared-styles/variables.less +0 -452
@@ -0,0 +1,388 @@
1
+ import { logout, STORAGE_KEYS } from '@/common/auth';
2
+ import {
3
+ getCurrentTimezone,
4
+ getTimezoneRegion,
5
+ setTimezoneRegion as setTimezoneRegionToStorage,
6
+ setTimezone as setTimezoneToStorage,
7
+ utcOffsetToTimezone,
8
+ } from '@/common/helpers';
9
+ import {
10
+ getCurrentLocale,
11
+ LOCALE,
12
+ setLocaleToStorage,
13
+ type TLocale,
14
+ } from '<%= packageScope %>/common-intl';
15
+ import IconFont from '@/components/IconFont';
16
+ import { useTheme } from '@/hooks/useTheme';
17
+ import { getTimezoneList, type ITimezone } from '@/services/config';
18
+ import { Avatar, Menu } from '@mico-platform/ui';
19
+ import { history, useIntl, useModel } from '@umijs/max';
20
+ import React, { useEffect, useState, useTransition } from 'react';
21
+ import { flushSync } from 'react-dom';
22
+ import HeaderDropdown from '../HeaderDropdown';
23
+ import './avatar-dropdown.less';
24
+
25
+ const MenuItem = Menu.Item;
26
+ const SubMenu = Menu.SubMenu;
27
+
28
+ export type GlobalHeaderRightProps = {
29
+ menu?: boolean;
30
+ children?: React.ReactNode;
31
+ };
32
+
33
+ // 菜单项类型定义
34
+ interface IMenuItem {
35
+ key: string;
36
+ label: string;
37
+ icon?: React.ReactNode;
38
+ path?: string;
39
+ children?: IMenuItem[];
40
+ }
41
+
42
+ const DEFAULT_AVATAR =
43
+ 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png';
44
+
45
+ // TODO: 临时假数据,后续接入真实登录态
46
+ const MOCK_USER = {
47
+ user_name: 'Test User',
48
+ avatar: DEFAULT_AVATAR,
49
+ };
50
+
51
+ export const AvatarName: React.FC<{ userName?: string }> = ({ userName }) => {
52
+ return <span className="ml-2 mr-2">{userName}</span>;
53
+ };
54
+
55
+ const languageLabelMap: Record<string, string> = {
56
+ [LOCALE.ZH_CN]: '中文',
57
+ [LOCALE.EN_US]: 'English',
58
+ };
59
+
60
+ export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
61
+ const { setInitialState, initialState } = useModel('@@initialState');
62
+ const { formatMessage } = useIntl();
63
+ // TODO: 临时使用假数据,后续接入真实登录态
64
+ const currentUser = initialState?.currentUser || MOCK_USER;
65
+ const { theme, setTheme } = useTheme();
66
+ const [timezoneLoading, startTransition] = useTransition();
67
+
68
+ // 时区相关状态
69
+ const [timezoneList, setTimezoneList] = useState<ITimezone[]>([]);
70
+ const [currentTimezone, setCurrentTimezone] = useState<string>(
71
+ getCurrentTimezone(),
72
+ );
73
+
74
+ // 获取当前时区的显示名称
75
+ const getCurrentTimezoneLabel = (): string => {
76
+ const offsetNum = Number(
77
+ currentTimezone.replace('UTC', '').replace('+', ''),
78
+ );
79
+ const currentRegion = getTimezoneRegion();
80
+
81
+ // 从 timezoneList 中找到匹配的时区(同时匹配 region 和 utc_offset)
82
+ const matchedTimezone = timezoneList.find(
83
+ (tz) => tz.utc_offset === offsetNum && tz.region === currentRegion,
84
+ );
85
+
86
+ if (matchedTimezone) {
87
+ return `${matchedTimezone.region} (${utcOffsetToTimezone(matchedTimezone.utc_offset)})`;
88
+ }
89
+
90
+ // 回退:只匹配 utc_offset
91
+ const fallbackTimezone = timezoneList.find(
92
+ (tz) => tz.utc_offset === offsetNum,
93
+ );
94
+ if (fallbackTimezone) {
95
+ return `${fallbackTimezone.region} (${utcOffsetToTimezone(fallbackTimezone.utc_offset)})`;
96
+ }
97
+
98
+ return utcOffsetToTimezone(offsetNum);
99
+ };
100
+
101
+ // 管理头像 URL
102
+ const [avatarSrc, setAvatarSrc] = useState<string>(
103
+ currentUser?.avatar || DEFAULT_AVATAR,
104
+ );
105
+
106
+ useEffect(() => {
107
+ setAvatarSrc(currentUser?.avatar || DEFAULT_AVATAR);
108
+ }, [currentUser?.avatar]);
109
+
110
+ // 加载时区列表
111
+ useEffect(() => {
112
+ const loadTimezoneList = async () => {
113
+ try {
114
+ const response = await getTimezoneList();
115
+ if (response?.timezone_list) {
116
+ setTimezoneList(response.timezone_list);
117
+ }
118
+ } catch (error) {
119
+ console.error('加载时区列表失败:', error);
120
+ }
121
+ };
122
+
123
+ startTransition(loadTimezoneList as any);
124
+ }, []);
125
+
126
+ // 监听 localStorage 中时区的变化
127
+ useEffect(() => {
128
+ const handleStorageChange = (e: StorageEvent) => {
129
+ if (e.key === STORAGE_KEYS.TIMEZONE && e.newValue) {
130
+ const offsetNum = Number(e.newValue);
131
+ if (!Number.isNaN(offsetNum) && e.newValue.trim() !== '') {
132
+ setCurrentTimezone(utcOffsetToTimezone(offsetNum));
133
+ } else {
134
+ setCurrentTimezone(e.newValue);
135
+ }
136
+ }
137
+ };
138
+
139
+ window.addEventListener('storage', handleStorageChange);
140
+ return () => {
141
+ window.removeEventListener('storage', handleStorageChange);
142
+ };
143
+ }, []);
144
+
145
+ const handleAvatarError = () => {
146
+ setAvatarSrc(DEFAULT_AVATAR);
147
+ };
148
+
149
+ const loginOut = async () => {
150
+ logout();
151
+ const { search, pathname } = window.location;
152
+ const urlParams = new URL(window.location.href).searchParams;
153
+ const searchParams = new URLSearchParams({
154
+ redirect: pathname + search,
155
+ });
156
+ const redirect = urlParams.get('redirect');
157
+ if (window.location.pathname !== '/user/login' && !redirect) {
158
+ history.replace({
159
+ pathname: '/user/login',
160
+ search: searchParams.toString(),
161
+ });
162
+ }
163
+ };
164
+
165
+ const onMenuClick = (key: string, path?: string) => {
166
+ if (key === 'logout') {
167
+ flushSync(() => {
168
+ setInitialState((s) => ({ ...s, currentUser: undefined }));
169
+ });
170
+ loginOut();
171
+ return;
172
+ }
173
+
174
+ // 处理语言切换
175
+ if (key.startsWith('language-')) {
176
+ const newLocale = key.replace('language-', '') as TLocale;
177
+ const currentLocale = getCurrentLocale();
178
+ if (newLocale === currentLocale) {
179
+ return;
180
+ }
181
+ // 存储 common-intl 格式的语言标识符,刷新后 umi 会通过映射转换
182
+ setLocaleToStorage(newLocale);
183
+ window.location.reload();
184
+ return;
185
+ }
186
+
187
+ // 处理时区切换
188
+ if (key.includes('/')) {
189
+ const lastSlashIndex = key.lastIndexOf('/');
190
+ const region = key.substring(0, lastSlashIndex);
191
+ const utcOffsetStr = key.substring(lastSlashIndex + 1);
192
+ const utcOffsetNum = Number(utcOffsetStr);
193
+ const timezoneStr = utcOffsetToTimezone(utcOffsetNum);
194
+ const currentRegion = getTimezoneRegion();
195
+
196
+ if (timezoneStr === currentTimezone && region === currentRegion) {
197
+ return;
198
+ }
199
+
200
+ setTimezoneToStorage(utcOffsetStr);
201
+ setTimezoneRegionToStorage(region);
202
+ setCurrentTimezone(timezoneStr);
203
+ window.location.reload();
204
+ return;
205
+ }
206
+
207
+ // 处理主题切换
208
+ if (key.startsWith('theme-')) {
209
+ const themeMode = key.replace('theme-', '') as 'light' | 'dark';
210
+ // 如果切换的主题和当前主题一致,则无需切换
211
+ if (themeMode === theme) {
212
+ return;
213
+ }
214
+ // 切换主题
215
+ setTheme(themeMode);
216
+ return;
217
+ }
218
+
219
+ if (path) {
220
+ history.push(path);
221
+ } else {
222
+ history.push(`/account/${key}`);
223
+ }
224
+ };
225
+
226
+ // TODO: 临时关闭加载逻辑,使用假数据
227
+ // const loading = <Spin size={16} className="ml-2 mr-2" />;
228
+ // if (!initialState) {
229
+ // return loading;
230
+ // }
231
+ // if (!currentUser || !currentUser.user_name) {
232
+ // return loading;
233
+ // }
234
+
235
+ // 菜单配置
236
+ const menuItems: IMenuItem[] = [
237
+ ...(menu
238
+ ? [
239
+ {
240
+ key: 'language',
241
+ label: formatMessage({ id: 'avatar.language' }),
242
+ children: [
243
+ {
244
+ key: `language-${LOCALE.ZH_CN}`,
245
+ label: formatMessage({ id: 'avatar.language.zh_CN' }),
246
+ },
247
+ {
248
+ key: `language-${LOCALE.EN_US}`,
249
+ label: formatMessage({ id: 'avatar.language.en' }),
250
+ },
251
+ ],
252
+ },
253
+ {
254
+ key: 'timezone',
255
+ label: getCurrentTimezoneLabel(),
256
+ children:
257
+ timezoneLoading || timezoneList.length === 0
258
+ ? []
259
+ : timezoneList.map((tz) => ({
260
+ key: `${tz.region}/${tz.utc_offset}`,
261
+ label: `${tz.region} (${utcOffsetToTimezone(tz.utc_offset)})`,
262
+ })),
263
+ },
264
+ {
265
+ key: 'theme',
266
+ label: formatMessage({ id: 'avatar.theme' }),
267
+ children: [
268
+ {
269
+ key: 'theme-light',
270
+ label: formatMessage({ id: 'avatar.theme.light' }),
271
+ },
272
+ {
273
+ key: 'theme-dark',
274
+ label: formatMessage({ id: 'avatar.theme.dark' }),
275
+ },
276
+ ],
277
+ },
278
+ ]
279
+ : []),
280
+ {
281
+ key: 'logout',
282
+ label: formatMessage({ id: 'avatar.logout' }),
283
+ },
284
+ ];
285
+
286
+ // 递归渲染菜单项
287
+ const renderMenuItems = (items: IMenuItem[]): React.ReactNode[] => {
288
+ return items.map((item) => {
289
+ if (item.children && item.children.length > 0) {
290
+ const subMenuTitle = (
291
+ <>
292
+ {item.icon && <span className="mr-2">{item.icon}</span>}
293
+ <span>{item.label}</span>
294
+ </>
295
+ );
296
+ return (
297
+ <SubMenu key={item.key} title={subMenuTitle}>
298
+ {renderMenuItems(item.children)}
299
+ </SubMenu>
300
+ );
301
+ }
302
+
303
+ let displayLabel: string | React.ReactNode = item.label;
304
+
305
+ // 否则渲染为普通菜单项
306
+ // 检查是否是主题菜单项,如果是则显示当前使用状态
307
+ if (item.key.startsWith('theme-')) {
308
+ const themeMode = item.key.replace('theme-', '') as 'light' | 'dark';
309
+ if (themeMode === theme) {
310
+ displayLabel = <span className="selected-label">{item.label}</span>;
311
+ }
312
+ }
313
+
314
+ // 语言菜单项选中状态
315
+ if (item.key.startsWith('language-')) {
316
+ const locale = item.key.replace('language-', '') as TLocale;
317
+ const currentLocale = getCurrentLocale();
318
+ if (locale === currentLocale) {
319
+ displayLabel = (
320
+ <>
321
+ <span className="selected-label">
322
+ {languageLabelMap[locale] || ''}
323
+ </span>{' '}
324
+ - <span className="label-name">{item.label}</span>
325
+ </>
326
+ );
327
+ } else {
328
+ displayLabel = (
329
+ <>
330
+ <span>{languageLabelMap[locale] || ''}</span> -{' '}
331
+ <span className="label-name">{item.label}</span>
332
+ </>
333
+ );
334
+ }
335
+ }
336
+
337
+ // 时区菜单项选中状态
338
+ if (item.key.includes('/')) {
339
+ const lastSlashIndex = item.key.lastIndexOf('/');
340
+ const region = item.key.substring(0, lastSlashIndex);
341
+ const utcOffsetStr = item.key.substring(lastSlashIndex + 1);
342
+ const utcOffsetNum = Number(utcOffsetStr);
343
+ const timezoneStr = utcOffsetToTimezone(utcOffsetNum);
344
+ const currentRegion = getTimezoneRegion();
345
+
346
+ if (timezoneStr === currentTimezone && region === currentRegion) {
347
+ displayLabel = <span className="selected-label">{item.label}</span>;
348
+ }
349
+ }
350
+
351
+ return (
352
+ <MenuItem
353
+ key={item.key}
354
+ onClick={() => onMenuClick(item.key, item.path)}
355
+ >
356
+ {item.icon && <span className="mr-2">{item.icon}</span>}
357
+ <span>{displayLabel}</span>
358
+ </MenuItem>
359
+ );
360
+ });
361
+ };
362
+
363
+ return (
364
+ <HeaderDropdown
365
+ position="br"
366
+ triggerProps={{ popupAlign: { bottom: [0, 20] } }}
367
+ droplist={
368
+ <Menu className="avatar-dropdown-menu">
369
+ {renderMenuItems(menuItems)}
370
+ </Menu>
371
+ }
372
+ >
373
+ <div className="flex items-center avatar-dropdown-trigger">
374
+ <div className="flex items-center">
375
+ <Avatar size={24} shape="circle">
376
+ <img src={avatarSrc} alt="avatar" onError={handleAvatarError} />
377
+ </Avatar>
378
+ </div>
379
+ <AvatarName userName={currentUser?.user_name} />
380
+ <IconFont
381
+ type="webcs-outline_down1"
382
+ className="avatar-dropdown-icon"
383
+ fontSize={12}
384
+ />
385
+ </div>
386
+ </HeaderDropdown>
387
+ );
388
+ };
@@ -0,0 +1,35 @@
1
+ @import '@mico-platform/theme/variables';
2
+
3
+ .avatar-dropdown-trigger {
4
+ background-color: @color-fill-2;
5
+ border-radius: @border-radius-button;
6
+ height: 32px;
7
+ padding: 1px 10px;
8
+ color: @color-text-1;
9
+ cursor: pointer;
10
+ }
11
+
12
+ .avatar-dropdown-trigger:hover {
13
+ background: @color-fill-3;
14
+ }
15
+
16
+ .avatar-dropdown-trigger.arco-dropdown-popup-visible .arco-icon-down {
17
+ transform: rotate(180deg);
18
+ }
19
+
20
+ .avatar-dropdown-menu.arco-dropdown-menu {
21
+ width: 154px;
22
+ }
23
+
24
+ .avatar-dropdown-icon {
25
+ margin-left: 4px;
26
+ transition: transform 0.2s;
27
+ }
28
+
29
+ .selected-label {
30
+ color: @Brand1-6;
31
+ }
32
+
33
+ .label-name {
34
+ color: @color-text-3;
35
+ }
@@ -0,0 +1,2 @@
1
+ export { AvatarDropdown, AvatarName } from './AvatarDropdown';
2
+ export type { GlobalHeaderRightProps } from './AvatarDropdown';
@@ -169,6 +169,8 @@ export const STORAGE_KEYS = {
169
169
  APP_INFO: 'appInfo',
170
170
  IS_SUPERUSER: 'is_superuser',
171
171
  GROUPS: 'groups',
172
+ TIMEZONE: 'mico-cs-timezone',
173
+ TIMEZONE_REGION: 'mico-cs-timezone-region',
172
174
  } as const;
173
175
 
174
176
  /**
@@ -1,10 +1,7 @@
1
- // ==================== 全局样式 ====================
2
- // 先导入 Arco Design CSS(确保它在项目样式之前)
3
- @import (css) '~@arco-design/web-react/dist/css/arco.css';
4
1
 
5
- // 再导入共享主题变量(CSS Variables + Less Variables)
6
- // 这样项目的变量定义会在 Arco 之后,可以正确覆盖
7
- @import '<%= packageScope %>/shared-styles';
2
+ // 再导入 @mico-platform/theme 主题变量(CSS Variables + Less Variables)
3
+ // 这样项目的变量定义会在 UI 库之后,可以正确覆盖
4
+ @import '@mico-platform/theme';
8
5
 
9
6
  * {
10
7
  box-sizing: border-box;
@@ -1,4 +1,4 @@
1
- @import '<%= packageScope %>/shared-styles/variables-only';
1
+ @import '@mico-platform/theme/variables';
2
2
 
3
3
  // Common mixins
4
4
  .header-gray-btn-mixin() {
@@ -22,6 +22,8 @@
22
22
  z-index: @header-z-index;
23
23
  height: @header-height;
24
24
  line-height: @header-height;
25
+ position: fixed;
26
+ width: 100vw;
25
27
  padding: 0 @spacing-lg;
26
28
  display: flex;
27
29
  align-items: center;
@@ -1,58 +1,12 @@
1
- import { useTheme } from '@/hooks/useTheme';
2
- import { logout } from '@/common/auth';
1
+ import { AvatarDropdown } from '@/components/RightContent';
3
2
  import { DEFAULT_NAME } from '@/constants';
4
- import { ROUTES } from '@/constants';
5
- import {
6
- Avatar,
7
- Divider,
8
- Dropdown,
9
- Layout,
10
- Menu,
11
- Space,
12
- } from '@arco-design/web-react';
13
- import {
14
- IconMoonFill,
15
- IconPoweroff,
16
- IconSettings,
17
- IconSunFill,
18
- } from '@arco-design/web-react/icon';
19
- import { useModel } from '@umijs/max';
20
- import React, { useCallback } from 'react';
3
+ import { Layout, Space } from '@mico-platform/ui';
4
+ import React from 'react';
21
5
  import './index.less';
22
6
 
23
7
  const Header = Layout.Header;
24
8
 
25
9
  const LayoutHeader: React.FC = () => {
26
- const { initialState } = useModel('@@initialState');
27
- const { theme, toggleTheme } = useTheme();
28
-
29
- const handleMenuClick = useCallback((key: string) => {
30
- if (key === 'logout') {
31
- // 清除本地存储的认证信息
32
- logout();
33
- // 跳转到登录页
34
- window.location.href = ROUTES.LOGIN;
35
- return;
36
- } else if (key === 'settings') {
37
- // TODO: Navigate to settings page
38
- console.log('settings');
39
- }
40
- }, []);
41
-
42
- const droplist = (
43
- <Menu onClickMenuItem={handleMenuClick}>
44
- <Menu.Item key="settings">
45
- <IconSettings style={{ marginRight: 8 }} />
46
- 设置
47
- </Menu.Item>
48
- <Divider style={{ margin: '4px 0' }} />
49
- <Menu.Item key="logout">
50
- <IconPoweroff style={{ marginRight: 8 }} />
51
- 退出登录
52
- </Menu.Item>
53
- </Menu>
54
- );
55
-
56
10
  return (
57
11
  <Header className="layout-header">
58
12
  {/* Logo */}
@@ -66,18 +20,18 @@ const LayoutHeader: React.FC = () => {
66
20
  <div className="layout-header-right">
67
21
  <Space size="medium">
68
22
  {/* Theme toggle */}
69
- <div
23
+ {/* <div
70
24
  className="layout-header-action"
71
25
  onClick={toggleTheme}
72
26
  title={theme === 'dark' ? '切换到亮色模式' : '切换到暗色模式'}
73
27
  >
74
28
  {theme === 'dark' ? <IconSunFill /> : <IconMoonFill />}
75
- </div>
29
+ </div> */}
76
30
 
77
31
  <span className="split-line" />
78
32
 
79
33
  {/* User info */}
80
- <Dropdown droplist={droplist} position="br" trigger="click">
34
+ {/* <Dropdown droplist={droplist} position="br" trigger="click">
81
35
  <div className="layout-header-user">
82
36
  {initialState?.currentUser?.avatar && (
83
37
  <Avatar size={32} style={{ marginRight: 8 }}>
@@ -91,7 +45,8 @@ const LayoutHeader: React.FC = () => {
91
45
  initialState?.currentUser?.email}
92
46
  </span>
93
47
  </div>
94
- </Dropdown>
48
+ </Dropdown> */}
49
+ <AvatarDropdown menu />
95
50
  </Space>
96
51
  </div>
97
52
  </Header>
@@ -1,4 +1,4 @@
1
- @import '<%= packageScope %>/shared-styles/variables-only';
1
+ @import '@mico-platform/theme/variables';
2
2
 
3
3
  .arco-layout-sider-collapsed {
4
4
  .layout-menu {
@@ -135,6 +135,8 @@
135
135
  // Sider styles
136
136
  .<%= projectName %>-sider {
137
137
  box-shadow: none;
138
+ position: fixed !important;
139
+ height: calc(100vh - 56px) !important;
138
140
 
139
141
  .arco-layout-sider-trigger {
140
142
  display: flex;
@@ -4,8 +4,8 @@ import { isAuthDisabled, isNoPermissionRoute } from '@/constants';
4
4
  import IconFont from '@/components/IconFont';
5
5
  import { useMenuState } from '@/hooks/useMenuState';
6
6
  import { useTheme } from '@/hooks/useTheme';
7
- import { Layout, Menu } from '@arco-design/web-react';
8
- import * as Icons from '@arco-design/web-react/icon';
7
+ import { Layout, Menu } from '@mico-platform/ui';
8
+ import * as Icons from '@mico-platform/ui/icon';
9
9
  import { useLocation, useModel } from '@umijs/max';
10
10
  import React, { useEffect, useMemo, useRef } from 'react';
11
11
  import './index.less';
@@ -15,8 +15,8 @@ const SubMenu = Menu.SubMenu;
15
15
  const Sider = Layout.Sider;
16
16
 
17
17
  /**
18
- * 图标名称到 Arco Icon 组件的映射
19
- * 用于处理自定义图标名称与 Arco 图标名称的差异
18
+ * 图标名称到 @mico-platform/ui Icon 组件的映射
19
+ * 用于处理自定义图标名称与 UI 图标名称的差异
20
20
  */
21
21
  const ICON_ALIAS_MAP: Record<string, keyof typeof Icons> = {
22
22
  Package: 'IconApps',