Browse Source

增加统计指标

master
xsx 6 months ago
parent
commit
10cd561b9f
  1. 11
      im-admin-ui/src/api/im/group/index.ts
  2. 11
      im-admin-ui/src/api/im/groupMessage/index.ts
  3. 13
      im-admin-ui/src/api/im/privateMessage/index.ts
  4. 31
      im-admin-ui/src/api/im/user/index.ts
  5. 549
      im-admin-ui/src/views/index.vue
  6. 9
      im-admin/ruoyi-im/src/main/java/org/dromara/im/controller/ImGroupController.java
  7. 18
      im-admin/ruoyi-im/src/main/java/org/dromara/im/controller/ImGroupMessageController.java
  8. 19
      im-admin/ruoyi-im/src/main/java/org/dromara/im/controller/ImPrivateMessageController.java
  9. 35
      im-admin/ruoyi-im/src/main/java/org/dromara/im/controller/ImUserController.java
  10. 16
      im-admin/ruoyi-im/src/main/java/org/dromara/im/mapper/ImGroupMessageMapper.java
  11. 16
      im-admin/ruoyi-im/src/main/java/org/dromara/im/mapper/ImPrivateMessageMapper.java
  12. 17
      im-admin/ruoyi-im/src/main/java/org/dromara/im/mapper/ImUserMapper.java
  13. 11
      im-admin/ruoyi-im/src/main/java/org/dromara/im/service/IImGroupMessageService.java
  14. 5
      im-admin/ruoyi-im/src/main/java/org/dromara/im/service/IImGroupService.java
  15. 11
      im-admin/ruoyi-im/src/main/java/org/dromara/im/service/IImPrivateMessageService.java
  16. 33
      im-admin/ruoyi-im/src/main/java/org/dromara/im/service/IImUserService.java
  17. 14
      im-admin/ruoyi-im/src/main/java/org/dromara/im/service/impl/ImGroupMessageServiceImpl.java
  18. 9
      im-admin/ruoyi-im/src/main/java/org/dromara/im/service/impl/ImGroupServiceImpl.java
  19. 14
      im-admin/ruoyi-im/src/main/java/org/dromara/im/service/impl/ImPrivateMessageServiceImpl.java
  20. 64
      im-admin/ruoyi-im/src/main/java/org/dromara/im/service/impl/ImUserServiceImpl.java

11
im-admin-ui/src/api/im/group/index.ts

@ -61,3 +61,14 @@ export const findGroupByName = (name?: String): AxiosPromise<GroupVO[]> => {
});
};
/**
*
*/
export const getTotalGroupCount = (): AxiosPromise<number> => {
return request({
url: '/im/group/totalCount',
method: 'get'
});
};

11
im-admin-ui/src/api/im/groupMessage/index.ts

@ -27,3 +27,14 @@ export const getGroupMessage = (id: string | number): AxiosPromise<GroupMessageV
});
};
/**
*
* @param days
*/
export const getDailyGroupMessageCount = (days?: number): AxiosPromise<any[]> => {
return request({
url: '/im/groupMessage/dailyCount',
method: 'get',
params: { days }
});
};

13
im-admin-ui/src/api/im/privateMessage/index.ts

@ -27,3 +27,16 @@ export const getPrivateMessage = (id: string | number): AxiosPromise<PrivateMess
});
};
/**
*
* @param days
*/
export const getDailyMessageCount = (days?: number): AxiosPromise<any[]> => {
return request({
url: '/im/privateMessage/dailyCount',
method: 'get',
params: { days }
});
};

31
im-admin-ui/src/api/im/user/index.ts

@ -61,3 +61,34 @@ export const findUserByName = (name?: String): AxiosPromise<UserVO[]> => {
});
};
/**
*
* @param days
*/
export const getDailyRegistrationCount = (days?: number): AxiosPromise<any[]> => {
return request({
url: '/im/user/dailyRegistrationCount',
method: 'get',
params: { days }
});
};
/**
*
*/
export const getTotalUserCount = (): AxiosPromise<number> => {
return request({
url: '/im/user/totalCount',
method: 'get'
});
};
/**
*
*/
export const getActiveUserStats = (): AxiosPromise<any> => {
return request({
url: '/im/user/activeStats',
method: 'get'
});
};

549
im-admin-ui/src/views/index.vue

