32 changed files with 577 additions and 9 deletions
@ -0,0 +1,7 @@ |
|||
import { eventHandler } from 'h3'; |
|||
import { TIME_ZONE_OPTIONS } from '~/utils/mock-data'; |
|||
import { useResponseSuccess } from '~/utils/response'; |
|||
|
|||
export default eventHandler(() => { |
|||
return useResponseSuccess(TIME_ZONE_OPTIONS); |
|||
}); |
|||
@ -0,0 +1,14 @@ |
|||
import { eventHandler, readBody } from 'h3'; |
|||
import { verifyAccessToken } from '~/utils/jwt-utils'; |
|||
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response'; |
|||
import { setTimezone } from '~/utils/timezone-utils'; |
|||
|
|||
export default eventHandler(async (event) => { |
|||
const userinfo = verifyAccessToken(event); |
|||
if (!userinfo) { |
|||
return unAuthorizedResponse(event); |
|||
} |
|||
const { timezone } = await readBody(event); |
|||
setTimezone(timezone); |
|||
return useResponseSuccess(); |
|||
}); |
|||
@ -0,0 +1,12 @@ |
|||
import { eventHandler } from 'h3'; |
|||
import { verifyAccessToken } from '~/utils/jwt-utils'; |
|||
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response'; |
|||
import { getTimezone } from '~/utils/timezone-utils'; |
|||
|
|||
export default eventHandler((event) => { |
|||
const userinfo = verifyAccessToken(event); |
|||
if (!userinfo) { |
|||
return unAuthorizedResponse(event); |
|||
} |
|||
return useResponseSuccess(getTimezone()); |
|||
}); |
|||
@ -0,0 +1,10 @@ |
|||
let mockTimeZone: null | string = null; |
|||
|
|||
export const setTimezone = (timeZone: string) => { |
|||
mockTimeZone = timeZone; |
|||
}; |
|||
|
|||
export const getTimezone = () => { |
|||
console.log('mockTimeZone', mockTimeZone); |
|||
return mockTimeZone; |
|||
}; |
|||
@ -1,3 +1,4 @@ |
|||
export * from './auth'; |
|||
export * from './menu'; |
|||
export * from './user'; |
|||
export * from './user-profile'; |
|||
|
|||
@ -0,0 +1,23 @@ |
|||
import type { TimezoneOption } from '@vben/types'; |
|||
|
|||
import { requestClient } from '#/api/request'; |
|||
|
|||
/** |
|||
* 获取系统支持的时区列表 |
|||
*/ |
|||
export async function getTimezoneOptionsApi() { |
|||
return requestClient.get<TimezoneOption[]>('/profile/timezone'); |
|||
} |
|||
/** |
|||
* 获取用户时区 |
|||
*/ |
|||
export async function getUserTimezoneApi(): Promise<null | string | undefined> { |
|||
return requestClient.get<null | string | undefined>('/user/timezone'); |
|||
} |
|||
/** |
|||
* 设置用户时区 |
|||
* @param timezone 时区 |
|||
*/ |
|||
export async function setUserTimezoneApi(timezone: string) { |
|||
return requestClient.post('/user/setTimezone', { timezone }); |
|||
} |
|||
@ -1 +1,2 @@ |
|||
export * from './auth'; |
|||
export * from './user-profile'; |
|||
|
|||
@ -0,0 +1,56 @@ |
|||
import { ref } from 'vue'; |
|||
|
|||
import { getTimezone, setDefaultTimezone } from '@vben/utils'; |
|||
|
|||
import { acceptHMRUpdate, defineStore } from 'pinia'; |
|||
|
|||
import { getUserTimezoneApi, setUserTimezoneApi } from '#/api'; |
|||
|
|||
const useUserProfileStore = defineStore('user-profile', () => { |
|||
const timezoneRef = ref( |
|||
getTimezone() || new Intl.DateTimeFormat().resolvedOptions().timeZone, |
|||
); |
|||
|
|||
/** |
|||
* 设置用户时区 |
|||
* Set the user's timezone |
|||
* @param timezone 时区字符串 |
|||
*/ |
|||
async function setTimezone(timezone: string) { |
|||
timezoneRef.value = timezone; |
|||
// 设置dayjs默认时区
|
|||
setDefaultTimezone(timezone); |
|||
// 保存用户的时区设置
|
|||
await setUserTimezoneApi(timezone); |
|||
} |
|||
|
|||
/** |
|||
* 初始化用户时区 |
|||
* Initialize the user's timezone |
|||
*/ |
|||
async function initTimezone() { |
|||
// 从服务器获取用户时区
|
|||
const timezone = await getUserTimezoneApi(); |
|||
if (timezone) { |
|||
timezoneRef.value = timezone; |
|||
// 设置dayjs默认时区
|
|||
setDefaultTimezone(timezone); |
|||
} |
|||
} |
|||
|
|||
initTimezone(); |
|||
|
|||
return { |
|||
timezone: timezoneRef, |
|||
setTimezone, |
|||
initTimezone, |
|||
}; |
|||
}); |
|||
|
|||
export { useUserProfileStore }; |
|||
|
|||
// 解决热更新问题
|
|||
const hot = import.meta.hot; |
|||
if (hot) { |
|||
hot.accept(acceptHMRUpdate(useUserProfileStore, hot)); |
|||
} |
|||
@ -1,3 +1,4 @@ |
|||
export * from './auth'; |
|||
export * from './menu'; |
|||
export * from './user'; |
|||
export * from './user-profile'; |
|||
|
|||
@ -0,0 +1,23 @@ |
|||
import type { TimezoneOption } from '@vben/types'; |
|||
|
|||
import { requestClient } from '#/api/request'; |
|||
|
|||
/** |
|||
* 获取系统支持的时区列表 |
|||
*/ |
|||
export async function getTimezoneOptionsApi() { |
|||
return requestClient.get<TimezoneOption[]>('/profile/timezone'); |
|||
} |
|||
/** |
|||
* 获取用户时区 |
|||
*/ |
|||
export async function getUserTimezoneApi(): Promise<null | string | undefined> { |
|||
return requestClient.get<null | string | undefined>('/user/timezone'); |
|||
} |
|||
/** |
|||
* 设置用户时区 |
|||
* @param timezone 时区 |
|||
*/ |
|||
export async function setUserTimezoneApi(timezone: string) { |
|||
return requestClient.post('/user/setTimezone', { timezone }); |
|||
} |
|||
@ -1 +1,2 @@ |
|||
export * from './auth'; |
|||
export * from './user-profile'; |
|||
|
|||
@ -0,0 +1,56 @@ |
|||
import { ref } from 'vue'; |
|||
|
|||
import { getTimezone, setDefaultTimezone } from '@vben/utils'; |
|||
|
|||
import { acceptHMRUpdate, defineStore } from 'pinia'; |
|||
|
|||
import { getUserTimezoneApi, setUserTimezoneApi } from '#/api'; |
|||
|
|||
const useUserProfileStore = defineStore('user-profile', () => { |
|||
const timezoneRef = ref( |
|||
getTimezone() || new Intl.DateTimeFormat().resolvedOptions().timeZone, |
|||
); |
|||
|
|||
/** |
|||
* 设置用户时区 |
|||
* Set the user's timezone |
|||
* @param timezone 时区字符串 |
|||
*/ |
|||
async function setTimezone(timezone: string) { |
|||
timezoneRef.value = timezone; |
|||
// 设置dayjs默认时区
|
|||
setDefaultTimezone(timezone); |
|||
// 保存用户的时区设置
|
|||
await setUserTimezoneApi(timezone); |
|||
} |
|||
|
|||
/** |
|||
* 初始化用户时区 |
|||
* Initialize the user's timezone |
|||
*/ |
|||
async function initTimezone() { |
|||
// 从服务器获取用户时区
|
|||
const timezone = await getUserTimezoneApi(); |
|||
if (timezone) { |
|||
timezoneRef.value = timezone; |
|||
// 设置dayjs默认时区
|
|||
setDefaultTimezone(timezone); |
|||
} |
|||
} |
|||
|
|||
initTimezone(); |
|||
|
|||
return { |
|||
timezone: timezoneRef, |
|||
setTimezone, |
|||
initTimezone, |
|||
}; |
|||
}); |
|||
|
|||
export { useUserProfileStore }; |
|||
|
|||
// 解决热更新问题
|
|||
const hot = import.meta.hot; |
|||
if (hot) { |
|||
hot.accept(acceptHMRUpdate(useUserProfileStore, hot)); |
|||
} |
|||
@ -1,3 +1,4 @@ |
|||
export * from './auth'; |
|||
export * from './menu'; |
|||
export * from './user'; |
|||
export * from './user-profile'; |
|||
|
|||
@ -0,0 +1,23 @@ |
|||
import type { TimezoneOption } from '@vben/types'; |
|||
|
|||
import { requestClient } from '#/api/request'; |
|||
|
|||
/** |
|||
* 获取系统支持的时区列表 |
|||
*/ |
|||
export async function getTimezoneOptionsApi() { |
|||
return requestClient.get<TimezoneOption[]>('/profile/timezone'); |
|||
} |
|||
/** |
|||
* 获取用户时区 |
|||
*/ |
|||
export async function getUserTimezoneApi(): Promise<null | string | undefined> { |
|||
return requestClient.get<null | string | undefined>('/user/timezone'); |
|||
} |
|||
/** |
|||
* 设置用户时区 |
|||
* @param timezone 时区 |
|||
*/ |
|||
export async function setUserTimezoneApi(timezone: string) { |
|||
return requestClient.post('/user/setTimezone', { timezone }); |
|||
} |
|||
@ -1 +1,2 @@ |
|||
export * from './auth'; |
|||
export * from './user-profile'; |
|||
|
|||
@ -0,0 +1,56 @@ |
|||
import { ref } from 'vue'; |
|||
|
|||
import { getTimezone, setDefaultTimezone } from '@vben/utils'; |
|||
|
|||
import { acceptHMRUpdate, defineStore } from 'pinia'; |
|||
|
|||
import { getUserTimezoneApi, setUserTimezoneApi } from '#/api'; |
|||
|
|||
const useUserProfileStore = defineStore('user-profile', () => { |
|||
const timezoneRef = ref( |
|||
getTimezone() || new Intl.DateTimeFormat().resolvedOptions().timeZone, |
|||
); |
|||
|
|||
/** |
|||
* 设置用户时区 |
|||
* Set the user's timezone |
|||
* @param timezone 时区字符串 |
|||
*/ |
|||
async function setTimezone(timezone: string) { |
|||
timezoneRef.value = timezone; |
|||
// 设置dayjs默认时区
|
|||
setDefaultTimezone(timezone); |
|||
// 保存用户的时区设置
|
|||
await setUserTimezoneApi(timezone); |
|||
} |
|||
|
|||
/** |
|||
* 初始化用户时区 |
|||
* Initialize the user's timezone |
|||
*/ |
|||
async function initTimezone() { |
|||
// 从服务器获取用户时区
|
|||
const timezone = await getUserTimezoneApi(); |
|||
if (timezone) { |
|||
timezoneRef.value = timezone; |
|||
// 设置dayjs默认时区
|
|||
setDefaultTimezone(timezone); |
|||
} |
|||
} |
|||
|
|||
initTimezone(); |
|||
|
|||
return { |
|||
timezone: timezoneRef, |
|||
setTimezone, |
|||
initTimezone, |
|||
}; |
|||
}); |
|||
|
|||
export { useUserProfileStore }; |
|||
|
|||
// 解决热更新问题
|
|||
const hot = import.meta.hot; |
|||
if (hot) { |
|||
hot.accept(acceptHMRUpdate(useUserProfileStore, hot)); |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
/** |
|||
* 时区选项 |
|||
*/ |
|||
interface TimezoneOption { |
|||
offset: number; |
|||
timezone: string; |
|||
} |
|||
|
|||
export type { TimezoneOption }; |
|||
@ -0,0 +1 @@ |
|||
export { default as TimezoneButton } from './timezone-button.vue'; |
|||
@ -0,0 +1,89 @@ |
|||
<script setup lang="ts"> |
|||
import type { ExtendedModalApi } from '@vben-core/popup-ui'; |
|||
|
|||
import { ref, unref, watch } from 'vue'; |
|||
|
|||
import { createIconifyIcon } from '@vben/icons'; |
|||
import { $t } from '@vben/locales'; |
|||
|
|||
import { useVbenModal } from '@vben-core/popup-ui'; |
|||
import { |
|||
RadioGroup, |
|||
RadioGroupItem, |
|||
VbenIconButton, |
|||
} from '@vben-core/shadcn-ui'; |
|||
|
|||
interface Props { |
|||
timezoneOptions: string[]; |
|||
okHandler?: ( |
|||
timezone: string, |
|||
modalApi: ExtendedModalApi, |
|||
) => Promise<void> | void; |
|||
timezone?: string; |
|||
} |
|||
|
|||
interface Listener { |
|||
change: (timezone: string) => void; |
|||
} |
|||
|
|||
const props = defineProps<Props>(); |
|||
const emit = defineEmits<Listener>(); |
|||
|
|||
const TimezoneIcon = createIconifyIcon('fluent-mdl2:world-clock'); |
|||
|
|||
const [Modal, modalApi] = useVbenModal({ |
|||
fullscreenButton: false, |
|||
onConfirm: () => { |
|||
props.okHandler?.(unref(timezoneValue), modalApi); |
|||
}, |
|||
}); |
|||
|
|||
const handleClick = () => { |
|||
modalApi.open(); |
|||
}; |
|||
|
|||
const timezoneValue = ref(props.timezone); |
|||
watch( |
|||
() => props.timezone, |
|||
(newTimezone) => { |
|||
timezoneValue.value = newTimezone; |
|||
}, |
|||
); |
|||
const handleClickItem = (timezone: string) => { |
|||
timezoneValue.value = timezone; |
|||
emit('change', timezone); |
|||
}; |
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<VbenIconButton |
|||
:tooltip="$t('ui.widgets.timezone.setTimezone')" |
|||
class="hover:animate-[shrink_0.3s_ease-in-out]" |
|||
@click="handleClick" |
|||
> |
|||
<TimezoneIcon class="text-foreground size-4" /> |
|||
</VbenIconButton> |
|||
<Modal :title="$t('ui.widgets.timezone.setTimezone')"> |
|||
<div class="timezone-container"> |
|||
<RadioGroup v-model="timezoneValue" class="flex flex-col gap-2"> |
|||
<div |
|||
class="flex cursor-pointer items-center gap-2" |
|||
v-for="item in props.timezoneOptions" |
|||
:key="`container${item}`" |
|||
@click="handleClickItem(item)" |
|||
> |
|||
<RadioGroupItem :id="item" :value="item" /> |
|||
<label class="cursor-pointer">{{ item }}</label> |
|||
</div> |
|||
</RadioGroup> |
|||
</div> |
|||
</Modal> |
|||
</div> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
.container { |
|||
padding-left: 20px; |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue