Skip to content

Commit 565be77

Browse files
committed
fix: resolve the issue of logout failure caused by the timezone store
1 parent ac6de03 commit 565be77

File tree

3 files changed

+180
-15
lines changed

3 files changed

+180
-15
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import dayjs from 'dayjs';
2+
import timezone from 'dayjs/plugin/timezone';
3+
import utc from 'dayjs/plugin/utc';
4+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5+
6+
import {
7+
formatDate,
8+
formatDateTime,
9+
getCurrentTimezone,
10+
getSystemTimezone,
11+
isDate,
12+
isDayjsObject,
13+
setCurrentTimezone,
14+
} from '../date';
15+
16+
dayjs.extend(utc);
17+
dayjs.extend(timezone);
18+
19+
describe('dateUtils', () => {
20+
const sampleISO = '2024-10-30T12:34:56Z';
21+
const sampleTimestamp = Date.parse(sampleISO);
22+
23+
beforeEach(() => {
24+
// 重置时区
25+
dayjs.tz.setDefault();
26+
setCurrentTimezone(); // 重置为系统默认
27+
});
28+
29+
afterEach(() => {
30+
vi.restoreAllMocks();
31+
});
32+
33+
// ===============================
34+
// formatDate
35+
// ===============================
36+
describe('formatDate', () => {
37+
it('should format a valid ISO date string', () => {
38+
const formatted = formatDate(sampleISO, 'YYYY/MM/DD');
39+
expect(formatted).toMatch(/2024\/10\/30/);
40+
});
41+
42+
it('should format a timestamp correctly', () => {
43+
const formatted = formatDate(sampleTimestamp);
44+
expect(formatted).toMatch(/2024-10-30/);
45+
});
46+
47+
it('should format a Date object', () => {
48+
const formatted = formatDate(new Date(sampleISO));
49+
expect(formatted).toMatch(/2024-10-30/);
50+
});
51+
52+
it('should format a dayjs object', () => {
53+
const formatted = formatDate(dayjs(sampleISO));
54+
expect(formatted).toMatch(/2024-10-30/);
55+
});
56+
57+
it('should return original input if date is invalid', () => {
58+
const invalid = 'not-a-date';
59+
const spy = vi.spyOn(console, 'error').mockImplementation(() => {});
60+
const formatted = formatDate(invalid);
61+
expect(formatted).toBe(invalid);
62+
expect(spy).toHaveBeenCalledOnce();
63+
});
64+
65+
it('should apply given format', () => {
66+
const formatted = formatDate(sampleISO, 'YYYY-MM-DD HH:mm');
67+
expect(formatted).toMatch(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}/);
68+
});
69+
});
70+
71+
// ===============================
72+
// formatDateTime
73+
// ===============================
74+
describe('formatDateTime', () => {
75+
it('should format date into full datetime', () => {
76+
const result = formatDateTime(sampleISO);
77+
expect(result).toMatch(/2024-10-30 \d{2}:\d{2}:\d{2}/);
78+
});
79+
});
80+
81+
// ===============================
82+
// isDate
83+
// ===============================
84+
describe('isDate', () => {
85+
it('should return true for Date instances', () => {
86+
expect(isDate(new Date())).toBe(true);
87+
});
88+
89+
it('should return false for non-Date values', () => {
90+
expect(isDate('2024-10-30')).toBe(false);
91+
expect(isDate(null)).toBe(false);
92+
expect(isDate(undefined)).toBe(false);
93+
});
94+
});
95+
96+
// ===============================
97+
// isDayjsObject
98+
// ===============================
99+
describe('isDayjsObject', () => {
100+
it('should return true for dayjs objects', () => {
101+
expect(isDayjsObject(dayjs())).toBe(true);
102+
});
103+
104+
it('should return false for other values', () => {
105+
expect(isDayjsObject(new Date())).toBe(false);
106+
expect(isDayjsObject('string')).toBe(false);
107+
});
108+
});
109+
110+
// ===============================
111+
// getSystemTimezone
112+
// ===============================
113+
describe('getSystemTimezone', () => {
114+
it('should return a valid IANA timezone string', () => {
115+
const tz = getSystemTimezone();
116+
expect(typeof tz).toBe('string');
117+
expect(tz).toMatch(/^[A-Z]+\/[A-Z_]+/i);
118+
});
119+
});
120+
121+
// ===============================
122+
// setCurrentTimezone / getCurrentTimezone
123+
// ===============================
124+
describe('setCurrentTimezone & getCurrentTimezone', () => {
125+
it('should set and retrieve the current timezone', () => {
126+
setCurrentTimezone('Asia/Shanghai');
127+
expect(getCurrentTimezone()).toBe('Asia/Shanghai');
128+
});
129+
130+
it('should reset to system timezone when called with no args', () => {
131+
const guessed = getSystemTimezone();
132+
setCurrentTimezone();
133+
expect(getCurrentTimezone()).toBe(guessed);
134+
});
135+
136+
it('should update dayjs default timezone', () => {
137+
setCurrentTimezone('America/New_York');
138+
const d = dayjs('2024-01-01T00:00:00Z');
139+
// 校验时区转换生效(小时变化)
140+
expect(d.tz().format('HH')).not.toBe('00');
141+
});
142+
});
143+
});

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

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import utc from 'dayjs/plugin/utc';
55
dayjs.extend(utc);
66
dayjs.extend(timezone);
77

