fix: resolve the issue of logout failure caused by the timezone store

This commit is contained in:
zhongming4762 2025-10-30 17:01:49 +08:00
parent ac6de0324c
commit 565be77e96
3 changed files with 183 additions and 18 deletions

View File

@ -0,0 +1,143 @@
import dayjs from 'dayjs';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import {
formatDate,
formatDateTime,
getCurrentTimezone,
getSystemTimezone,
isDate,
isDayjsObject,
setCurrentTimezone,
} from '../date';
dayjs.extend(utc);
dayjs.extend(timezone);
describe('dateUtils', () => {
const sampleISO = '2024-10-30T12:34:56Z';
const sampleTimestamp = Date.parse(sampleISO);
beforeEach(() => {
// 重置时区
dayjs.tz.setDefault();
setCurrentTimezone(); // 重置为系统默认
});
afterEach(() => {
vi.restoreAllMocks();
});
// ===============================
// formatDate
// ===============================
describe('formatDate', () => {
it('should format a valid ISO date string', () => {
const formatted = formatDate(sampleISO, 'YYYY/MM/DD');
expect(formatted).toMatch(/2024\/10\/30/);
});
it('should format a timestamp correctly', () => {
const formatted = formatDate(sampleTimestamp);
expect(formatted).toMatch(/2024-10-30/);
});
it('should format a Date object', () => {
const formatted = formatDate(new Date(sampleISO));
expect(formatted).toMatch(/2024-10-30/);
});
it('should format a dayjs object', () => {
const formatted = formatDate(dayjs(sampleISO));
expect(formatted).toMatch(/2024-10-30/);
});
it('should return original input if date is invalid', () => {
const invalid = 'not-a-date';
const spy = vi.spyOn(console, 'error').mockImplementation(() => {});
const formatted = formatDate(invalid);
expect(formatted).toBe(invalid);
expect(spy).toHaveBeenCalledOnce();
});
it('should apply given format', () => {
const formatted = formatDate(sampleISO, 'YYYY-MM-DD HH:mm');
expect(formatted).toMatch(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}/);
});
});
// ===============================
// formatDateTime
// ===============================
describe('formatDateTime', () => {
it('should format date into full datetime', () => {
const result = formatDateTime(sampleISO);
expect(result).toMatch(/2024-10-30 \d{2}:\d{2}:\d{2}/);
});
});
// ===============================
// isDate
// ===============================
describe('isDate', () => {
it('should return true for Date instances', () => {
expect(isDate(new Date())).toBe(true);
});
it('should return false for non-Date values', () => {
expect(isDate('2024-10-30')).toBe(false);
expect(isDate(null)).toBe(false);
expect(isDate(undefined)).toBe(false);
});
});
// ===============================
// isDayjsObject
// ===============================
describe('isDayjsObject', () => {
it('should return true for dayjs objects', () => {
expect(isDayjsObject(dayjs())).toBe(true);
});
it('should return false for other values', () => {
expect(isDayjsObject(new Date())).toBe(false);
expect(isDayjsObject('string')).toBe(false);
});
});
// ===============================
// getSystemTimezone
// ===============================
describe('getSystemTimezone', () => {
it('should return a valid IANA timezone string', () => {
const tz = getSystemTimezone();
expect(typeof tz).toBe('string');
expect(tz).toMatch(/^[A-Z]+\/[A-Z_]+/i);
});
});
// ===============================
// setCurrentTimezone / getCurrentTimezone
// ===============================
describe('setCurrentTimezone & getCurrentTimezone', () => {
it('should set and retrieve the current timezone', () => {
setCurrentTimezone('Asia/Shanghai');
expect(getCurrentTimezone()).toBe('Asia/Shanghai');
});
it('should reset to system timezone when called with no args', () => {
const guessed = getSystemTimezone();
setCurrentTimezone();
expect(getCurrentTimezone()).toBe(guessed);
});
it('should update dayjs default timezone', () => {
setCurrentTimezone('America/New_York');
const d = dayjs('2024-01-01T00:00:00Z');
// 校验时区转换生效(小时变化)
expect(d.tz().format('HH')).not.toBe('00');
});
});
});

View File

