新增用户流量报表、license流量报表页面,及后端接口定义

This commit is contained in:
aoshiguchen
2023-03-19 15:55:38 +08:00
parent 983d5dde8c
commit e2c152a569
11 changed files with 485 additions and 46 deletions
+16
View File
@@ -0,0 +1,16 @@
import request from '@/utils/request'
export function fetchUserFlowReportList(query) {
return request({
url: '/report/user/flow-report/page',
method: 'get',
params: query
})
}
export function fetchLicenseFlowReportList(query) {
return request({
url: '/report/license/flow-report/page',
method: 'get',
params: query
})
}
+8 -2
View File
@@ -56,7 +56,10 @@ export default {
jobLog: '调度日志',
log: '日志管理',
loginLog: '登录日志',
clientConnectLog: '客户端连接日志'
clientConnectLog: '客户端连接日志',
report: '报表管理',
userFlowReport: '用户流量报表',
licenseFlowReport: 'License流量报表'
},
navbar: {
logOut: '退出登录',
@@ -153,7 +156,10 @@ export default {
msg: '消息',
outcome: '结果',
err: '异常信息',
resetKey: '重置Key'
resetKey: '重置Key',
upFlow: '上行流量',
downFlow: '下行流量',
totalFlow: '总流量'
},
button: {
lookOver: '查看'
+14
View File
@@ -80,6 +80,20 @@ export const asyncRouterMap = [
{ path: 'jobManager', component: _import('system/jobManager'), name: 'jobManager', meta: { title: 'jobManager' }}
]
},
{
path: '/report',
component: Layout,
redirect: 'noredirect',
name: 'report',
meta: {
title: 'report',
icon: 'component'
},
children: [
{ path: 'userFlowReport', component: _import('report/userFlowReport'), name: 'userFlowReport', meta: { title: 'userFlowReport' }},
{ path: 'licenseFlowReport', component: _import('report/licenseFlowReport'), name: 'licenseFlowReport', meta: { title: 'licenseFlowReport' }}
]
},
{
path: '/log',
component: Layout,
@@ -0,0 +1,128 @@
<template>
<div class="app-container calendar-list-container">
<div class="filter-container">
<el-select v-model="listQuery.userId" placeholder="请选择用户" clearable>
<el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
<el-button type="primary" v-waves icon="el-icon-search" @click="handleFilter">{{$t('table.search')}}</el-button>
</div>
<el-table :key='tableKey' :data="list" v-loading="listLoading" element-loading-text="给我一点时间" border fit highlight-current-row style="width: 100%">
<el-table-column type="index" width="100" :label="$t('table.id')"></el-table-column>
<el-table-column align="center" :label="$t('table.userName')" min-width="120">
<template slot-scope="scope">
<span>{{scope.row.userName}}</span>
</template>
</el-table-column>
<el-table-column align="center" :label="$t('table.licenseName')" min-width="120">
<template slot-scope="scope">
<span>{{scope.row.licenseName}}</span>
</template>
</el-table-column>
<el-table-column align="center" :label="$t('table.upFlow')" min-width="120">
<template slot-scope="scope">
<span>{{scope.row.upFlowDesc}}</span>
</template>
</el-table-column>
<el-table-column align="center" :label="$t('table.downFlow')" min-width="120">
<template slot-scope="scope">
<span>{{scope.row.downFlowDesc}}</span>
</template>
</el-table-column>
<el-table-column align="center" :label="$t('table.totalFlow')" min-width="120">
<template slot-scope="scope">
<span>{{scope.row.totalFlowDesc}}</span>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.current"
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.size" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
</template>
<script>
import { fetchLicenseFlowReportList } from '@/api/report'
import { userList } from '@/api/user'
import waves from '@/directive/waves'
export default {
name: 'jobLog',
directives: {
waves
},
data() {
return {
tableKey: 0,
list: null,
total: null,
listLoading: false,
listQuery: {
current: 1,
size: 10,
jobId: undefined
},
userList: [],
dialogVisible: false,
selectRow: {}
}
},
filters: {
},
created() {
this.getList()
this.getUserList()
},
activated() {
this.getUserList()
if (this.$route.query.jobId) {
this.listQuery.jobId = this.$route.query.jobId
this.getList()
}
},
methods: {
getList() {
this.listLoading = true
fetchLicenseFlowReportList(this.listQuery).then(response => {
this.list = response.data.data.records
this.total = response.data.data.total
this.listLoading = false
})
},
getUserList() {
userList().then(response => {
this.userList = response.data.data
})
},
handleFilter() {
this.listQuery.current = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.size = val
this.listQuery.current = 1
this.getList()
},
handleCurrentChange(val) {
this.listQuery.current = val
this.getList()
},
handleShowClick(row) {
console.log(row)
},
handleLookOver(row) {
this.selectRow = row
this.dialogVisible = true
}
}
}
</script>
<style>
.job-msg-div{
max-height: 400px;
overflow-y: auto;
}
</style>
@@ -0,0 +1,123 @@
<template>
<div class="app-container calendar-list-container">
<div class="filter-container">
<el-select v-model="listQuery.userId" placeholder="请选择用户" clearable>
<el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
<el-button type="primary" v-waves icon="el-icon-search" @click="handleFilter">{{$t('table.search')}}</el-button>
</div>
<el-table :key='tableKey' :data="list" v-loading="listLoading" element-loading-text="给我一点时间" border fit highlight-current-row style="width: 100%">
<el-table-column type="index" width="100" :label="$t('table.id')"></el-table-column>
<el-table-column align="center" :label="$t('table.userName')" min-width="120">
<template slot-scope="scope">
<span>{{scope.row.userName}}</span>
</template>
</el-table-column>
<el-table-column align="center" :label="$t('table.upFlow')" min-width="120">
<template slot-scope="scope">
<span>{{scope.row.upFlowDesc}}</span>
</template>
</el-table-column>
<el-table-column align="center" :label="$t('table.downFlow')" min-width="120">
<template slot-scope="scope">
<span>{{scope.row.downFlowDesc}}</span>
</template>
</el-table-column>
<el-table-column align="center" :label="$t('table.totalFlow')" min-width="120">
<template slot-scope="scope">
<span>{{scope.row.totalFlowDesc}}</span>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-pageInfo.sync="listQuery.current"
:pageInfo-sizes="[10,20,30, 50]" :pageInfo-size="listQuery.size" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
</template>
<script>
import { fetchUserFlowReportList } from '@/api/report'
import { userList } from '@/api/user'
import waves from '@/directive/waves' // 水波纹指令
export default {
name: 'jobLog',
directives: {
waves
},
data() {
return {
tableKey: 0,
list: null,
total: null,
listLoading: false,
listQuery: {
current: 1,
size: 10,
jobId: undefined
},
userList: [],
dialogVisible: false,
selectRow: {}
}
},
filters: {
},
created() {
this.getList()
this.getUserList()
},
activated() {
this.getUserList()
if (this.$route.query.jobId) {
this.listQuery.jobId = this.$route.query.jobId
this.getList()
}
},
methods: {
getList() {
this.listLoading = true
fetchUserFlowReportList(this.listQuery).then(response => {
this.list = response.data.data.records
this.total = response.data.data.total
this.listLoading = false
})
},
getUserList() {
userList().then(response => {
this.userList = response.data.data
})
},
handleFilter() {
this.listQuery.current = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.size = val
this.listQuery.current = 1
this.getList()
},
handleCurrentChange(val) {
this.listQuery.current = val
this.getList()
},
handleShowClick(row) {
console.log(row)
},
handleLookOver(row) {
this.selectRow = row
this.dialogVisible = true
}
}
}
</script>
<style>
.job-msg-div{
max-height: 400px;
overflow-y: auto;
}
</style>
@@ -29,5 +29,6 @@ import lombok.Data;
*/
@Data
public class LicenseFlowReportReq {
private Integer userId;
private Integer licenseId;
}
@@ -29,5 +29,8 @@ import lombok.Data;
*/
@Data
public class UserFlowReportReq {
/**
* 用户ID
*/
private Integer userId;
}
@@ -22,6 +22,7 @@
package fun.asgc.neutrino.proxy.server.controller.res;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
@@ -29,6 +30,7 @@ import java.util.Date;
* @author: aoshiguchen
* @date: 2022/12/21
*/
@Accessors(chain = true)
@Data
public class LicenseFlowReportRes {
/**
@@ -48,31 +50,27 @@ public class LicenseFlowReportRes {
*/
private String licenseName;
/**
* 写入字节数
* 上行流量字节数
*/
private Long writeBytes;
private Long upFlowBytes;
/**
* 读取字节数
* 下行流量字节数
*/
private Long readBytes;
private Long downFlowBytes;
/**
* 写入流量描述
* 总流量字节数
*/
private String writeFlowStr;
private Long totalFlowBytes;
/**
* 读取流量描述
* 上行流量描述
*/
private String readFlowStr;
private String upFlowDesc;
/**
* 流量描述
* 下行流量描述
*/
private String flowStr;
private String downFlowDesc;
/**
* 报表时间
* 总流量描述
*/
private Date date;
/**
* 创建时间
*/
private Date createTime;
private String totalFlowDesc;
}
@@ -22,6 +22,7 @@
package fun.asgc.neutrino.proxy.server.controller.res;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
@@ -29,6 +30,7 @@ import java.util.Date;
* @author: aoshiguchen
* @date: 2022/12/21
*/
@Accessors(chain = true)
@Data
public class UserFlowReportRes {
/**
@@ -40,39 +42,27 @@ public class UserFlowReportRes {
*/
private String userName;
/**
* 历史写入字节数
* 上行流量字节数
*/
private Long historyWriteBytes;
private Long upFlowBytes;
/**
* 历史读取字节数
* 下行流量字节数
*/
private Long historyReadBytes;
private Long downFlowBytes;
/**
* 写入字节数
* 总流量字节数
*/
private Long writeBytes;
private Long totalFlowBytes;
/**
* 读取字节数
* 上行流量描述
*/
private Long readBytes;
private String upFlowDesc;
/**
* 写入流量描述
* 下行流量描述
*/
private String writeFlowStr;
private String downFlowDesc;
/**
* 读取流量描述
* 流量描述
*/
private String readFlowStr;
/**
* 流量描述
*/
private String flowStr;
/**
* 报表时间
*/
private Date date;
/**
* 创建时间
*/
private Date createTime;
private String totalFlowDesc;
}
@@ -1,14 +1,19 @@
package fun.asgc.neutrino.proxy.server.service;
import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Lists;
import fun.asgc.neutrino.proxy.server.base.page.PageInfo;
import fun.asgc.neutrino.proxy.server.base.page.PageQuery;
import fun.asgc.neutrino.proxy.server.controller.req.LicenseFlowReportReq;
import fun.asgc.neutrino.proxy.server.controller.req.UserFlowReportReq;
import fun.asgc.neutrino.proxy.server.controller.res.LicenseFlowReportRes;
import fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes;
import fun.asgc.neutrino.proxy.server.util.FormatUtil;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import java.util.List;
/**
* @author: aoshiguchen
* @date: 2022/12/23
@@ -25,7 +30,43 @@ public class ReportService {
*/
public PageInfo<UserFlowReportRes> userFlowReportPage(PageQuery pageQuery, UserFlowReportReq req) {
// TODO
return null;
List<UserFlowReportRes> all = Lists.newArrayList(
new UserFlowReportRes().setUserId(1).setUserName("用户1").setUpFlowBytes(100L).setDownFlowBytes(200L),
new UserFlowReportRes().setUserId(2).setUserName("用户2").setUpFlowBytes(400L).setDownFlowBytes(600L),
new UserFlowReportRes().setUserId(3).setUserName("用户3").setUpFlowBytes(800L).setDownFlowBytes(1200L),
new UserFlowReportRes().setUserId(4).setUserName("用户4").setUpFlowBytes(120L).setDownFlowBytes(1600L),
new UserFlowReportRes().setUserId(5).setUserName("用户5").setUpFlowBytes(1600L).setDownFlowBytes(2000L),
new UserFlowReportRes().setUserId(6).setUserName("用户6").setUpFlowBytes(2200L).setDownFlowBytes(2500L),
new UserFlowReportRes().setUserId(7).setUserName("用户7").setUpFlowBytes(2800L).setDownFlowBytes(3200L),
new UserFlowReportRes().setUserId(8).setUserName("用户8").setUpFlowBytes(41000L).setDownFlowBytes(52000L),
new UserFlowReportRes().setUserId(9).setUserName("用户9").setUpFlowBytes(310000L).setDownFlowBytes(420000L),
new UserFlowReportRes().setUserId(10).setUserName("用户10").setUpFlowBytes(51000L).setDownFlowBytes(620000L),
new UserFlowReportRes().setUserId(11).setUserName("用户11").setUpFlowBytes(310000L).setDownFlowBytes(20000L),
new UserFlowReportRes().setUserId(12).setUserName("用户12").setUpFlowBytes(23100L).setDownFlowBytes(245200L),
new UserFlowReportRes().setUserId(13).setUserName("用户13").setUpFlowBytes(98100L).setDownFlowBytes(65200L),
new UserFlowReportRes().setUserId(14).setUserName("用户14").setUpFlowBytes(234100L).setDownFlowBytes(7809200L),
new UserFlowReportRes().setUserId(15).setUserName("用户15").setUpFlowBytes(23100L).setDownFlowBytes(4200L),
new UserFlowReportRes().setUserId(16).setUserName("用户16").setUpFlowBytes(21003100L).setDownFlowBytes(4099200L),
new UserFlowReportRes().setUserId(17).setUserName("用户17").setUpFlowBytes(23100L).setDownFlowBytes(4200L),
new UserFlowReportRes().setUserId(18).setUserName("用户18").setUpFlowBytes(10023100L).setDownFlowBytes(20004200L),
new UserFlowReportRes().setUserId(19).setUserName("用户19").setUpFlowBytes(300023100L).setDownFlowBytes(40004200L),
new UserFlowReportRes().setUserId(20).setUserName("用户20").setUpFlowBytes(5000023100L).setDownFlowBytes(600004200L),
new UserFlowReportRes().setUserId(21).setUserName("用户21").setUpFlowBytes(700023100L).setDownFlowBytes(80094200L),
new UserFlowReportRes().setUserId(22).setUserName("用户22").setUpFlowBytes(40000023100L).setDownFlowBytes(6000004200L),
new UserFlowReportRes().setUserId(23).setUserName("用户23").setUpFlowBytes(300000023100L).setDownFlowBytes(40000004200L),
new UserFlowReportRes().setUserId(24).setUserName("用户24").setUpFlowBytes(300998723100L).setDownFlowBytes(2099877664200L),
new UserFlowReportRes().setUserId(25).setUserName("用户25").setUpFlowBytes(50987668623100L).setDownFlowBytes(30987657864200L)
);
List<UserFlowReportRes> list = null;
if (pageQuery.getCurrent() == 1) {
list = all.subList(0, 10);
} else if (pageQuery.getCurrent() == 2){
list = all.subList(10, 20);
} else {
list = all.subList(20, all.size());
}
fillUserFlowReport(list);
return PageInfo.of(list, 25L, pageQuery.getCurrent(), pageQuery.getSize());
}
/**
@@ -36,6 +77,76 @@ public class ReportService {
*/
public PageInfo<LicenseFlowReportRes> licenseFlowReportPage(PageQuery pageQuery, LicenseFlowReportReq req) {
// TODO
return null;
List<LicenseFlowReportRes> all = Lists.newArrayList(
new LicenseFlowReportRes().setUserId(1).setUserName("用户1").setLicenseName("license1").setUpFlowBytes(100L).setDownFlowBytes(200L),
new LicenseFlowReportRes().setUserId(2).setUserName("用户2").setLicenseName("license1").setUpFlowBytes(400L).setDownFlowBytes(600L),
new LicenseFlowReportRes().setUserId(3).setUserName("用户3").setLicenseName("license1").setUpFlowBytes(800L).setDownFlowBytes(1200L),
new LicenseFlowReportRes().setUserId(4).setUserName("用户4").setLicenseName("license1").setUpFlowBytes(120L).setDownFlowBytes(1600L),
new LicenseFlowReportRes().setUserId(5).setUserName("用户5").setLicenseName("license1").setUpFlowBytes(1600L).setDownFlowBytes(2000L),
new LicenseFlowReportRes().setUserId(6).setUserName("用户6").setLicenseName("license1").setUpFlowBytes(2200L).setDownFlowBytes(2500L),
new LicenseFlowReportRes().setUserId(7).setUserName("用户7").setLicenseName("license1").setUpFlowBytes(2800L).setDownFlowBytes(3200L),
new LicenseFlowReportRes().setUserId(8).setUserName("用户8").setLicenseName("license1").setUpFlowBytes(41000L).setDownFlowBytes(52000L),
new LicenseFlowReportRes().setUserId(9).setUserName("用户9").setLicenseName("license1").setUpFlowBytes(310000L).setDownFlowBytes(420000L),
new LicenseFlowReportRes().setUserId(10).setUserName("用户10").setLicenseName("license1").setUpFlowBytes(51000L).setDownFlowBytes(620000L),
new LicenseFlowReportRes().setUserId(11).setUserName("用户11").setLicenseName("license1").setUpFlowBytes(310000L).setDownFlowBytes(20000L),
new LicenseFlowReportRes().setUserId(12).setUserName("用户12").setLicenseName("license1").setUpFlowBytes(23100L).setDownFlowBytes(245200L),
new LicenseFlowReportRes().setUserId(13).setUserName("用户13").setLicenseName("license1").setUpFlowBytes(98100L).setDownFlowBytes(65200L),
new LicenseFlowReportRes().setUserId(14).setUserName("用户14").setLicenseName("license1").setUpFlowBytes(234100L).setDownFlowBytes(7809200L),
new LicenseFlowReportRes().setUserId(15).setUserName("用户15").setLicenseName("license1").setUpFlowBytes(23100L).setDownFlowBytes(4200L),
new LicenseFlowReportRes().setUserId(16).setUserName("用户16").setLicenseName("license1").setUpFlowBytes(21003100L).setDownFlowBytes(4099200L),
new LicenseFlowReportRes().setUserId(17).setUserName("用户17").setLicenseName("license1").setUpFlowBytes(23100L).setDownFlowBytes(4200L),
new LicenseFlowReportRes().setUserId(18).setUserName("用户18").setLicenseName("license1").setUpFlowBytes(10023100L).setDownFlowBytes(20004200L),
new LicenseFlowReportRes().setUserId(19).setUserName("用户19").setLicenseName("license1").setUpFlowBytes(300023100L).setDownFlowBytes(40004200L),
new LicenseFlowReportRes().setUserId(20).setUserName("用户20").setLicenseName("license1").setUpFlowBytes(5000023100L).setDownFlowBytes(600004200L),
new LicenseFlowReportRes().setUserId(21).setUserName("用户21").setLicenseName("license1").setUpFlowBytes(700023100L).setDownFlowBytes(80094200L),
new LicenseFlowReportRes().setUserId(22).setUserName("用户22").setLicenseName("license1").setUpFlowBytes(40000023100L).setDownFlowBytes(6000004200L),
new LicenseFlowReportRes().setUserId(23).setUserName("用户23").setLicenseName("license1").setUpFlowBytes(300000023100L).setDownFlowBytes(40000004200L),
new LicenseFlowReportRes().setUserId(24).setUserName("用户24").setLicenseName("license1").setUpFlowBytes(300998723100L).setDownFlowBytes(2099877664200L),
new LicenseFlowReportRes().setUserId(25).setUserName("用户25").setLicenseName("license1").setUpFlowBytes(50987668623100L).setDownFlowBytes(30987657864200L)
);
List<LicenseFlowReportRes> list = null;
if (pageQuery.getCurrent() == 1) {
list = all.subList(0, 10);
} else if (pageQuery.getCurrent() == 2){
list = all.subList(10, 20);
} else {
list = all.subList(20, all.size());
}
fillLicenseFlowReport(list);
return PageInfo.of(list, 25L, pageQuery.getCurrent(), pageQuery.getSize());
}
private void fillUserFlowReport(List<UserFlowReportRes> list) {
if (CollectionUtil.isEmpty(list)) {
return;
}
for (UserFlowReportRes item : list) {
long upFlowBytes = (null == item.getUpFlowBytes()) ? 0 : item.getUpFlowBytes();
long downFlowBytes = (null == item.getDownFlowBytes()) ? 0 : item.getDownFlowBytes();
long totalFlowBytes = upFlowBytes + downFlowBytes;
item.setUpFlowBytes(upFlowBytes);
item.setDownFlowBytes(downFlowBytes);
item.setTotalFlowBytes(totalFlowBytes);
item.setUpFlowDesc(FormatUtil.getSizeDescByByteCount(upFlowBytes));
item.setDownFlowDesc(FormatUtil.getSizeDescByByteCount(downFlowBytes));
item.setTotalFlowDesc(FormatUtil.getSizeDescByByteCount(totalFlowBytes));
}
}
private void fillLicenseFlowReport(List<LicenseFlowReportRes> list) {
if (CollectionUtil.isEmpty(list)) {
return;
}
for (LicenseFlowReportRes item : list) {
long upFlowBytes = (null == item.getUpFlowBytes()) ? 0 : item.getUpFlowBytes();
long downFlowBytes = (null == item.getDownFlowBytes()) ? 0 : item.getDownFlowBytes();
long totalFlowBytes = upFlowBytes + downFlowBytes;
item.setUpFlowBytes(upFlowBytes);
item.setDownFlowBytes(downFlowBytes);
item.setTotalFlowBytes(totalFlowBytes);
item.setUpFlowDesc(FormatUtil.getSizeDescByByteCount(upFlowBytes));
item.setDownFlowDesc(FormatUtil.getSizeDescByByteCount(downFlowBytes));
item.setTotalFlowDesc(FormatUtil.getSizeDescByByteCount(totalFlowBytes));
}
}
}
@@ -0,0 +1,49 @@
package fun.asgc.neutrino.proxy.server.util;
/**
* @author: aoshiguchen
* @date: 2023/3/19
*/
public class FormatUtil {
private static final String[] SIZE_UNINTS = {"B", "KB", "MB", "GB", "TB"};
private static final int SIZE_SYSTEM = 1024;
/**
* 根据字节数获取大小描述
* 1、小于1024字节的以B为单位
* 2、小于1024KB的以KB为单位
* 3、小于1024M的以MB为单位
* 4、小于1024G的以GB为单位
* 5、其他以TB为单位
* @param byteCount
* @return
*/
public static String getSizeDescByByteCount(long byteCount){
if(byteCount <= 0){
return "0B";
}
double res = byteCount;
int index = 0;
while (index < SIZE_UNINTS.length && res >= SIZE_SYSTEM){
res /= SIZE_SYSTEM;
index++;
}
if(index >= SIZE_UNINTS.length){
index = SIZE_UNINTS.length - 1;
res *= 1024;
}
return trimZero(String.format("%.2f", res)) + " " + SIZE_UNINTS[index];
}
private static String trimZero(String s) {
if (s.indexOf(".") > 0) {
// 去掉多余的0
s = s.replaceAll("0+?$", "");
// 如最后一位是.则去掉
s = s.replaceAll("[.]$", "");
}
return s;
}
}