From 2d19a275a8b4fca71532e62dde7ad0a8fbd23e81 Mon Sep 17 00:00:00 2001 From: zhx Date: Fri, 8 May 2026 13:29:18 +0800 Subject: [PATCH] feat(admin): add dashboard timezone selector --- apps/src/api/legacy/datav.ts | 1 + apps/src/views/statistics/datav.vue | 41 +++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/apps/src/api/legacy/datav.ts b/apps/src/api/legacy/datav.ts index e551fd8..4b67133 100644 --- a/apps/src/api/legacy/datav.ts +++ b/apps/src/api/legacy/datav.ts @@ -46,6 +46,7 @@ export interface CountryDashboardResult { periodType: string; records: CountryDashboardMetric[]; startDate?: string; + statTimezone?: string; total: CountryDashboardMetric; } diff --git a/apps/src/views/statistics/datav.vue b/apps/src/views/statistics/datav.vue index 3257723..ceae0a1 100644 --- a/apps/src/views/statistics/datav.vue +++ b/apps/src/views/statistics/datav.vue @@ -35,6 +35,8 @@ import { Tooltip, } from 'antdv-next'; import dayjs from 'dayjs'; +import timezone from 'dayjs/plugin/timezone'; +import utc from 'dayjs/plugin/utc'; import { countryDashboard, @@ -48,6 +50,11 @@ import PurchaseCount from './components/purchase-count.vue'; defineOptions({ name: 'StatisticsDatav' }); +dayjs.extend(utc); +dayjs.extend(timezone); + +const DEFAULT_STAT_TIMEZONE = 'Asia/Riyadh'; + const accessStore = useAccessStore(); const datavFullscreen = ref(); @@ -65,9 +72,10 @@ const arpuDashboards = ref<{ threeDay: null, week: null, }); +const initialDate = dayjs().tz(DEFAULT_STAT_TIMEZONE); const dateRange = ref<[string, string] | null>([ - dayjs().subtract(6, 'day').format('YYYY-MM-DD'), - dayjs().format('YYYY-MM-DD'), + initialDate.subtract(6, 'day').format('YYYY-MM-DD'), + initialDate.format('YYYY-MM-DD'), ]); const selectedCountryCodes = ref([]); const rechargeDetailOpen = ref(false); @@ -81,6 +89,7 @@ const rechargeDetailPagination = reactive({ const query = reactive({ periodType: 'DAY', + statTimezone: DEFAULT_STAT_TIMEZONE, sysOrigin: '', }); @@ -110,6 +119,12 @@ const periodTypeOptions = [ { label: '全部', value: 'ALL' }, ]; +const statTimezoneOptions = [ + { label: '利雅得(服务器)', value: 'Asia/Riyadh' }, + { label: 'UTC', value: 'UTC' }, + { label: '北京', value: 'Asia/Shanghai' }, +]; + const metricColumns = new Set([ 'countryNewUser', 'd1RetentionRate', @@ -366,6 +381,9 @@ function hasPermission(code: string) { const canQuery = computed(() => hasPermission('datav:query')); const canPaidPreview = computed(() => hasPermission('datav:paid:preview')); +const currentTimezoneLabel = computed(() => { + return statTimezoneOptions.find((item) => item.value === query.statTimezone)?.label || query.statTimezone; +}); function syncFullscreenState() { fullscreen.value = document.fullscreenElement === datavFullscreen.value; @@ -392,7 +410,7 @@ async function toggleVisualMode() { } function defaultRange(periodType: string): [string, string] | null { - const now = dayjs(); + const now = dayjs().tz(query.statTimezone || DEFAULT_STAT_TIMEZONE); if (periodType === 'ALL') { return null; } @@ -411,9 +429,15 @@ function handlePeriodChange(value: string) { loadDashboard(); } +function handleTimezoneChange() { + dateRange.value = defaultRange(query.periodType); + loadDashboard(); +} + function buildParams() { const params: Record = { periodType: query.periodType, + statTimezone: query.statTimezone || DEFAULT_STAT_TIMEZONE, sysOrigin: query.sysOrigin || undefined, }; if (dateRange.value?.[0] && dateRange.value?.[1]) { @@ -424,12 +448,13 @@ function buildParams() { } function buildRecentDayParams(dayCount: number) { - const end = dayjs(); + const end = dayjs().tz(query.statTimezone || DEFAULT_STAT_TIMEZONE); const start = end.subtract(dayCount - 1, 'day'); return { periodType: 'DAY', startDate: start.format('YYYY-MM-DD'), endDate: end.format('YYYY-MM-DD'), + statTimezone: query.statTimezone || DEFAULT_STAT_TIMEZONE, sysOrigin: query.sysOrigin || undefined, }; } @@ -919,7 +944,7 @@ onBeforeUnmount(() => {
数据大屏
- 国家维度 · {{ dashboard?.computedAt || '-' }} + 国家维度 · {{ currentTimezoneLabel }} · {{ dashboard?.computedAt || '-' }}
@@ -948,6 +973,12 @@ onBeforeUnmount(() => { style="width: 150px" @change="loadDashboard" /> +