feat: 完善仪表盘访客地域分布区块内容
This commit is contained in:
parent
83b2e2a7c0
commit
dc1691f019
@ -17,6 +17,7 @@
|
||||
package top.charles7c.cnadmin.monitor.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import top.charles7c.cnadmin.common.base.BaseMapper;
|
||||
import top.charles7c.cnadmin.monitor.model.entity.LogDO;
|
||||
@ -44,4 +45,11 @@ public interface LogMapper extends BaseMapper<LogDO> {
|
||||
* @return 仪表盘热门模块列表
|
||||
*/
|
||||
List<DashboardPopularModuleVO> selectListDashboardPopularModule();
|
||||
|
||||
/**
|
||||
* 查询仪表盘访客地域分布信息
|
||||
*
|
||||
* @return 仪表盘访客地域分布信息
|
||||
*/
|
||||
List<Map<String, Object>> selectListDashboardGeoDistribution();
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.cnadmin.monitor.model.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 仪表盘-访客地域分布信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/9/9 12:07
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "仪表盘-访客地域分布信息")
|
||||
public class DashboardGeoDistributionVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 地点列表
|
||||
*/
|
||||
@Schema(description = "地点列表", example = "[\"中国北京北京市\",\"中国广东省深圳市\"]")
|
||||
private List<String> locations;
|
||||
|
||||
/**
|
||||
* 地点 IP 统计信息
|
||||
*/
|
||||
@Schema(description = "地点 IP 统计信息",
|
||||
example = "[{\"name\":\"中国北京北京市\",\"value\":1000},{\"name\":\"中国广东省深圳市\",\"value\": 500}]")
|
||||
private List<Map<String, Object>> locationIpStatistics;
|
||||
}
|
@ -32,6 +32,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
* @since 2023/9/9 9:52
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "仪表盘-热门模块信息")
|
||||
public class DashboardPopularModuleVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -32,6 +32,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
* @since 2023/9/8 21:32
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "仪表盘-总计信息")
|
||||
public class DashboardTotalVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -18,6 +18,7 @@ package top.charles7c.cnadmin.monitor.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import top.charles7c.cnadmin.monitor.model.vo.DashboardGeoDistributionVO;
|
||||
import top.charles7c.cnadmin.monitor.model.vo.DashboardPopularModuleVO;
|
||||
import top.charles7c.cnadmin.monitor.model.vo.DashboardTotalVO;
|
||||
import top.charles7c.cnadmin.system.model.vo.DashboardAnnouncementVO;
|
||||
@ -44,6 +45,13 @@ public interface DashboardService {
|
||||
*/
|
||||
List<DashboardPopularModuleVO> listPopularModule();
|
||||
|
||||
/**
|
||||
* 查询访客地域分布信息
|
||||
*
|
||||
* @return 访客地域分布信息
|
||||
*/
|
||||
DashboardGeoDistributionVO getGeoDistribution();
|
||||
|
||||
/**
|
||||
* 查询公告列表
|
||||
*
|
||||
|
@ -17,6 +17,7 @@
|
||||
package top.charles7c.cnadmin.monitor.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import top.charles7c.cnadmin.common.model.query.PageQuery;
|
||||
import top.charles7c.cnadmin.common.model.vo.PageDataVO;
|
||||
@ -87,5 +88,12 @@ public interface LogService {
|
||||
*
|
||||
* @return 仪表盘热门模块列表
|
||||
*/
|
||||
List<DashboardPopularModuleVO> listPopularModule();
|
||||
List<DashboardPopularModuleVO> listDashboardPopularModule();
|
||||
|
||||
/**
|
||||
* 查询仪表盘访客地域分布信息
|
||||
*
|
||||
* @return 仪表盘访客地域分布信息
|
||||
*/
|
||||
List<Map<String, Object>> listDashboardGeoDistribution();
|
||||
}
|
||||
|
@ -18,14 +18,18 @@ package top.charles7c.cnadmin.monitor.service.impl;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
|
||||
import top.charles7c.cnadmin.monitor.model.vo.DashboardGeoDistributionVO;
|
||||
import top.charles7c.cnadmin.monitor.model.vo.DashboardPopularModuleVO;
|
||||
import top.charles7c.cnadmin.monitor.model.vo.DashboardTotalVO;
|
||||
import top.charles7c.cnadmin.monitor.service.DashboardService;
|
||||
@ -61,7 +65,7 @@ public class DashboardServiceImpl implements DashboardService {
|
||||
|
||||
@Override
|
||||
public List<DashboardPopularModuleVO> listPopularModule() {
|
||||
List<DashboardPopularModuleVO> popularModuleList = logService.listPopularModule();
|
||||
List<DashboardPopularModuleVO> popularModuleList = logService.listDashboardPopularModule();
|
||||
for (DashboardPopularModuleVO popularModule : popularModuleList) {
|
||||
Long todayPvCount = popularModule.getTodayPvCount();
|
||||
Long yesterdayPvCount = popularModule.getYesterdayPvCount();
|
||||
@ -73,6 +77,16 @@ public class DashboardServiceImpl implements DashboardService {
|
||||
return popularModuleList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DashboardGeoDistributionVO getGeoDistribution() {
|
||||
List<Map<String, Object>> locationIpStatistics = logService.listDashboardGeoDistribution();
|
||||
DashboardGeoDistributionVO geoDistribution = new DashboardGeoDistributionVO();
|
||||
geoDistribution.setLocationIpStatistics(locationIpStatistics);
|
||||
geoDistribution.setLocations(
|
||||
locationIpStatistics.stream().map(m -> Convert.toStr(m.get("name"))).collect(Collectors.toList()));
|
||||
return geoDistribution;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DashboardAnnouncementVO> listAnnouncement() {
|
||||
return announcementService.listDashboard();
|
||||
|
@ -17,6 +17,7 @@
|
||||
package top.charles7c.cnadmin.monitor.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -151,10 +152,15 @@ public class LogServiceImpl implements LogService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DashboardPopularModuleVO> listPopularModule() {
|
||||
public List<DashboardPopularModuleVO> listDashboardPopularModule() {
|
||||
return logMapper.selectListDashboardPopularModule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> listDashboardGeoDistribution() {
|
||||
return logMapper.selectListDashboardGeoDistribution();
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充数据
|
||||
*
|
||||
|
@ -22,4 +22,14 @@
|
||||
ORDER BY `pvCount` DESC
|
||||
LIMIT 10
|
||||
</select>
|
||||
|
||||
<select id="selectListDashboardGeoDistribution" resultType="java.util.Map">
|
||||
SELECT
|
||||
`location` AS name,
|
||||
COUNT(DISTINCT `client_ip`) AS value
|
||||
FROM `sys_log`
|
||||
GROUP BY `location`
|
||||
ORDER BY COUNT(DISTINCT `client_ip`) DESC
|
||||
LIMIT 10
|
||||
</select>
|
||||
</mapper>
|
@ -31,7 +31,7 @@ import top.charles7c.cnadmin.system.enums.AnnouncementTypeEnum;
|
||||
* @since 2023/8/20 10:55
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "仪表盘公告信息")
|
||||
@Schema(description = "仪表盘-公告信息")
|
||||
public class DashboardAnnouncementVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -16,6 +16,11 @@ export interface DashboardPopularModuleRecord {
|
||||
newPvFromYesterday: number;
|
||||
}
|
||||
|
||||
export interface DashboardGeoDistributionRecord {
|
||||
locations: string[];
|
||||
locationIpStatistics: [];
|
||||
}
|
||||
|
||||
export interface DashboardAnnouncementRecord {
|
||||
id: string;
|
||||
title: string;
|
||||
@ -32,6 +37,12 @@ export function listPopularModule() {
|
||||
);
|
||||
}
|
||||
|
||||
export function getGeoDistribution() {
|
||||
return axios.get<DashboardGeoDistributionRecord>(
|
||||
`${BASE_URL}/geo/distribution`
|
||||
);
|
||||
}
|
||||
|
||||
export function listAnnouncement() {
|
||||
return axios.get<DashboardAnnouncementRecord[]>(`${BASE_URL}/announcement`);
|
||||
}
|
||||
@ -43,15 +54,4 @@ export interface ContentDataRecord {
|
||||
|
||||
export function queryContentData() {
|
||||
return axios.get<ContentDataRecord[]>('/api/content-data');
|
||||
}
|
||||
|
||||
export interface PopularRecord {
|
||||
key: number;
|
||||
clickNumber: string;
|
||||
title: string;
|
||||
increases: number;
|
||||
}
|
||||
|
||||
export function queryPopularList(params: { type: string }) {
|
||||
return axios.get<TableData[]>('/api/popular/list', { params });
|
||||
}
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
<template>
|
||||
<a-spin :loading="loading" style="width: 100%">
|
||||
<a-card
|
||||
class="general-card"
|
||||
:header-style="{ paddingBottom: '0' }"
|
||||
:body-style="{
|
||||
padding: '20px',
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
{{ $t('workplace.categoriesPercent') }}
|
||||
</template>
|
||||
<Chart height="310px" :option="chartOption" />
|
||||
</a-card>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import useLoading from '@/hooks/loading';
|
||||
import useChartOption from '@/hooks/chart-option';
|
||||
|
||||
const { loading } = useLoading();
|
||||
const { chartOption } = useChartOption((isDark) => {
|
||||
// echarts support https://echarts.apache.org/zh/theme-builder.html
|
||||
// It's not used here
|
||||
return {
|
||||
legend: {
|
||||
left: 'center',
|
||||
data: ['纯文本', '图文类', '视频类'],
|
||||
bottom: 0,
|
||||
icon: 'circle',
|
||||
itemWidth: 8,
|
||||
textStyle: {
|
||||
color: isDark ? 'rgba(255, 255, 255, 0.7)' : '#4E5969',
|
||||
},
|
||||
itemStyle: {
|
||||
borderWidth: 0,
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
show: true,
|
||||
trigger: 'item',
|
||||
},
|
||||
graphic: {
|
||||
elements: [
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: '40%',
|
||||
style: {
|
||||
text: '内容量',
|
||||
textAlign: 'center',
|
||||
fill: isDark ? '#ffffffb3' : '#4E5969',
|
||||
fontSize: 14,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: '50%',
|
||||
style: {
|
||||
text: '928,531',
|
||||
textAlign: 'center',
|
||||
fill: isDark ? '#ffffffb3' : '#1D2129',
|
||||
fontSize: 16,
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['50%', '70%'],
|
||||
center: ['50%', '50%'],
|
||||
label: {
|
||||
formatter: '{d}%',
|
||||
fontSize: 14,
|
||||
color: isDark ? 'rgba(255, 255, 255, 0.7)' : '#4E5969',
|
||||
},
|
||||
itemStyle: {
|
||||
borderColor: isDark ? '#232324' : '#fff',
|
||||
borderWidth: 1,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: [148564],
|
||||
name: '纯文本',
|
||||
itemStyle: {
|
||||
color: isDark ? '#3D72F6' : '#249EFF',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: [334271],
|
||||
name: '图文类',
|
||||
itemStyle: {
|
||||
color: isDark ? '#A079DC' : '#313CA9',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: [445694],
|
||||
name: '视频类',
|
||||
itemStyle: {
|
||||
color: isDark ? '#6CAAF5' : '#21CCFF',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less"></style>
|
@ -3,8 +3,8 @@
|
||||
class="general-card"
|
||||
:title="$t('workplace.docs')"
|
||||
:header-style="{ paddingBottom: 0 }"
|
||||
:body-style="{ paddingTop: 0 }"
|
||||
style="height: 166px"
|
||||
:body-style="{ paddingTop: '10px', paddingBottom: '10px' }"
|
||||
style="height: 198px"
|
||||
>
|
||||
<template #extra>
|
||||
<a-link href="https://doc.charles7c.top" target="_blank" rel="noopener">{{
|
||||
@ -48,6 +48,24 @@
|
||||
{{ $t('workplace.docs.changelog') }}
|
||||
</a-link>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-link
|
||||
href="https://blog.charles7c.top"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
{{ $t('workplace.docs.authorSite') }}👋
|
||||
</a-link>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-link
|
||||
href="https://doc.charles7c.top/require.html"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
{{ $t('workplace.docs.require') }}✨
|
||||
</a-link>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</template>
|
||||
@ -58,3 +76,4 @@
|
||||
color: rgb(var(--gray-8));
|
||||
}
|
||||
</style>
|
||||
<script setup lang="ts"></script>
|
@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<a-spin :loading="loading" style="width: 100%">
|
||||
<a-card
|
||||
class="general-card"
|
||||
:header-style="{ paddingBottom: '0' }"
|
||||
:body-style="{
|
||||
padding: '0 20px',
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
{{ $t('workplace.geoDistribution') }}
|
||||
</template>
|
||||
<Chart height="480px" :option="chartOption" />
|
||||
</a-card>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import useChartOption from '@/hooks/chart-option';
|
||||
import {
|
||||
DashboardGeoDistributionRecord,
|
||||
getGeoDistribution,
|
||||
} from '@/api/common/dashboard';
|
||||
|
||||
const { loading, setLoading } = useLoading();
|
||||
const statisticsData = ref<DashboardGeoDistributionRecord>({
|
||||
locations: [],
|
||||
locationIpStatistics: [],
|
||||
});
|
||||
|
||||
/**
|
||||
* 查询访客地域分布信息
|
||||
*/
|
||||
const getData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { data } = await getGeoDistribution();
|
||||
statisticsData.value = data;
|
||||
} catch (err) {
|
||||
// you can report use errorHandler or other
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
getData();
|
||||
|
||||
const { chartOption } = useChartOption((isDark) => {
|
||||
// echarts support https://echarts.apache.org/zh/theme-builder.html
|
||||
// It's not used here
|
||||
return {
|
||||
legend: {
|
||||
left: 'center',
|
||||
data: statisticsData.value.locations,
|
||||
bottom: -5,
|
||||
icon: 'circle',
|
||||
itemStyle: {
|
||||
borderWidth: 0,
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
show: true,
|
||||
trigger: 'item',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '70%',
|
||||
label: {
|
||||
formatter: '{d}%',
|
||||
fontSize: 14,
|
||||
color: isDark ? 'rgba(255, 255, 255, 0.7)' : '#4E5969',
|
||||
},
|
||||
itemStyle: {
|
||||
borderColor: isDark ? '#232324' : '#fff',
|
||||
borderWidth: 1,
|
||||
},
|
||||
data: statisticsData.value.locationIpStatistics,
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.general-card {
|
||||
min-height: 566px;
|
||||
}
|
||||
</style>
|
@ -3,7 +3,7 @@
|
||||
<a-card
|
||||
class="general-card"
|
||||
:header-style="{ paddingBottom: '0' }"
|
||||
:body-style="{ padding: '17px 20px 21px 20px' }"
|
||||
:body-style="{ padding: '17px 20px 20px 20px' }"
|
||||
>
|
||||
<template #title>
|
||||
{{ $t('workplace.popularModule') }}
|
||||
@ -13,7 +13,7 @@
|
||||
:data="dataList"
|
||||
:pagination="false"
|
||||
:bordered="false"
|
||||
:scroll="{ x: '100%', y: '310px' }"
|
||||
:scroll="{ x: '100%', y: '484px' }"
|
||||
>
|
||||
<template #columns>
|
||||
<a-table-column title="排名">
|
||||
@ -89,7 +89,7 @@
|
||||
|
||||
<style scoped lang="less">
|
||||
.general-card {
|
||||
min-height: 395px;
|
||||
min-height: 400px;
|
||||
}
|
||||
:deep(.arco-table-tr) {
|
||||
height: 44px;
|
||||
|
@ -46,7 +46,7 @@
|
||||
import DataPanel from './components/data-panel.vue';
|
||||
import ContentChart from './components/content-chart.vue';
|
||||
import PopularModule from './components/popular-module.vue';
|
||||
import CategoriesPercent from './components/categories-percent.vue';
|
||||
import CategoriesPercent from './components/geo-distribution.vue';
|
||||
import RecentlyVisited from './components/recently-visited.vue';
|
||||
import QuickOperation from './components/quick-operation.vue';
|
||||
import Announcement from './components/announcement.vue';
|
||||
|
@ -14,6 +14,8 @@ export default {
|
||||
'workplace.docs.userGuide': 'User Guide',
|
||||
'workplace.docs.faq': 'FAQ',
|
||||
'workplace.docs.changelog': 'Change Log',
|
||||
'workplace.docs.authorSite': 'Author Site',
|
||||
'workplace.docs.require': 'Require',
|
||||
'workplace.announcement': 'Announcement',
|
||||
'workplace.recently.visited': 'Recently Visited',
|
||||
'workplace.record.nodata': 'No data',
|
||||
@ -23,8 +25,8 @@ export default {
|
||||
'workplace.loadMore': 'More',
|
||||
'workplace.viewMore': 'More',
|
||||
'workplace.contentData': 'Content Data',
|
||||
'workplace.popularModule': 'Popular Module',
|
||||
'workplace.categoriesPercent': 'Categories Percent',
|
||||
'workplace.popularModule': 'Popular Module(Top10)',
|
||||
'workplace.geoDistribution': 'Geo Distribution(Top10)',
|
||||
'workplace.unit.pecs': 'pecs',
|
||||
'workplace.unit.times': 'times',
|
||||
};
|
||||
|
@ -14,6 +14,8 @@ export default {
|
||||
'workplace.docs.userGuide': '使用指南',
|
||||
'workplace.docs.faq': '常见问题',
|
||||
'workplace.docs.changelog': '更新日志',
|
||||
'workplace.docs.authorSite': '作者主页',
|
||||
'workplace.docs.require': '需求墙',
|
||||
'workplace.announcement': '公告',
|
||||
'workplace.recently.visited': '最近访问',
|
||||
'workplace.record.nodata': '暂无数据',
|
||||
@ -23,8 +25,8 @@ export default {
|
||||
'workplace.loadMore': '加载更多',
|
||||
'workplace.viewMore': '查看更多',
|
||||
'workplace.contentData': '内容数据',
|
||||
'workplace.popularModule': '热门模块',
|
||||
'workplace.categoriesPercent': '内容类型占比',
|
||||
'workplace.popularModule': '热门模块(Top10)',
|
||||
'workplace.geoDistribution': '访客地域分布(Top10)',
|
||||
'workplace.unit.pecs': '个',
|
||||
'workplace.unit.times': '次',
|
||||
};
|
||||
|
@ -30,6 +30,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import top.charles7c.cnadmin.common.model.vo.R;
|
||||
import top.charles7c.cnadmin.monitor.annotation.Log;
|
||||
import top.charles7c.cnadmin.monitor.model.vo.DashboardGeoDistributionVO;
|
||||
import top.charles7c.cnadmin.monitor.model.vo.DashboardPopularModuleVO;
|
||||
import top.charles7c.cnadmin.monitor.model.vo.DashboardTotalVO;
|
||||
import top.charles7c.cnadmin.monitor.service.DashboardService;
|
||||
@ -63,6 +64,12 @@ public class DashboardController {
|
||||
return R.ok(dashboardService.listPopularModule());
|
||||
}
|
||||
|
||||
@Operation(summary = "查询访客地域分布信息", description = "查询访客地域分布信息")
|
||||
@GetMapping("/geo/distribution")
|
||||
public R<DashboardGeoDistributionVO> getGeoDistribution() {
|
||||
return R.ok(dashboardService.getGeoDistribution());
|
||||
}
|
||||
|
||||
@Operation(summary = "查询公告列表", description = "查询公告列表")
|
||||
@GetMapping("/announcement")
|
||||
public R<List<DashboardAnnouncementVO>> listAnnouncement() {
|
||||
|
Loading…
Reference in New Issue
Block a user