Files
im_manager/web/src/views/imDashboard/index.vue
T

107 lines
3.4 KiB
Vue

<template>
<div>
<div class="n-layout-page-header">
<n-card :bordered="false" title="数据概览">
<template #header-extra>
<n-space align="center">
<n-select
v-if="isPlatformAdmin"
v-model:value="tenantId"
:options="imQueryTenantOptions"
class="tenant-select"
placeholder="请选择商户"
/>
<n-select v-model:value="days" :options="dayOptions" class="days-select" />
<n-button type="primary" :loading="loading" @click="loadDashboard">刷新</n-button>
</n-space>
</template>
</n-card>
</div>
<n-card :bordered="false" class="proCard">
<n-grid cols="1 s:2 m:3" responsive="screen" :x-gap="12" :y-gap="12">
<n-grid-item v-for="item in metrics" :key="item.key">
<n-statistic :label="item.label" :value="overview[item.key] || 0" />
</n-grid-item>
</n-grid>
<n-divider />
<n-h3>最近 {{ days }} 天增长趋势</n-h3>
<n-data-table
:columns="trendColumns"
:data="trends"
:loading="loading"
:pagination="false"
:bordered="false"
/>
</n-card>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue';
import { useMessage } from 'naive-ui';
import { useUserStore } from '@/store/modules/user';
import { Overview, Trends } from '@/api/imDashboard';
import { imQueryTenantOptions, loadImQueryTenantOptions } from '@/views/imAdminQueryShared';
const message = useMessage();
const userStore = useUserStore();
const isPlatformAdmin = computed(() => userStore.isCompanyDept);
const tenantId = ref(0);
const days = ref(7);
const loading = ref(false);
const overview = ref<Recordable>({});
const trends = ref<any[]>([]);
const dayOptions = [
{ label: '最近7天', value: 7 },
{ label: '最近14天', value: 14 },
{ label: '最近30天', value: 30 },
];
const metrics = [
{ key: 'totalUsers', label: '总用户数' },
{ key: 'activeUsers', label: '活跃用户' },
{ key: 'totalGroups', label: '总群组数' },
{ key: 'totalConversations', label: '总会话数' },
{ key: 'totalMessages', label: '总消息数' },
{ key: 'todayMessages', label: '今日消息' },
];
const trendColumns = [
{ title: '日期', key: 'date' },
{ title: '新增用户', key: 'userCount' },
{ title: '新增消息', key: 'messageCount' },
];
async function loadDashboard() {
if (isPlatformAdmin.value && !tenantId.value) {
message.warning('请选择商户');
return;
}
loading.value = true;
try {
const params = { tenantId: tenantId.value, days: days.value };
const [summary, trendRes] = await Promise.all([Overview(params), Trends(params)]);
overview.value = summary || {};
trends.value = trendRes?.list || [];
} finally {
loading.value = false;
}
}
onMounted(async () => {
if (isPlatformAdmin.value) {
await loadImQueryTenantOptions();
tenantId.value = imQueryTenantOptions.value[0]?.value || 0;
if (!tenantId.value) message.warning('暂无可用商户');
}
if (!isPlatformAdmin.value || tenantId.value) await loadDashboard();
});
</script>
<style lang="less" scoped>
.tenant-select {
width: 240px;
}
.days-select {
width: 120px;
}
</style>