Skip to content

Commit ac6de03

Browse files
committed
Merge branch 'fork/ming4762/timezone-20251020'
2 parents cfbce0d + f46ae02 commit ac6de03

File tree

24 files changed

+444
-5
lines changed

24 files changed

+444
-5
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { eventHandler } from 'h3';
2+
import { verifyAccessToken } from '~/utils/jwt-utils';
3+
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
4+
import { getTimezone } from '~/utils/timezone-utils';
5+
6+
export default eventHandler((event) => {
7+
const userinfo = verifyAccessToken(event);
8+
if (!userinfo) {
9+
return unAuthorizedResponse(event);
10+
}
11+
return useResponseSuccess(getTimezone());
12+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { eventHandler } from 'h3';
2+
import { TIME_ZONE_OPTIONS } from '~/utils/mock-data';
3+
import { useResponseSuccess } from '~/utils/response';
4+
5+
export default eventHandler(() => {
6+
const data = TIME_ZONE_OPTIONS.map((o) => ({
7+
label: `${o.timezone} (GMT${o.offset >= 0 ? `+${o.offset}` : o.offset})`,
8+
value: o.timezone,
9+
}));
10+
return useResponseSuccess(data);
11+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { eventHandler, readBody } from 'h3';
2+
import { verifyAccessToken } from '~/utils/jwt-utils';
3+
import { TIME_ZONE_OPTIONS } from '~/utils/mock-data';
4+
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
5+
import { setTimezone } from '~/utils/timezone-utils';
6+
7+
export default eventHandler(async (event) => {
8+
const userinfo = verifyAccessToken(event);
9+
if (!userinfo) {
10+
return unAuthorizedResponse(event);
11+
}
12+
const body = await readBody<{ timezone?: unknown }>(event);
13+
const timezone =
14+
typeof body?.timezone === 'string' ? body.timezone : undefined;
15+
const allowed = TIME_ZONE_OPTIONS.some((o) => o.timezone === timezone);
16+
if (!timezone || !allowed) {
17+
setResponseStatus(event, 400);
18+
return useResponseError('Bad Request', 'Invalid timezone');
19+
}
20+
setTimezone(timezone);
21+
return useResponseSuccess({});
22+
});

apps/backend-mock/utils/mock-data.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ export interface UserInfo {
77
homePath?: string;
88
}
99

10+
export interface TimezoneOption {
11+
offset: number;
12+
timezone: string;
13+
}
14+
1015
export const MOCK_USERS: UserInfo[] = [
1116
{
1217
id: 0,
@@ -388,3 +393,29 @@ export function getMenuIds(menus: any[]) {
388393
});
389394
return ids;
390395
}
396+
397+
/**
398+
* 时区选项
399+
*/
400+
export const TIME_ZONE_OPTIONS: TimezoneOption[] = [
401+
{
402+
offset: -5,
403+
timezone: 'America/New_York',
404+
},
405+
{
406+
offset: 0,
407+
timezone: 'Europe/London',
408+
},
409+
{
410+
offset: 8,
411+
timezone: 'Asia/Shanghai',
412+
},
413+
{
414+
offset: 9,
415+
timezone: 'Asia/Tokyo',
416+
},
417+
{
418+
offset: 9,
419+
timezone: 'Asia/Seoul',
420+
},
421+
];
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
let mockTimeZone: null | string = null;
2+
3+
export const setTimezone = (timeZone: string) => {
4+
mockTimeZone = timeZone;
5+
};
6+
7+
export const getTimezone = () => {
8+
return mockTimeZone;
9+
};

packages/@core/base/shared/src/utils/date.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import dayjs from 'dayjs';
2+
import timezone from 'dayjs/plugin/timezone';
3+
import utc from 'dayjs/plugin/utc';
4+
5+
dayjs.extend(utc);
6+
dayjs.extend(timezone);
27

38
export function formatDate(time: number | string, format = 'YYYY-MM-DD') {
49
try {
510
const date = dayjs(time);
611
if (!date.isValid()) {
712
throw new Error('Invalid date');
813
}
9-
return date.format(format);
14+
return date.tz().format(format);
1015
} catch (error) {
1116
console.error(`Error formatting date: ${error}`);
1217
return time;
@@ -24,3 +29,19 @@ export function isDate(value: any): value is Date {
2429
export function isDayjsObject(value: any): value is dayjs.Dayjs {
2530
return dayjs.isDayjs(value);
2631
}
32+
33+
/**
34+
* 设置默认时区
35+
* @param timezone
36+
*/
37+
export const setDefaultTimezone = (timezone?: string) => {
38+
timezone ? dayjs.tz.setDefault(timezone) : dayjs.tz.setDefault();
39+
};
40+
41+
/**
42+
* 获取当前时区
43+
* @returns 当前时区
44+
*/
45+
export const getTimezone = () => {
46+
return dayjs.tz.guess();
47+
};

packages/@core/base/typings/src/app.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ type PageTransitionType = 'fade' | 'fade-down' | 'fade-slide' | 'fade-up';
9393
*/
9494
type AuthPageLayoutType = 'panel-center' | 'panel-left' | 'panel-right';
9595

96+
/**
97+
* 时区选项
98+
*/
99+
interface TimezoneOption {
100+
label: string;
101+
offset: number;
102+
timezone: string;
103+
}
104+
96105
export type {
97106
AccessModeType,
98107
AuthPageLayoutType,
@@ -108,4 +117,5 @@ export type {
108117
PreferencesButtonPositionType,
109118
TabsStyleType,
110119
ThemeModeType,
120+
TimezoneOption,
111121
};

packages/@core/preferences/__tests__/__snapshots__/config.test.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ exports[`defaultPreferences immutability test > should not modify the config obj
133133
"refresh": true,
134134
"sidebarToggle": true,
135135
"themeToggle": true,
136+
"timezone": true,
136137
},
137138
}
138139
`;

packages/@core/preferences/src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ const defaultPreferences: Preferences = {
134134
refresh: true,
135135
sidebarToggle: true,
136136
themeToggle: true,
137+
timezone: true,
137138
},
138139
};
139140

packages/@core/preferences/src/constants.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { BuiltinThemeType } from '@vben-core/typings';
1+
import type { BuiltinThemeType, TimezoneOption } from '@vben-core/typings';
22

33
interface BuiltinThemePreset {
44
color: string;
@@ -81,8 +81,39 @@ const BUILT_IN_THEME_PRESETS: BuiltinThemePreset[] = [
8181
},
8282
];
8383

84+
/**
85+
* 时区选项
86+
*/
87+
const DEFAULT_TIME_ZONE_OPTIONS: TimezoneOption[] = [
88+
{
89+
offset: -5,
90+
timezone: 'America/New_York',
91+
label: 'America/New_York(GMT-5)',
92+
},
93+
{
94+
offset: 0,
95+
timezone: 'Europe/London',
96+
label: 'Europe/London(GMT0)',
97+
},
98+
{
99+
offset: 8,
100+
timezone: 'Asia/Shanghai',
101+
label: 'Asia/Shanghai(GMT+8)',
102+
},
103+
{
104+
offset: 9,
105+
timezone: 'Asia/Tokyo',
106+
label: 'Asia/Tokyo(GMT+9)',
107+
},
108+
{
109+
offset: 9,
110+
timezone: 'Asia/Seoul',
111+
label: 'Asia/Seoul(GMT+9)',
112+
},
113+
];
114+
84115
export const COLOR_PRESETS = [...BUILT_IN_THEME_PRESETS].slice(0, 7);
85116

86-
export { BUILT_IN_THEME_PRESETS };
117+
export { BUILT_IN_THEME_PRESETS, DEFAULT_TIME_ZONE_OPTIONS };
87118

88119
export type { BuiltinThemePreset };

0 commit comments

Comments
 (0)