@ -5,9 +5,11 @@ import utc from 'dayjs/plugin/utc';
dayjs.extend(utc); dayjs.extend(utc);
dayjs.extend(timezone); dayjs.extend(timezone);
export function formatDate(time: number | string, format = 'YYYY-MM-DD') { type FormatDate = Date | dayjs.Dayjs | number | string;
export function formatDate(time: FormatDate, format = 'YYYY-MM-DD') {
try { try {
const date = dayjs(time); const date = dayjs.isDayjs(time) ? time : dayjs(time);
if (!date.isValid()) { if (!date.isValid()) {
throw new Error('Invalid date'); throw new Error('Invalid date');
} }
@ -18,7 +20,7 @@ export function formatDate(time: number | string, format = 'YYYY-MM-DD') {
} }
} }
export function formatDateTime(time: number | string) { export function formatDateTime(time: FormatDate) {
return formatDate(time, 'YYYY-MM-DD HH:mm:ss'); return formatDate(time, 'YYYY-MM-DD HH:mm:ss');
} }
@ -30,18 +32,32 @@ export function isDayjsObject(value: any): value is dayjs.Dayjs {
return dayjs.isDayjs(value); return dayjs.isDayjs(value);
} }
/**
*
* @param timezone
*/
export const setDefaultTimezone = (timezone?: string) => {
timezone ? dayjs.tz.setDefault(timezone) : dayjs.tz.setDefault();
};
/** /**
* *
* @returns * @returns
*/ */
export const getTimezone = () => { export const getSystemTimezone = () => {
return dayjs.tz.guess(); return dayjs.tz.guess();
}; };
/**
*
*/
let currentTimezone = getSystemTimezone();
/**
*
* @param timezone
*/
export const setCurrentTimezone = (timezone?: string) => {
currentTimezone = timezone || getSystemTimezone();
dayjs.tz.setDefault(currentTimezone);
};
/**
*
* @returns
*/
export const getCurrentTimezone = () => {
return currentTimezone;
};

View File

@ -1,7 +1,10 @@
import { ref, unref } from 'vue'; import { ref, unref } from 'vue';
import { DEFAULT_TIME_ZONE_OPTIONS } from '@vben-core/preferences'; import { DEFAULT_TIME_ZONE_OPTIONS } from '@vben-core/preferences';
import { getTimezone, setDefaultTimezone } from '@vben-core/shared/utils'; import {
getCurrentTimezone,
setCurrentTimezone,
} from '@vben-core/shared/utils';
import { acceptHMRUpdate, defineStore } from 'pinia'; import { acceptHMRUpdate, defineStore } from 'pinia';
@ -59,9 +62,7 @@ const getTimezoneHandler = () => {
const useTimezoneStore = defineStore( const useTimezoneStore = defineStore(
'core-timezone', 'core-timezone',
() => { () => {
const timezoneRef = ref( const timezoneRef = ref(getCurrentTimezone());
getTimezone() || new Intl.DateTimeFormat().resolvedOptions().timeZone,
);
/** /**
* *
@ -74,7 +75,7 @@ const useTimezoneStore = defineStore(
timezoneRef.value = timezone; timezoneRef.value = timezone;
} }
// 设置dayjs默认时区 // 设置dayjs默认时区
setDefaultTimezone(unref(timezoneRef)); setCurrentTimezone(unref(timezoneRef));
} }
/** /**
@ -87,7 +88,7 @@ const useTimezoneStore = defineStore(
await timezoneHandler.setTimezone?.(timezone); await timezoneHandler.setTimezone?.(timezone);
timezoneRef.value = timezone; timezoneRef.value = timezone;
// 设置dayjs默认时区 // 设置dayjs默认时区
setDefaultTimezone(timezone); setCurrentTimezone(timezone);
} }
/** /**
@ -103,10 +104,15 @@ const useTimezoneStore = defineStore(
console.error('Failed to initialize timezone during store setup:', error); console.error('Failed to initialize timezone during store setup:', error);
}); });
function $reset() {
timezoneRef.value = getCurrentTimezone();
}
return { return {
timezone: timezoneRef, timezone: timezoneRef,
setTimezone, setTimezone,
getTimezoneOptions, getTimezoneOptions,
$reset,
}; };
}, },
{ {