@ -1,81 +1,530 @@
<template>
<div class="app-container home">
<el-row :gutter="20">
<el-col :sm="24" :lg="12" style="padding-left: 20px">
<h2>盒子IM 后台管理系统</h2>
<h4>盒子IM是一个仿微信的聊天系统支持私聊群聊离线消息发送图片文件语音emoji表情音视频通话等功能</h4>
<!-- 统计指标卡片 -->
<el-row :gutter="20" style="margin-bottom: 20px">
<el-col :span="6">
<el-card class="statistics-card">
<div class="statistics-item">
<div class="statistics-icon" style="background-color: #409EFF;">
<el-icon size="24">
<User />
</el-icon>
</div>
<div class="statistics-content">
<div class="statistics-title">总用户量</div>
<div class="statistics-value">{{ totalUserCount }}</div>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="statistics-card">
<div class="statistics-item">
<div class="statistics-icon" style="background-color: #67C23A;">
<el-icon size="24">
<ChatDotRound />
</el-icon>
</div>
<div class="statistics-content">
<div class="statistics-title">总群组数量</div>
<div class="statistics-value">{{ totalGroupCount }}</div>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="statistics-card">
<div class="statistics-item">
<div class="statistics-icon" style="background-color: #E6A23C;">
<el-icon size="24">
<Timer />
</el-icon>
</div>
<div class="statistics-content">
<div class="statistics-title">日活用户</div>
<div class="statistics-value">{{ dailyActiveCount }}</div>
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card class="statistics-card">
<div class="statistics-item">
<div class="statistics-icon" style="background-color: #909399;">
<el-icon size="24">
<Clock />
</el-icon>
</div>
<div class="statistics-content">
<div class="statistics-title">月活用户</div>
<div class="statistics-value">{{ monthlyActiveCount }}</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-divider />
<!-- 统计图表 -->
<div class="chart-section">
<el-row :gutter="20">
<el-col :span="12">
<el-card>
<template #header>
<span>用户注册</span>
<el-select v-model="registrationSelectedDays" @change="loadRegistrationChartData"
style="width: 100px; float: right;" size="small">
<el-option label="7天" :value="7"></el-option>
<el-option label="15天" :value="15"></el-option>
<el-option label="30天" :value="30"></el-option>
</el-select>
</template>
<div ref="registrationChartContainer" style="width: 100%; height: 300px;"></div>
</el-card>
</el-col>
<el-col :span="12">
<el-card>
<template #header>
<span>消息统计</span>
<el-select v-model="selectedDays" @change="loadChartData" style="width: 100px; float: right;"
size="small">
<el-option label="7天" :value="7"></el-option>
<el-option label="15天" :value="15"></el-option>
<el-option label="30天" :value="30"></el-option>
</el-select>
</template>
<div ref="chartContainer" style="width: 100%; height: 300px;"></div>
</el-card>
</el-col>
</el-row>
</div>
</div>
</template>
<script setup name="Index" lang="ts">
const goTarget = (url: string) => {
window.open(url, '__blank');
import { ref, onMounted, nextTick, computed } from 'vue';
import * as echarts from 'echarts';
import { getDailyMessageCount } from '@/api/im/privateMessage';
import { getDailyGroupMessageCount } from '@/api/im/groupMessage';
import { getDailyRegistrationCount, getTotalUserCount, getActiveUserStats } from '@/api/im/user';
import { getTotalGroupCount } from '@/api/im/group';
import { User, ChatDotRound, Timer, Calendar, Clock } from '@element-plus/icons-vue';
const chartContainer = ref<HTMLElement>();
const selectedDays = ref(7);
let chartInstance: echarts.ECharts | null = null;
const registrationChartContainer = ref<HTMLElement>();
const registrationSelectedDays = ref(7);
let registrationChartInstance: echarts.ECharts | null = null;
//
const totalUserCount = ref(0);
//
const totalGroupCount = ref(0);
//
const dailyActiveCount = ref(0);
const weeklyActiveCount = ref(0);
const monthlyActiveCount = ref(0);
//
const loadTotalUserCount = async () => {
try {
const response = await getTotalUserCount();
totalUserCount.value = response.data;
} catch (error) {
console.error('加载总用户数量失败:', error);
totalUserCount.value = 0;
}
};
</script>
<style scoped lang="scss">
.home {
blockquote {
padding: 10px 20px;
margin: 0 0 20px;
font-size: 17.5px;
border-left: 5px solid #eee;
//
const loadTotalGroupCount = async () => {
try {
const response = await getTotalGroupCount();
totalGroupCount.value = response.data;
} catch (error) {
console.error('加载总群组数量失败:', error);
totalGroupCount.value = 0;
}
hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #eee;
};
//
const loadActiveUserStats = async () => {
try {
const response = await getActiveUserStats();
dailyActiveCount.value = response.data.dailyActive;
weeklyActiveCount.value = response.data.weeklyActive;
monthlyActiveCount.value = response.data.monthlyActive;
} catch (error) {
console.error('加载活跃用户统计失败:', error);
dailyActiveCount.value = 0;
weeklyActiveCount.value = 0;
monthlyActiveCount.value = 0;
}
};
//
const loadChartData = async () => {
try {
//
const [privateResponse, groupResponse] = await Promise.all([
getDailyMessageCount(selectedDays.value),
getDailyGroupMessageCount(selectedDays.value)
]);
const privateData = privateResponse.data;
const groupData = groupResponse.data;
//
const chartData = processChartData(privateData, groupData);
//
if (chartInstance) {
chartInstance.setOption({
xAxis: {
data: chartData.dates
},
series: [
{
data: chartData.privateCounts
},
{
data: chartData.groupCounts
}
]
});
}
} catch (error) {
console.error('加载图表数据失败:', error);
}
};
//
const processChartData = (privateData: any[], groupData: any[]) => {
const dates: string[] = [];
const privateCounts: number[] = [];
const groupCounts: number[] = [];
//
const today = new Date();
for (let i = selectedDays.value - 1; i >= 0; i--) {
const date = new Date(today);
date.setDate(date.getDate() - i);
const dateStr = date.toISOString().split('T')[0];
dates.push(dateStr);
//
const privateDayData = privateData.find(item => item.date === dateStr);
privateCounts.push(privateDayData ? parseInt(privateDayData.count) : 0);
//
const groupDayData = groupData.find(item => item.date === dateStr);
groupCounts.push(groupDayData ? parseInt(groupDayData.count) : 0);
}
return { dates, privateCounts, groupCounts };
};
//
const loadRegistrationChartData = async () => {
try {
const response = await getDailyRegistrationCount(registrationSelectedDays.value);
const data = response.data;
//
const chartData = processRegistrationChartData(data);
//
if (registrationChartInstance) {
registrationChartInstance.setOption({
xAxis: {
data: chartData.dates
},
series: [{
data: chartData.counts
}]
});
}
} catch (error) {
console.error('加载用户注册统计图表数据失败:', error);
}
.col-item {
margin-bottom: 20px;
};
//
const processRegistrationChartData = (data: any[]) => {
const dates: string[] = [];
const counts: number[] = [];
//
const today = new Date();
for (let i = registrationSelectedDays.value - 1; i >= 0; i--) {
const date = new Date(today);
date.setDate(date.getDate() - i);
const dateStr = date.toISOString().split('T')[0];
dates.push(dateStr);
//
const dayData = data.find(item => item.date === dateStr);
counts.push(dayData ? parseInt(dayData.count) : 0);
}
ul {
padding: 0;
margin: 0;
return { dates, counts };
};
//
const initChart = async () => {
await nextTick();
if (chartContainer.value) {
chartInstance = echarts.init(chartContainer.value);
const option = {
title: {
text: '每日消息量趋势对比',
left: 'center'
},
tooltip: {
trigger: 'axis',
formatter: (params: any) => {
let result = `${params[0].name}<br/>`;
params.forEach((param: any) => {
result += `${param.seriesName}: ${param.value}<br/>`;
});
return result;
}
},
legend: {
data: ['私聊消息', '群聊消息'],
top: 30
},
xAxis: {
type: 'category',
data: [],
axisLabel: {
formatter: (value: string) => {
return value.substring(5); // -
}
}
},
yAxis: {
type: 'value',
name: '消息量'
},
series: [
{
name: '私聊消息',
type: 'line',
data: [],
smooth: true,
itemStyle: {
color: '#409EFF'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: 'rgba(64, 158, 255, 0.3)'
}, {
offset: 1, color: 'rgba(64, 158, 255, 0.1)'
}]
}
}
},
{
name: '群聊消息',
type: 'line',
data: [],
smooth: true,
itemStyle: {
color: '#67C23A'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: 'rgba(103, 194, 58, 0.3)'
}, {
offset: 1, color: 'rgba(103, 194, 58, 0.1)'
}]
}
}
}
],
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
}
};
chartInstance.setOption(option);
//
await loadChartData();
}
};
font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 13px;
color: #676a6c;
overflow-x: hidden;
onMounted(() => {
loadTotalUserCount();
loadTotalGroupCount();
loadActiveUserStats();
initChart();
initRegistrationChart();
});
ul {
list-style-type: none;
//
const initRegistrationChart = async () => {
await nextTick();
if (registrationChartContainer.value) {
registrationChartInstance = echarts.init(registrationChartContainer.value);
const option = {
title: {
text: '每日用户注册趋势',
left: 'center'
},
tooltip: {
trigger: 'axis',
formatter: (params: any) => {
const data = params[0];
return `${data.name}<br/>注册用户: ${data.value}`;
}
},
xAxis: {
type: 'category',
data: [],
axisLabel: {
formatter: (value: string) => {
return value.substring(5); // -
}
}
},
yAxis: {
type: 'value',
name: '注册用户数'
},
series: [{
name: '注册用户',
type: 'line',
data: [],
smooth: true,
itemStyle: {
color: '#E6A23C'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: 'rgba(230, 162, 60, 0.3)'
}, {
offset: 1, color: 'rgba(230, 162, 60, 0.1)'
}]
}
}
}],
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
}
};
registrationChartInstance.setOption(option);
//
await loadRegistrationChartData();
}
};
</script>
<style scoped lang="scss">
.app-container {
padding: 20px;
}
h4 {
margin-top: 0px;
//
.statistics-card {
border-radius: 8px;
border: 1px solid #f0f2f5;
:deep(.el-card__body) {
padding: 16px;
}
}
h2 {
margin-top: 10px;
font-size: 26px;
font-weight: 100;
.statistics-item {
display: flex;
align-items: center;
.statistics-icon {
width: 48px;
height: 48px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
color: white;
}
p {
margin-top: 10px;
.statistics-content {
flex: 1;
.statistics-title {
font-size: 13px;
color: #8c8c8c;
margin-bottom: 4px;
}
b {
font-weight: 700;
.statistics-value {
font-size: 24px;
font-weight: 600;
color: #262626;
line-height: 1;
}
}
}
//
.chart-section {
margin-top: 24px;
.el-card {
border-radius: 8px;
border: 1px solid #f0f2f5;
.update-log {
ol {
display: block;
list-style-type: decimal;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0;
margin-inline-end: 0;
padding-inline-start: 40px;
:deep(.el-card__body) {
padding: 16px;
}
}
}
//
:deep(.el-card__header) {
border-bottom: 1px solid #f0f2f5;
padding: 12px 16px;
span {
font-size: 14px;
font-weight: 500;
color: #262626;
}
}
</style>

9
im-admin/ruoyi-im/src/main/java/org/dromara/im/controller/ImGroupController.java

@ -104,4 +104,13 @@ public class ImGroupController extends BaseController {
public TableDataInfo<ImGroupMemberVo> findMembers( ImGroupMemberBo bo, PageQuery pageQuery) {
return groupMemberService.queryPageList(bo,pageQuery);
}
/**
* 获取总群组数量
*/
@SaCheckPermission("im:group:list")
@GetMapping("/totalCount")
public R<Long> getTotalGroupCount() {
return R.ok(groupService.getTotalGroupCount());
}
}

18
im-admin/ruoyi-im/src/main/java/org/dromara/im/controller/ImGroupMessageController.java

@ -11,10 +11,10 @@ import org.dromara.im.domain.bo.ImGroupMessageBo;
import org.dromara.im.domain.vo.ImGroupMessageVo;
import org.dromara.im.service.IImGroupMessageService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 群消息
@ -51,5 +51,15 @@ public class ImGroupMessageController extends BaseController {
return R.ok(imGroupMessageService.queryById(id));
}
/**
* 按天统计群聊消息量
*
* @param days 统计天数默认7天
*/
@SaCheckPermission("im:groupMessage:list")
@GetMapping("/dailyCount")
public R<List<Map<String, Object>>> getDailyGroupMessageCount(@RequestParam(defaultValue = "7") Integer days) {
return R.ok(imGroupMessageService.getDailyGroupMessageCount(days));
}
}

19
im-admin/ruoyi-im/src/main/java/org/dromara/im/controller/ImPrivateMessageController.java

@ -11,10 +11,10 @@ import org.dromara.im.domain.bo.ImPrivateMessageBo;
import org.dromara.im.domain.vo.ImPrivateMessageVo;
import org.dromara.im.service.IImPrivateMessageService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 私聊消息
@ -52,4 +52,15 @@ public class ImPrivateMessageController extends BaseController {
return R.ok(imPrivateMessageService.queryById(id));
}
/**
* 按天统计私聊消息量
*
* @param days 统计天数默认7天
*/
@SaCheckPermission("im:privateMessage:list")
@GetMapping("/dailyCount")
public R<List<Map<String, Object>>> getDailyMessageCount(@RequestParam(value = "days", defaultValue = "7") Integer days) {
return R.ok(imPrivateMessageService.getDailyMessageCount(days));
}
}

35
im-admin/ruoyi-im/src/main/java/org/dromara/im/controller/ImUserController.java

@ -22,7 +22,9 @@ import org.dromara.im.util.CommaTextUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@ -101,4 +103,37 @@ public class ImUserController extends BaseController {
List<ImUserVo> vos = userService.findByIds(arrIds);
return R.ok(vos);
}
/**
* 按天统计用户注册数量
*
* @param days 统计天数默认7天
*/
@SaCheckPermission("im:user:list")
@GetMapping("/dailyRegistrationCount")
public R<List<Map<String, Object>>> getDailyRegistrationCount(@RequestParam(value = "days", defaultValue = "7") Integer days) {
return R.ok(userService.getDailyRegistrationCount(days));
}
/**
* 获取总用户数量
*/
@SaCheckPermission("im:user:list")
@GetMapping("/totalCount")
public R<Long> getTotalUserCount() {
return R.ok(userService.getTotalUserCount());
}
/**
* 获取活跃用户统计日活周活月活
*/
@SaCheckPermission("im:user:list")
@GetMapping("/activeStats")
public R<Map<String, Long>> getActiveUserStats() {
Map<String, Long> stats = new HashMap<>();
stats.put("dailyActive", userService.getDailyActiveUserCount());
stats.put("weeklyActive", userService.getWeeklyActiveUserCount());
stats.put("monthlyActive", userService.getMonthlyActiveUserCount());
return R.ok(stats);
}
}

16
im-admin/ruoyi-im/src/main/java/org/dromara/im/mapper/ImGroupMessageMapper.java

@ -1,9 +1,14 @@
package org.dromara.im.mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.im.domain.ImGroupMessage;
import org.dromara.im.domain.vo.ImGroupMessageVo;
import java.util.List;
import java.util.Map;
/**
* 群消息Mapper接口
*
@ -12,4 +17,15 @@ import org.dromara.im.domain.vo.ImGroupMessageVo;
*/
public interface ImGroupMessageMapper extends BaseMapperPlus<ImGroupMessage, ImGroupMessageVo> {
/**
* 按天统计群聊消息量
* @param days 统计天数
* @return 统计结果
*/
@Select("SELECT DATE(send_time) as date, COUNT(*) as count " +
"FROM im_group_message " +
"WHERE send_time >= DATE_SUB(CURDATE(), INTERVAL #{days} DAY) " +
"GROUP BY DATE(send_time) " +
"ORDER BY date ASC")
List<Map<String, Object>> getDailyGroupMessageCount(@Param("days") Integer days);
}

16
im-admin/ruoyi-im/src/main/java/org/dromara/im/mapper/ImPrivateMessageMapper.java

@ -1,9 +1,14 @@
package org.dromara.im.mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.im.domain.ImPrivateMessage;
import org.dromara.im.domain.vo.ImPrivateMessageVo;
import java.util.List;
import java.util.Map;
/**
* 私聊消息Mapper接口
*
@ -12,4 +17,15 @@ import org.dromara.im.domain.vo.ImPrivateMessageVo;
*/
public interface ImPrivateMessageMapper extends BaseMapperPlus<ImPrivateMessage, ImPrivateMessageVo> {
/**
* 按天统计私聊消息量
* @param days 统计天数
* @return 统计结果
*/
@Select("SELECT DATE(send_time) as date, COUNT(*) as count " +
"FROM im_private_message " +
"WHERE send_time >= DATE_SUB(CURDATE(), INTERVAL #{days} DAY) " +
"GROUP BY DATE(send_time) " +
"ORDER BY date ASC")
List<Map<String, Object>> getDailyMessageCount(@Param("days") Integer days);
}

17
im-admin/ruoyi-im/src/main/java/org/dromara/im/mapper/ImUserMapper.java

@ -1,9 +1,14 @@
package org.dromara.im.mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.im.domain.ImUser;
import org.dromara.im.domain.vo.ImUserVo;
import java.util.List;
import java.util.Map;
/**
* 用户Mapper接口
*
@ -12,4 +17,16 @@ import org.dromara.im.domain.vo.ImUserVo;
*/
public interface ImUserMapper extends BaseMapperPlus<ImUser, ImUserVo> {
/**
* 按天统计用户注册数量
* @param days 统计天数
* @return 统计结果
*/
@Select("SELECT DATE(created_time) as date, COUNT(*) as count " +
"FROM im_user " +
"WHERE created_time >= DATE_SUB(CURDATE(), INTERVAL #{days} DAY) " +
"GROUP BY DATE(created_time) " +
"ORDER BY date ASC")
List<Map<String, Object>> getDailyRegistrationCount(@Param("days") Integer days);
}

11
im-admin/ruoyi-im/src/main/java/org/dromara/im/service/IImGroupMessageService.java

@ -5,6 +5,9 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.im.domain.bo.ImGroupMessageBo;
import org.dromara.im.domain.vo.ImGroupMessageVo;
import java.util.List;
import java.util.Map;
/**
* 群消息Service接口
*
@ -30,6 +33,12 @@ public interface IImGroupMessageService {
*/
TableDataInfo<ImGroupMessageVo> queryPageList(ImGroupMessageBo bo, PageQuery pageQuery);
/**
* 按天统计群聊消息数量
*
* @param days 统计天数
* @return 按天统计数据
*/
List<Map<String, Object>> getDailyGroupMessageCount(Integer days);
}

5
im-admin/ruoyi-im/src/main/java/org/dromara/im/service/IImGroupService.java

@ -65,6 +65,11 @@ public interface IImGroupService {
List<ImGroupVo> findByName(String name);
/**
* 获取总群组数量
* @return 总群组数量
*/
Long getTotalGroupCount();
}

11
im-admin/ruoyi-im/src/main/java/org/dromara/im/service/IImPrivateMessageService.java

@ -5,6 +5,9 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.im.domain.bo.ImPrivateMessageBo;
import org.dromara.im.domain.vo.ImPrivateMessageVo;
import java.util.List;
import java.util.Map;
/**
* 私聊消息Service接口
*
@ -31,6 +34,12 @@ public interface IImPrivateMessageService {
TableDataInfo<ImPrivateMessageVo> queryPageList(ImPrivateMessageBo bo, PageQuery pageQuery);
/**
* 按天统计私聊消息量
*
* @param days 统计天数
* @return 统计结果
*/
List<Map<String, Object>> getDailyMessageCount(Integer days);
}

33
im-admin/ruoyi-im/src/main/java/org/dromara/im/service/IImUserService.java

@ -8,6 +8,7 @@ import org.dromara.im.domain.dto.ImUserUnbanDto;
import org.dromara.im.domain.vo.ImUserVo;
import java.util.List;
import java.util.Map;
/**
* 用户Service接口
@ -70,4 +71,36 @@ public interface IImUserService {
*/
List<ImUserVo> findByIds(List<Long> ids);
/**
* 按天统计用户注册数量
*
* @param days 统计天数
* @return 统计结果
*/
List<Map<String, Object>> getDailyRegistrationCount(Integer days);
/**
* 获取总用户数量
* @return 总用户数量
*/
Long getTotalUserCount();
/**
* 获取日活跃用户数量最近1天
* @return 日活跃用户数量
*/
Long getDailyActiveUserCount();
/**
* 获取周活跃用户数量最近7天
* @return 周活跃用户数量
*/
Long getWeeklyActiveUserCount();
/**
* 获取月活跃用户数量最近30天
* @return 月活跃用户数量
*/
Long getMonthlyActiveUserCount();
}

