From 82022b86de29b0a95a52451b1ebe058f34acf167 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 1 May 2026 09:25:39 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(im):=20=E5=AE=9E=E7=8E=B0=20im?= =?UTF-8?q?=20=E7=9A=84=E9=A6=96=E9=A1=B5=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/im/manager/statistics/index.ts | 112 +++++------------- .../statistics/components/GroupSizeChart.vue | 47 +++++--- .../components/MessageTrendChart.vue | 2 +- .../components/MessageTypeChart.vue | 54 ++++++--- .../statistics/components/TopSendersChart.vue | 52 ++++---- .../statistics/components/UserTrendChart.vue | 2 +- src/views/im/manager/statistics/index.vue | 20 ++-- 7 files changed, 137 insertions(+), 152 deletions(-) diff --git a/src/api/im/manager/statistics/index.ts b/src/api/im/manager/statistics/index.ts index 4df7fca9b..675a5cd82 100644 --- a/src/api/im/manager/statistics/index.ts +++ b/src/api/im/manager/statistics/index.ts @@ -1,9 +1,4 @@ -// IM 数据看板 API -// -// vibe 阶段:所有方法用本地 mock(setTimeout + 随机数据)实现,不发真实请求。 -// 后端就绪后把 mockXxx 调用替换为 request.get(...) 一行即可。 -// -// import request from '@/config/axios' +import request from '@/config/axios' export interface ImStatisticsOverviewVO { totalUser: number @@ -24,99 +19,48 @@ export interface ImStatisticsTrendVO { series: Record } -export interface ImStatisticsDistributionVO { - messageTypeDistribution: { name: string; value: number }[] - groupSizeDistribution: { range: string; count: number }[] - topSenders: { userId: number; nickname: string; messageCount: number }[] +export interface ImStatisticsMessageTypeVO { + type: number // 参见 ImMessageTypeEnum 枚举类,由前端按 DICT_TYPE.IM_MESSAGE_TYPE 翻译 + value: number } -// ==================== mock helpers ==================== - -const fakePromise = (data: T, delay = 300): Promise => - new Promise((r) => setTimeout(() => r(data), delay)) - -const randomInt = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1)) + min - -const buildDates = (days: number): string[] => { - const dates: string[] = [] - const today = new Date() - for (let i = days - 1; i >= 0; i--) { - const d = new Date(today) - d.setDate(d.getDate() - i) - dates.push(d.toISOString().slice(0, 10)) - } - return dates +export interface ImStatisticsGroupSizeVO { + range: string + count: number } -// ==================== exposed APIs ==================== +export interface ImStatisticsTopSenderVO { + userId: number + nickname: string + messageCount: number +} // 获得 KPI 概览 export const getStatisticsOverview = (): Promise => { - return fakePromise({ - totalUser: 12345, - newUserToday: 23, - totalGroup: 678, - newGroupToday: 4, - activeUserDaily: 1023, - activeUserWeekly: 4567, - activeUserMonthly: 8901, - privateMessageToday: 8765, - groupMessageToday: 3210, - privateMessageYesterday: 7890, - groupMessageYesterday: 3000 - }) - // 真实请求版本:return request.get({ url: '/im/manager/statistics/overview' }) + return request.get({ url: '/im/manager/statistics/overview' }) } // 获得消息趋势(私聊 + 群聊双线) export const getMessageTrend = (days: number): Promise => { - const dates = buildDates(days) - return fakePromise({ - dates, - series: { - private: dates.map(() => randomInt(500, 2000)), - group: dates.map(() => randomInt(200, 1200)) - } - }) - // return request.get({ url: '/im/manager/statistics/message-trend', params: { days } }) + return request.get({ url: '/im/manager/statistics/message-trend', params: { days } }) } // 获得用户趋势(新增注册 + 日活双线) export const getUserTrend = (days: number): Promise => { - const dates = buildDates(days) - return fakePromise({ - dates, - series: { - register: dates.map(() => randomInt(5, 80)), - active: dates.map(() => randomInt(800, 1500)) - } - }) - // return request.get({ url: '/im/manager/statistics/user-trend', params: { days } }) + return request.get({ url: '/im/manager/statistics/user-trend', params: { days } }) } -// 获得分布数据(消息类型 / 群规模 / TOP 发送者) -export const getStatisticsDistribution = (): Promise => { - return fakePromise({ - messageTypeDistribution: [ - { name: '文本', value: 8000 }, - { name: '图片', value: 2400 }, - { name: '视频', value: 320 }, - { name: '语音', value: 980 }, - { name: '文件', value: 540 }, - { name: '位置', value: 65 }, - { name: '名片', value: 32 } - ], - groupSizeDistribution: [ - { range: '1-9 人', count: 320 }, - { range: '10-49 人', count: 240 }, - { range: '50-199 人', count: 95 }, - { range: '200+ 人', count: 23 } - ], - topSenders: Array.from({ length: 10 }, (_, i) => ({ - userId: 1000 + i, - nickname: `测试用户${i + 1}`, - messageCount: 1500 - i * 120 - })) - }) - // return request.get({ url: '/im/manager/statistics/distribution' }) +// 获得消息类型分布(最近 30 天) +export const getMessageTypeDistribution = (): Promise => { + return request.get({ url: '/im/manager/statistics/message-type-distribution' }) +} + +// 获得群规模分布 +export const getGroupSizeDistribution = (): Promise => { + return request.get({ url: '/im/manager/statistics/group-size-distribution' }) +} + +// 获得消息 TOP 发送者(最近 30 天) +export const getTopSenders = (): Promise => { + return request.get({ url: '/im/manager/statistics/top-senders' }) } diff --git a/src/views/im/manager/statistics/components/GroupSizeChart.vue b/src/views/im/manager/statistics/components/GroupSizeChart.vue index b9b399a1e..5a3bbfde0 100644 --- a/src/views/im/manager/statistics/components/GroupSizeChart.vue +++ b/src/views/im/manager/statistics/components/GroupSizeChart.vue @@ -1,47 +1,62 @@ diff --git a/src/views/im/manager/statistics/components/MessageTrendChart.vue b/src/views/im/manager/statistics/components/MessageTrendChart.vue index 31c5a5796..41bda096c 100644 --- a/src/views/im/manager/statistics/components/MessageTrendChart.vue +++ b/src/views/im/manager/statistics/components/MessageTrendChart.vue @@ -31,7 +31,7 @@ const buildOption = (dates: string[], priv: number[], grp: number[]): echarts.EC xAxis: { type: 'category', data: dates, - axisLabel: { formatter: (v: string) => v.substring(5) } + axisLabel: { formatter: (v: string) => v.slice(5, 10) } }, yAxis: { type: 'value', name: '消息量' }, series: [ diff --git a/src/views/im/manager/statistics/components/MessageTypeChart.vue b/src/views/im/manager/statistics/components/MessageTypeChart.vue index 7385c59fb..2a855c47c 100644 --- a/src/views/im/manager/statistics/components/MessageTypeChart.vue +++ b/src/views/im/manager/statistics/components/MessageTypeChart.vue @@ -1,47 +1,67 @@ diff --git a/src/views/im/manager/statistics/components/TopSendersChart.vue b/src/views/im/manager/statistics/components/TopSendersChart.vue index 52833d34d..c3e8fc80d 100644 --- a/src/views/im/manager/statistics/components/TopSendersChart.vue +++ b/src/views/im/manager/statistics/components/TopSendersChart.vue @@ -1,55 +1,67 @@ diff --git a/src/views/im/manager/statistics/components/UserTrendChart.vue b/src/views/im/manager/statistics/components/UserTrendChart.vue index 7428c0d2a..6d8865618 100644 --- a/src/views/im/manager/statistics/components/UserTrendChart.vue +++ b/src/views/im/manager/statistics/components/UserTrendChart.vue @@ -31,7 +31,7 @@ const buildOption = (dates: string[], reg: number[], act: number[]): echarts.ECh xAxis: { type: 'category', data: dates, - axisLabel: { formatter: (v: string) => v.substring(5) } + axisLabel: { formatter: (v: string) => v.slice(5, 10) } }, yAxis: [ { type: 'value', name: '新增注册', position: 'left' }, diff --git a/src/views/im/manager/statistics/index.vue b/src/views/im/manager/statistics/index.vue index d850263ce..1d65e42cb 100644 --- a/src/views/im/manager/statistics/index.vue +++ b/src/views/im/manager/statistics/index.vue @@ -1,6 +1,6 @@