From 7aed3ce16d0f15f4feb945d198413053ca6c44c1 Mon Sep 17 00:00:00 2001 From: 170-carry Date: Tue, 28 Apr 2026 11:35:19 +0800 Subject: [PATCH] =?UTF-8?q?up=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../routes/modules/resident-activity.ts | 2 +- apps/src/views/statistics/datav.vue | 117 ++++++++++++++++-- 2 files changed, 109 insertions(+), 10 deletions(-) diff --git a/apps/src/router/routes/modules/resident-activity.ts b/apps/src/router/routes/modules/resident-activity.ts index a7290c1..c00a3a2 100644 --- a/apps/src/router/routes/modules/resident-activity.ts +++ b/apps/src/router/routes/modules/resident-activity.ts @@ -40,7 +40,7 @@ const routes: RouteRecordRaw[] = [ path: 'specified-gift-weekly-rank', alias: 'week-star', component: () => import('#/views/resident-activity/week-star.vue'), - meta: { title: '指定礼物周榜' }, + meta: { title: '周星' }, }, { name: 'ResidentRoomTurnoverReward', diff --git a/apps/src/views/statistics/datav.vue b/apps/src/views/statistics/datav.vue index 4f13af2..778079a 100644 --- a/apps/src/views/statistics/datav.vue +++ b/apps/src/views/statistics/datav.vue @@ -48,6 +48,15 @@ const fullscreen = ref(false); const visualMode = ref(false); const loading = ref(false); const dashboard = ref(null); +const upDashboards = ref<{ + day: CountryDashboardResult | null; + threeDay: CountryDashboardResult | null; + week: CountryDashboardResult | null; +}>({ + day: null, + threeDay: null, + week: null, +}); const dateRange = ref<[string, string] | null>([ dayjs().subtract(6, 'day').format('YYYY-MM-DD'), dayjs().format('YYYY-MM-DD'), @@ -220,7 +229,11 @@ const columns: any[] = [ { align: 'right', dataIndex: 'gamePayoutRate', key: 'gamePayoutRate', title: '游戏返奖率', width: 140 }, { align: 'right', dataIndex: 'gameProfit', key: 'gameProfit', title: '游戏利润', width: 130 }, { align: 'right', dataIndex: 'gameProfitRate', key: 'gameProfitRate', title: '游戏利润率', width: 140 }, -]; +].map((column) => ({ + ...column, + sortDirections: ['ascend', 'descend'], + sorter: compareTableColumn(String(column.dataIndex)), +})); const tableScrollX = columns.reduce((totalWidth, item) => totalWidth + Number(item.width || 0), 0); const rawRecords = computed(() => dashboard.value?.records || []); @@ -238,11 +251,7 @@ const countryOptions = computed(() => { .toSorted((current, next) => current.label.localeCompare(next.label)); }); const records = computed(() => { - const selected = new Set(selectedCountryCodes.value); - if (selected.size === 0) { - return rawRecords.value; - } - return rawRecords.value.filter((item) => selected.has(String(item.countryCode || ''))); + return filterRecordsBySelectedCountries(rawRecords.value); }); const chartRecords = computed(() => records.value.filter((item) => item.countryCode !== 'ALL')); const visibleSummary = computed(() => buildVisibleSummary(records.value)); @@ -273,6 +282,14 @@ const appDataCards = computed(() => { { label: '30 日留存率', value: formatPercent(summary.d30RetentionRate) }, ]; }); +const upValueCards = computed(() => { + return [ + { label: '日 UP 值', value: formatUpValue(upDashboards.value.day) }, + { label: '3 日 UP 值', value: formatUpValue(upDashboards.value.threeDay) }, + { label: '周 UP 值', value: formatUpValue(upDashboards.value.week) }, + { label: '筛选 UP 值', value: formatAmount(calcUpValue(visibleSummary.value)) }, + ]; +}); function hasPermission(code: string) { const codes = accessCodes.value; @@ -338,15 +355,43 @@ function buildParams() { return params; } +function buildRecentDayParams(dayCount: number) { + const end = dayjs(); + const start = end.subtract(dayCount - 1, 'day'); + return { + periodType: 'DAY', + startDate: start.format('YYYY-MM-DD'), + endDate: end.format('YYYY-MM-DD'), + sysOrigin: query.sysOrigin || undefined, + }; +} + async function loadDashboard() { if (!canQuery.value) { return; } loading.value = true; try { - dashboard.value = await countryDashboard(buildParams()); + const [mainDashboard, dayUpDashboard, threeDayUpDashboard, weekUpDashboard] = + await Promise.all([ + countryDashboard(buildParams()), + countryDashboard(buildRecentDayParams(1)), + countryDashboard(buildRecentDayParams(3)), + countryDashboard(buildRecentDayParams(7)), + ]); + dashboard.value = mainDashboard; + upDashboards.value = { + day: dayUpDashboard, + threeDay: threeDayUpDashboard, + week: weekUpDashboard, + }; } catch (error) { dashboard.value = null; + upDashboards.value = { + day: null, + threeDay: null, + week: null, + }; message.error('数据大屏加载失败'); throw error; } finally { @@ -450,6 +495,19 @@ function resolveMetricRate(record: Record, key: string) { return 0; } +function calcUpValue(summary: Record) { + const activeUser = toAmount(summary.dailyActiveUser); + if (activeUser === 0) { + return 0; + } + return toAmount(summary.totalRecharge) / activeUser; +} + +function formatUpValue(result?: CountryDashboardResult | null) { + const summary = buildVisibleSummary(filterRecordsBySelectedCountries(result?.records || [])); + return formatAmount(calcUpValue(summary)); +} + function emptySummary(): SummaryMetric { return { countryNewUser: 0, @@ -529,6 +587,29 @@ function tableCellText(record: Record, key: string) { return formatAmount(record[key] as number | string); } +function compareTableColumn(key: string) { + return (current: Record, next: Record) => { + if (metricColumns.has(key)) { + const currentValue = percentMetricColumns.has(key) + ? resolveMetricRate(current, key) + : toAmount(current[key]); + const nextValue = percentMetricColumns.has(key) + ? resolveMetricRate(next, key) + : toAmount(next[key]); + return currentValue - nextValue; + } + return String(current[key] || '').localeCompare(String(next[key] || '')); + }; +} + +function filterRecordsBySelectedCountries(list: CountryDashboardMetric[]) { + const selected = new Set(selectedCountryCodes.value); + if (selected.size === 0) { + return list; + } + return list.filter((item) => selected.has(String(item.countryCode || ''))); +} + function rowKey(record: Record) { return `${record.countryCode}-${record.periodKey}`; } @@ -805,6 +886,19 @@ onBeforeUnmount(() => { +
+
UP 值
+
+
+
{{ item.label }}
+
{{ item.value }}
+
+
+
@@ -956,7 +1050,7 @@ onBeforeUnmount(() => { .metric-section-grid { display: grid; gap: 16px; - grid-template-columns: minmax(0, 3fr) minmax(280px, 2fr); + grid-template-columns: minmax(0, 3fr) minmax(260px, 2fr) minmax(260px, 2fr); } .metric-section { @@ -980,6 +1074,10 @@ onBeforeUnmount(() => { grid-template-columns: repeat(2, minmax(0, 1fr)); } +.metric-card-grid--up { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + .metric-card { background: #111827; border: 1px solid rgba(45, 212, 191, 0.18); @@ -1096,7 +1194,8 @@ onBeforeUnmount(() => { .metric-section-grid, .metric-card-grid, - .metric-card-grid--app { + .metric-card-grid--app, + .metric-card-grid--up { grid-template-columns: 1fr; } }