feat(admin): add country dashboard game metrics table
This commit is contained in:
parent
2e816ed681
commit
6eb24bdd99
@ -65,6 +65,25 @@ export interface CountryDashboardRechargeDetail {
|
|||||||
userNickname: string;
|
userNickname: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CountryDashboardGameMetric {
|
||||||
|
consumeAmount: number | string;
|
||||||
|
countryCode: string;
|
||||||
|
countryName: string;
|
||||||
|
gameId: string;
|
||||||
|
gameName: string;
|
||||||
|
gameProvider: string;
|
||||||
|
orderCount: number;
|
||||||
|
payoutAmount: number | string;
|
||||||
|
payoutRate: number | string;
|
||||||
|
periodKey: string;
|
||||||
|
periodName: string;
|
||||||
|
profitAmount: number | string;
|
||||||
|
profitRate: number | string;
|
||||||
|
refreshedAt: string;
|
||||||
|
statTimezone: string;
|
||||||
|
userCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
export async function countryDashboard(params: Record<string, any> = {}) {
|
export async function countryDashboard(params: Record<string, any> = {}) {
|
||||||
return requestClient.get<CountryDashboardResult>('/datav/country-dashboard', {
|
return requestClient.get<CountryDashboardResult>('/datav/country-dashboard', {
|
||||||
params,
|
params,
|
||||||
@ -84,6 +103,19 @@ export async function countryDashboardRechargeDetails(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function countryDashboardGameMetrics(
|
||||||
|
params: Record<string, any> = {},
|
||||||
|
) {
|
||||||
|
return requestClient.get<{
|
||||||
|
current: number;
|
||||||
|
records: CountryDashboardGameMetric[];
|
||||||
|
size: number;
|
||||||
|
total: number;
|
||||||
|
}>('/datav/country-dashboard/game-metrics', {
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export async function latestActiveUserCountryCode(params: Record<string, any> = {}) {
|
export async function latestActiveUserCountryCode(params: Record<string, any> = {}) {
|
||||||
return requestClient.get<Array<Record<string, any>>>(
|
return requestClient.get<Array<Record<string, any>>>(
|
||||||
'/datav/active/user-country-code',
|
'/datav/active/user-country-code',
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
import type { EchartsUIType } from '@vben/plugins/echarts';
|
import type { EchartsUIType } from '@vben/plugins/echarts';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
CountryDashboardGameMetric,
|
||||||
CountryDashboardMetric,
|
CountryDashboardMetric,
|
||||||
CountryDashboardRechargeDetail,
|
CountryDashboardRechargeDetail,
|
||||||
CountryDashboardResult,
|
CountryDashboardResult,
|
||||||
@ -24,13 +25,14 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
DateRangePicker,
|
DateRangePicker,
|
||||||
Empty,
|
Empty,
|
||||||
|
Input,
|
||||||
message,
|
message,
|
||||||
Modal,
|
Modal,
|
||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
Spin,
|
Spin,
|
||||||
TabPane,
|
|
||||||
Table,
|
Table,
|
||||||
|
TabPane,
|
||||||
Tabs,
|
Tabs,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from 'antdv-next';
|
} from 'antdv-next';
|
||||||
@ -40,6 +42,7 @@ import utc from 'dayjs/plugin/utc';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
countryDashboard,
|
countryDashboard,
|
||||||
|
countryDashboardGameMetrics,
|
||||||
countryDashboardRechargeDetails,
|
countryDashboardRechargeDetails,
|
||||||
} from '#/api/legacy/datav';
|
} from '#/api/legacy/datav';
|
||||||
import SysOriginSelect from '#/components/sys-origin-select.vue';
|
import SysOriginSelect from '#/components/sys-origin-select.vue';
|
||||||
@ -62,7 +65,7 @@ const fullscreen = ref(false);
|
|||||||
const visualMode = ref(false);
|
const visualMode = ref(false);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const dashboard = ref<CountryDashboardResult | null>(null);
|
const dashboard = ref<CountryDashboardResult | null>(null);
|
||||||
const activeTableTab = ref<'overview' | 'recharge'>('overview');
|
const activeTableTab = ref<'game' | 'overview' | 'recharge'>('overview');
|
||||||
const arpuDashboards = ref<{
|
const arpuDashboards = ref<{
|
||||||
day: CountryDashboardResult | null;
|
day: CountryDashboardResult | null;
|
||||||
threeDay: CountryDashboardResult | null;
|
threeDay: CountryDashboardResult | null;
|
||||||
@ -86,6 +89,27 @@ const rechargeDetailPagination = reactive({
|
|||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
total: 0,
|
total: 0,
|
||||||
});
|
});
|
||||||
|
const gameMetricLoading = ref(false);
|
||||||
|
const gameMetricRecords = ref<CountryDashboardGameMetric[]>([]);
|
||||||
|
const gameMetricPagination = reactive({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 50,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
|
const gameMetricSorter = reactive<{
|
||||||
|
field?: string;
|
||||||
|
order?: 'ascend' | 'descend';
|
||||||
|
}>({
|
||||||
|
field: 'consumeAmount',
|
||||||
|
order: 'descend',
|
||||||
|
});
|
||||||
|
const gameQuery = reactive<{
|
||||||
|
gameKeyword: string;
|
||||||
|
gameProvider?: string;
|
||||||
|
}>({
|
||||||
|
gameKeyword: '',
|
||||||
|
gameProvider: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
const query = reactive({
|
const query = reactive({
|
||||||
periodType: 'DAY',
|
periodType: 'DAY',
|
||||||
@ -125,6 +149,18 @@ const statTimezoneOptions = [
|
|||||||
{ label: '北京', value: 'Asia/Shanghai' },
|
{ label: '北京', value: 'Asia/Shanghai' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const gameProviderOptions = [
|
||||||
|
{ label: '全部游戏厂商', value: '' },
|
||||||
|
{ label: '站内游戏', value: 'INTERNAL' },
|
||||||
|
{ label: '百顺', value: 'BAISHUN' },
|
||||||
|
{ label: 'Game Open', value: 'GAME_OPEN' },
|
||||||
|
{ label: '灵犀', value: 'LINGXIAN' },
|
||||||
|
{ label: 'Yomi', value: 'YOMI' },
|
||||||
|
{ label: 'HKYS', value: 'HKYS' },
|
||||||
|
{ label: 'Hot', value: 'HOT' },
|
||||||
|
{ label: '未识别', value: 'UNKNOWN' },
|
||||||
|
];
|
||||||
|
|
||||||
const metricColumns = new Set([
|
const metricColumns = new Set([
|
||||||
'countryNewUser',
|
'countryNewUser',
|
||||||
'd1RetentionRate',
|
'd1RetentionRate',
|
||||||
@ -132,7 +168,6 @@ const metricColumns = new Set([
|
|||||||
'd30RetentionRate',
|
'd30RetentionRate',
|
||||||
'dailyActiveUser',
|
'dailyActiveUser',
|
||||||
'dealerRecharge',
|
'dealerRecharge',
|
||||||
'googleRecharge',
|
|
||||||
'gamePayout',
|
'gamePayout',
|
||||||
'gamePayoutRate',
|
'gamePayoutRate',
|
||||||
'gameProfit',
|
'gameProfit',
|
||||||
@ -140,6 +175,7 @@ const metricColumns = new Set([
|
|||||||
'gameTotalFlow',
|
'gameTotalFlow',
|
||||||
'gameUser',
|
'gameUser',
|
||||||
'giftConsume',
|
'giftConsume',
|
||||||
|
'googleRecharge',
|
||||||
'luckyGiftPayout',
|
'luckyGiftPayout',
|
||||||
'luckyGiftPayoutRate',
|
'luckyGiftPayoutRate',
|
||||||
'luckyGiftProfit',
|
'luckyGiftProfit',
|
||||||
@ -288,6 +324,79 @@ const rechargeColumns: any[] = [
|
|||||||
sorter: compareTableColumn(String(column.dataIndex)),
|
sorter: compareTableColumn(String(column.dataIndex)),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const gameMetricNumberColumns = new Set([
|
||||||
|
'consumeAmount',
|
||||||
|
'orderCount',
|
||||||
|
'payoutAmount',
|
||||||
|
'profitAmount',
|
||||||
|
'userCount',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const gameMetricIntegerColumns = new Set(['orderCount', 'userCount']);
|
||||||
|
|
||||||
|
const gameMetricPercentColumns = new Set(['payoutRate', 'profitRate']);
|
||||||
|
|
||||||
|
const gameMetricColumns: any[] = [
|
||||||
|
{ dataIndex: 'periodName', fixed: 'left' as const, key: 'periodName', title: '日期/周期', width: 120 },
|
||||||
|
{ dataIndex: 'countryName', key: 'countryName', title: '国家', width: 150 },
|
||||||
|
{ dataIndex: 'countryCode', key: 'countryCode', title: 'Code', width: 86 },
|
||||||
|
{ dataIndex: 'gameProvider', key: 'gameProvider', title: '游戏厂商', width: 120 },
|
||||||
|
{ dataIndex: 'gameId', key: 'gameId', title: '游戏 ID', width: 130 },
|
||||||
|
{ dataIndex: 'gameName', key: 'gameName', title: '游戏名称', width: 180 },
|
||||||
|
{
|
||||||
|
align: 'right' as const,
|
||||||
|
dataIndex: 'consumeAmount',
|
||||||
|
key: 'consumeAmount',
|
||||||
|
sortDirections: ['descend', 'ascend'],
|
||||||
|
sorter: true,
|
||||||
|
title: '消耗',
|
||||||
|
width: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'right' as const,
|
||||||
|
dataIndex: 'payoutAmount',
|
||||||
|
key: 'payoutAmount',
|
||||||
|
sortDirections: ['descend', 'ascend'],
|
||||||
|
sorter: true,
|
||||||
|
title: '返奖',
|
||||||
|
width: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'right' as const,
|
||||||
|
dataIndex: 'profitAmount',
|
||||||
|
key: 'profitAmount',
|
||||||
|
sortDirections: ['descend', 'ascend'],
|
||||||
|
sorter: true,
|
||||||
|
title: '收益',
|
||||||
|
width: 130,
|
||||||
|
},
|
||||||
|
{ align: 'right' as const, dataIndex: 'payoutRate', key: 'payoutRate', title: '返奖率', width: 110 },
|
||||||
|
{ align: 'right' as const, dataIndex: 'profitRate', key: 'profitRate', title: '收益率', width: 110 },
|
||||||
|
{
|
||||||
|
align: 'right' as const,
|
||||||
|
dataIndex: 'userCount',
|
||||||
|
key: 'userCount',
|
||||||
|
sortDirections: ['descend', 'ascend'],
|
||||||
|
sorter: true,
|
||||||
|
title: '游戏用户数',
|
||||||
|
width: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'right' as const,
|
||||||
|
dataIndex: 'orderCount',
|
||||||
|
key: 'orderCount',
|
||||||
|
sortDirections: ['descend', 'ascend'],
|
||||||
|
sorter: true,
|
||||||
|
title: '流水笔数',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{ dataIndex: 'refreshedAt', key: 'refreshedAt', title: '更新时间', width: 170 },
|
||||||
|
];
|
||||||
|
const gameTableScrollX = gameMetricColumns.reduce(
|
||||||
|
(totalWidth, item) => totalWidth + Number(item.width || 0),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
const rechargeDetailColumns: any[] = [
|
const rechargeDetailColumns: any[] = [
|
||||||
{ dataIndex: 'createTime', key: 'createTime', title: '时间', width: 170 },
|
{ dataIndex: 'createTime', key: 'createTime', title: '时间', width: 170 },
|
||||||
{ dataIndex: 'sourceType', key: 'sourceType', title: '来源', width: 120 },
|
{ dataIndex: 'sourceType', key: 'sourceType', title: '来源', width: 120 },
|
||||||
@ -478,6 +587,9 @@ async function loadDashboard() {
|
|||||||
threeDay: threeDayArpuDashboard,
|
threeDay: threeDayArpuDashboard,
|
||||||
week: weekArpuDashboard,
|
week: weekArpuDashboard,
|
||||||
};
|
};
|
||||||
|
if (activeTableTab.value === 'game') {
|
||||||
|
await loadGameMetrics();
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
dashboard.value = null;
|
dashboard.value = null;
|
||||||
arpuDashboards.value = {
|
arpuDashboards.value = {
|
||||||
@ -493,6 +605,66 @@ async function loadDashboard() {
|
|||||||
renderVisualCharts();
|
renderVisualCharts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildGameMetricParams() {
|
||||||
|
return {
|
||||||
|
...buildParams(),
|
||||||
|
countryCodes: selectedCountryCodes.value.join(',') || undefined,
|
||||||
|
cursor: gameMetricPagination.current,
|
||||||
|
gameKeyword: gameQuery.gameKeyword.trim() || undefined,
|
||||||
|
gameProvider: gameQuery.gameProvider || undefined,
|
||||||
|
limit: gameMetricPagination.pageSize,
|
||||||
|
sortField: gameMetricSorter.field || undefined,
|
||||||
|
sortOrder: gameMetricSorter.order || undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadGameMetrics() {
|
||||||
|
if (!canQuery.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gameMetricLoading.value = true;
|
||||||
|
try {
|
||||||
|
const result = await countryDashboardGameMetrics(buildGameMetricParams());
|
||||||
|
gameMetricRecords.value = result.records || [];
|
||||||
|
gameMetricPagination.total = Number(result.total || 0);
|
||||||
|
gameMetricPagination.current = Number(result.current || gameMetricPagination.current || 1);
|
||||||
|
const resultPageSize = Number(result.size);
|
||||||
|
gameMetricPagination.pageSize =
|
||||||
|
Number.isFinite(resultPageSize) && resultPageSize > 0
|
||||||
|
? resultPageSize
|
||||||
|
: gameMetricPagination.pageSize;
|
||||||
|
} catch {
|
||||||
|
gameMetricRecords.value = [];
|
||||||
|
gameMetricPagination.total = 0;
|
||||||
|
message.error('游戏数据加载失败');
|
||||||
|
} finally {
|
||||||
|
gameMetricLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleGameMetricTableChange(
|
||||||
|
pagination: Record<string, any>,
|
||||||
|
_filters: Record<string, any>,
|
||||||
|
sorter: Record<string, any> | Record<string, any>[],
|
||||||
|
) {
|
||||||
|
const activeSorter = Array.isArray(sorter) ? sorter[0] : sorter;
|
||||||
|
gameMetricPagination.current = Number(pagination.current || 1);
|
||||||
|
gameMetricPagination.pageSize = Number(pagination.pageSize || gameMetricPagination.pageSize || 50);
|
||||||
|
gameMetricSorter.field = activeSorter?.field ? String(activeSorter.field) : undefined;
|
||||||
|
gameMetricSorter.order =
|
||||||
|
activeSorter?.order === 'ascend' || activeSorter?.order === 'descend'
|
||||||
|
? activeSorter.order
|
||||||
|
: undefined;
|
||||||
|
await loadGameMetrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleGameMetricFilterChange() {
|
||||||
|
gameMetricPagination.current = 1;
|
||||||
|
if (activeTableTab.value === 'game') {
|
||||||
|
await loadGameMetrics();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function loadRechargeDetails() {
|
async function loadRechargeDetails() {
|
||||||
rechargeDetailLoading.value = true;
|
rechargeDetailLoading.value = true;
|
||||||
try {
|
try {
|
||||||
@ -524,6 +696,16 @@ function rechargeDetailRowKey(record: Record<string, any>) {
|
|||||||
return `${record.sourceType}-${record.recordId}`;
|
return `${record.sourceType}-${record.recordId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function gameMetricRowKey(record: Record<string, any>) {
|
||||||
|
return [
|
||||||
|
record.periodKey,
|
||||||
|
record.statTimezone,
|
||||||
|
record.countryCode,
|
||||||
|
record.gameProvider,
|
||||||
|
record.gameId,
|
||||||
|
].join('-');
|
||||||
|
}
|
||||||
|
|
||||||
function rechargeSourceName(sourceType: string) {
|
function rechargeSourceName(sourceType: string) {
|
||||||
return rechargeSourceNameMap[sourceType] || sourceType || '-';
|
return rechargeSourceNameMap[sourceType] || sourceType || '-';
|
||||||
}
|
}
|
||||||
@ -541,6 +723,10 @@ function showRechargeDetailTotal(total: number) {
|
|||||||
return `共 ${total} 条`;
|
return `共 ${total} 条`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showGameMetricTotal(total: number) {
|
||||||
|
return `共 ${total} 条`;
|
||||||
|
}
|
||||||
|
|
||||||
function toAmount(value?: null | number | string) {
|
function toAmount(value?: null | number | string) {
|
||||||
const number = Number(value || 0);
|
const number = Number(value || 0);
|
||||||
return Number.isFinite(number) ? number : 0;
|
return Number.isFinite(number) ? number : 0;
|
||||||
@ -730,6 +916,19 @@ function tableCellText(record: Record<string, any>, key: string) {
|
|||||||
return formatAmount(record[key] as number | string);
|
return formatAmount(record[key] as number | string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function gameMetricCellText(record: Record<string, any>, key: string) {
|
||||||
|
if (gameMetricIntegerColumns.has(key)) {
|
||||||
|
return formatInteger(record[key] as number | string);
|
||||||
|
}
|
||||||
|
if (gameMetricPercentColumns.has(key)) {
|
||||||
|
return formatPercent(record[key] as number | string);
|
||||||
|
}
|
||||||
|
if (gameMetricNumberColumns.has(key)) {
|
||||||
|
return formatAmount(record[key] as number | string);
|
||||||
|
}
|
||||||
|
return record[key] || '-';
|
||||||
|
}
|
||||||
|
|
||||||
function compareTableColumn(key: string) {
|
function compareTableColumn(key: string) {
|
||||||
return (current: Record<string, any>, next: Record<string, any>) => {
|
return (current: Record<string, any>, next: Record<string, any>) => {
|
||||||
if (metricColumns.has(key)) {
|
if (metricColumns.has(key)) {
|
||||||
@ -921,6 +1120,20 @@ watch(countryOptions, (options) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(activeTableTab, (value) => {
|
||||||
|
if (value === 'game') {
|
||||||
|
gameMetricPagination.current = 1;
|
||||||
|
void loadGameMetrics();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(selectedCountryCodes, () => {
|
||||||
|
if (activeTableTab.value === 'game') {
|
||||||
|
gameMetricPagination.current = 1;
|
||||||
|
void loadGameMetrics();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.addEventListener('fullscreenchange', syncFullscreenState);
|
document.addEventListener('fullscreenchange', syncFullscreenState);
|
||||||
loadDashboard();
|
loadDashboard();
|
||||||
@ -1004,7 +1217,24 @@ onBeforeUnmount(() => {
|
|||||||
show-search
|
show-search
|
||||||
style="width: 300px"
|
style="width: 300px"
|
||||||
/>
|
/>
|
||||||
<Button :loading="loading" type="primary" @click="loadDashboard">
|
<Select
|
||||||
|
v-if="activeTableTab === 'game'"
|
||||||
|
v-model:value="gameQuery.gameProvider"
|
||||||
|
:options="gameProviderOptions"
|
||||||
|
allow-clear
|
||||||
|
placeholder="游戏厂商"
|
||||||
|
style="width: 150px"
|
||||||
|
@change="handleGameMetricFilterChange"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
v-if="activeTableTab === 'game'"
|
||||||
|
v-model:value="gameQuery.gameKeyword"
|
||||||
|
allow-clear
|
||||||
|
placeholder="游戏 ID / 名称"
|
||||||
|
style="width: 220px"
|
||||||
|
@press-enter="handleGameMetricFilterChange"
|
||||||
|
/>
|
||||||
|
<Button :loading="loading || gameMetricLoading" type="primary" @click="loadDashboard">
|
||||||
查询
|
查询
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
@ -1105,12 +1335,43 @@ onBeforeUnmount(() => {
|
|||||||
<Empty v-else />
|
<Empty v-else />
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<Tabs v-model:activeKey="activeTableTab" class="dashboard-tabs" size="small">
|
<Tabs v-model:active-key="activeTableTab" class="dashboard-tabs" size="small">
|
||||||
<TabPane key="overview" tab="指标总览" />
|
<TabPane key="overview" tab="指标总览" />
|
||||||
<TabPane key="recharge" tab="充值相关数据" />
|
<TabPane key="recharge" tab="充值相关数据" />
|
||||||
|
<TabPane key="game" tab="游戏数据" />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<Table
|
<Table
|
||||||
v-if="records.length > 0"
|
v-if="activeTableTab === 'game'"
|
||||||
|
:columns="gameMetricColumns"
|
||||||
|
:data-source="gameMetricRecords"
|
||||||
|
:loading="gameMetricLoading"
|
||||||
|
:pagination="{
|
||||||
|
current: gameMetricPagination.current,
|
||||||
|
pageSize: gameMetricPagination.pageSize,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showTotal: showGameMetricTotal,
|
||||||
|
total: gameMetricPagination.total,
|
||||||
|
}"
|
||||||
|
:row-key="gameMetricRowKey"
|
||||||
|
:scroll="{ x: gameTableScrollX }"
|
||||||
|
size="small"
|
||||||
|
@change="handleGameMetricTableChange"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template
|
||||||
|
v-if="
|
||||||
|
gameMetricNumberColumns.has(String(column.dataIndex)) ||
|
||||||
|
gameMetricPercentColumns.has(String(column.dataIndex))
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span class="number-cell">
|
||||||
|
{{ gameMetricCellText(record, String(column.dataIndex)) }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</Table>
|
||||||
|
<Table
|
||||||
|
v-else-if="records.length > 0"
|
||||||
:columns="activeColumns"
|
:columns="activeColumns"
|
||||||
:data-source="records"
|
:data-source="records"
|
||||||
:pagination="{ pageSize: 20, showSizeChanger: true }"
|
:pagination="{ pageSize: 20, showSizeChanger: true }"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user