8-
export function formatDate(time: number | string, format = 'YYYY-MM-DD') {
8+
type FormatDate = Date | dayjs.Dayjs | number | string;
9+
10+
export function formatDate(time: FormatDate, format = 'YYYY-MM-DD') {
911
try {
10-
const date = dayjs(time);
12+
const date = dayjs.isDayjs(time) ? time : dayjs(time);
1113
if (!date.isValid()) {
1214
throw new Error('Invalid date');
1315
}
@@ -18,7 +20,7 @@ export function formatDate(time: number | string, format = 'YYYY-MM-DD') {
1820
}
1921
}
2022

21-
export function formatDateTime(time: number | string) {
23+
export function formatDateTime(time: FormatDate) {
2224
return formatDate(time, 'YYYY-MM-DD HH:mm:ss');
2325
}
2426

@@ -30,18 +32,32 @@ export function isDayjsObject(value: any): value is dayjs.Dayjs {
3032
return dayjs.isDayjs(value);
3133
}
3234

35+
/**
36+
* 获取当前时区
37+
* @returns 当前时区
38+
*/
39+
export const getSystemTimezone = () => {
40+
return dayjs.tz.guess();
41+
};
42+
43+
/**
44+
* 自定义设置的时区
45+
*/
46+
let currentTimezone = getSystemTimezone();
47+
3348
/**
3449
* 设置默认时区
3550
* @param timezone
3651
*/
37-
export const setDefaultTimezone = (timezone?: string) => {
38-
timezone ? dayjs.tz.setDefault(timezone) : dayjs.tz.setDefault();
52+
export const setCurrentTimezone = (timezone?: string) => {
53+
currentTimezone = timezone || getSystemTimezone();
54+
dayjs.tz.setDefault(currentTimezone);
3955
};
4056

4157
/**
42-
* 获取当前时区
43-
* @returns 当前时区
58+
* 获取设置的时区
59+
* @returns 设置的时区
4460
*/
45-
export const getTimezone = () => {
46-
return dayjs.tz.guess();
61+
export const getCurrentTimezone = () => {
62+
return currentTimezone;
4763
};

packages/stores/src/modules/timezone.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { ref, unref } from 'vue';
22

33
import { DEFAULT_TIME_ZONE_OPTIONS } from '@vben-core/preferences';
4-
import { getTimezone, setDefaultTimezone } from '@vben-core/shared/utils';
4+
import {
5+
getCurrentTimezone,
6+
setCurrentTimezone,
7+
} from '@vben-core/shared/utils';
58

69
import { acceptHMRUpdate, defineStore } from 'pinia';
710

@@ -59,9 +62,7 @@ const getTimezoneHandler = () => {
5962
const useTimezoneStore = defineStore(
6063
'core-timezone',
6164
() => {
62-
const timezoneRef = ref(
63-
getTimezone() || new Intl.DateTimeFormat().resolvedOptions().timeZone,
64-
);
65+
const timezoneRef = ref(getCurrentTimezone());
6566

6667
/**
6768
* 初始化时区
@@ -74,7 +75,7 @@ const useTimezoneStore = defineStore(
7475
timezoneRef.value = timezone;
7576
}
7677
// 设置dayjs默认时区
77-
setDefaultTimezone(unref(timezoneRef));
78+
setCurrentTimezone(unref(timezoneRef));
7879
}
7980

8081
/**
@@ -87,7 +88,7 @@ const useTimezoneStore = defineStore(
8788
await timezoneHandler.setTimezone?.(timezone);
8889
timezoneRef.value = timezone;
8990
// 设置dayjs默认时区
90-
setDefaultTimezone(timezone);
91+
setCurrentTimezone(timezone);
9192
}
9293

9394
/**
@@ -103,10 +104,15 @@ const useTimezoneStore = defineStore(
103104
console.error('Failed to initialize timezone during store setup:', error);
104105
});
105106

107+
function $reset() {
108+
timezoneRef.value = getCurrentTimezone();
109+
}
110+
106111
return {
107112
timezone: timezoneRef,
108113
setTimezone,
109114
getTimezoneOptions,
115+
$reset,
110116
};
111117
},
112118
{

0 commit comments

Comments
 (0)