mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 22:57:17 +08:00 
			
		
		
		
	feat: 完善仪表盘访客地域分布区块内容
This commit is contained in:
		| @@ -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`); | ||||
| } | ||||
| @@ -44,14 +55,3 @@ 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() { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user