14
im-admin/ruoyi-im/src/main/java/org/dromara/im/service/impl/ImGroupMessageServiceImpl.java

@ -16,6 +16,7 @@ import org.dromara.im.mapper.ImGroupMessageMapper;
import org.dromara.im.service.IImGroupMessageService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
@ -56,6 +57,19 @@ public class ImGroupMessageServiceImpl implements IImGroupMessageService {
return TableDataInfo.build(result);
}
/**
* 按天统计群聊消息数量
*
* @param days 统计天数
* @return 按天统计数据
*/
@Override
public List<Map<String, Object>> getDailyGroupMessageCount(Integer days) {
if (days == null || days <= 0) {
days = 7; // 默认统计最近7天
}
return baseMapper.getDailyGroupMessageCount(days);
}
private LambdaQueryWrapper<ImGroupMessage> buildQueryWrapper(ImGroupMessageBo bo) {
Map<String, Object> params = bo.getParams();

9
im-admin/ruoyi-im/src/main/java/org/dromara/im/service/impl/ImGroupServiceImpl.java

@ -128,6 +128,15 @@ public class ImGroupServiceImpl implements IImGroupService {
return baseMapper.selectVoList(queryWrapper);
}
/**
* 获取总群组数量
* @return 总群组数量
*/
@Override
public Long getTotalGroupCount() {
return baseMapper.selectCount(null);
}
private LambdaQueryWrapper<ImGroup> buildQueryWrapper(ImGroupBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<ImGroup> wrapper = Wrappers.lambdaQuery();

14
im-admin/ruoyi-im/src/main/java/org/dromara/im/service/impl/ImPrivateMessageServiceImpl.java

@ -16,6 +16,7 @@ import org.dromara.im.mapper.ImPrivateMessageMapper;
import org.dromara.im.service.IImPrivateMessageService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -57,6 +58,19 @@ public class ImPrivateMessageServiceImpl implements IImPrivateMessageService {
return TableDataInfo.build(result);
}
/**
* 按天统计私聊消息量
*
* @param days 统计天数
* @return 统计结果
*/
@Override
public List<Map<String, Object>> getDailyMessageCount(Integer days) {
if (days == null || days <= 0) {
days = 7; // 默认统计最近7天
}
return baseMapper.getDailyMessageCount(days);
}
private LambdaQueryWrapper<ImPrivateMessage> buildQueryWrapper(ImPrivateMessageBo bo) {
Map<String, Object> params = bo.getParams();

64
im-admin/ruoyi-im/src/main/java/org/dromara/im/service/impl/ImUserServiceImpl.java

@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.logging.log4j.util.Strings;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
@ -23,7 +24,9 @@ import org.dromara.im.mq.ImRedisMQTemplate;
import org.dromara.im.service.IImUserService;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 用户Service业务层处理
@ -125,4 +128,65 @@ public class ImUserServiceImpl implements IImUserService {
queryWrapper.in(ImUser::getId, ids);
return baseMapper.selectVoList(queryWrapper);
}
/**
* 按天统计用户注册数量
*
* @param days 统计天数
* @return 统计结果
*/
@Override
public List<Map<String, Object>> getDailyRegistrationCount(Integer days) {
if (days == null || days <= 0) {
days = 7; // 默认统计最近7天
}
return baseMapper.getDailyRegistrationCount(days);
}
/**
* 获取总用户数量
*
* @return 总用户数量
*/
@Override
public Long getTotalUserCount() {
return baseMapper.selectCount(null);
}
/**
* 获取日活跃用户数量最近1天
*
* @return 日活跃用户数量
*/
@Override
public Long getDailyActiveUserCount() {
LambdaQueryWrapper<ImUser> wrapper = Wrappers.lambdaQuery();
wrapper.ge(ImUser::getLastLoginTime, DateUtils.addMonths(new Date(), -1));
return baseMapper.selectCount(wrapper);
}
/**
* 获取周活跃用户数量最近7天
*
* @return 周活跃用户数量
*/
@Override
public Long getWeeklyActiveUserCount() {
LambdaQueryWrapper<ImUser> wrapper = Wrappers.lambdaQuery();
wrapper.ge(ImUser::getLastLoginTime, DateUtils.addMonths(new Date(), -7));
return baseMapper.selectCount(wrapper);
}
/**
* 获取月活跃用户数量最近30天
*
* @return 月活跃用户数量
*/
@Override
public Long getMonthlyActiveUserCount() {
LambdaQueryWrapper<ImUser> wrapper = Wrappers.lambdaQuery();
wrapper.ge(ImUser::getLastLoginTime, DateUtils.addMonths(new Date(), -30));
return baseMapper.selectCount(wrapper);
}
}

Loading…
Cancel
Save