用户行为分析,数据基础信息新增字段,设计图纸和资料文件列表查询,水库月核定生态流量查询,水库责任体系新增修改
parent
eb1168223f
commit
abce68b34b
|
|
@ -2,6 +2,7 @@ package com.gunshi.project.xyt.controller;
|
|||
|
||||
import com.gunshi.core.result.R;
|
||||
import com.gunshi.project.xyt.model.AttResBase;
|
||||
import com.gunshi.project.xyt.model.FileAssociations;
|
||||
import com.gunshi.project.xyt.service.AttResBaseService;
|
||||
import com.gunshi.project.xyt.service.FileAssociationsService;
|
||||
import com.gunshi.project.xyt.validate.markers.Insert;
|
||||
|
|
@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.*;
|
|||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 描述: 水库基本信息表
|
||||
|
|
@ -98,6 +100,18 @@ public class AttResBaseController extends AbstractCommonFileController {
|
|||
return R.ok(list);
|
||||
}
|
||||
|
||||
@Operation(summary = "设计图纸和资料列表")
|
||||
@GetMapping("/fileList/{resCode}")
|
||||
public R<List<FileAssociations>> list(@PathVariable("resCode") String resCode) {
|
||||
List<FileAssociations> files = fileService.getFiles(getGroupId(), resCode);
|
||||
if (CollectionUtils.isEmpty(files)){
|
||||
return R.ok(files);
|
||||
}
|
||||
List<FileAssociations> datas = files.stream().filter(o -> "1".equals(o.getType()))
|
||||
.collect(Collectors.toList());
|
||||
return R.ok(datas);
|
||||
}
|
||||
|
||||
// @Operation(summary = "分页")
|
||||
// @PostMapping("/page")
|
||||
public R<List<AttResBase>> page() {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public class ResMonthEcoFlowController {
|
|||
|
||||
@Operation(summary = "列表")
|
||||
@PostMapping("/list")
|
||||
public R<List<ResMonthEcoFlow>> list(@Validated ResMonthEcoFlowListSo vo) {
|
||||
public R<List<ResMonthEcoFlow>> list(@Validated @RequestBody ResMonthEcoFlowListSo vo) {
|
||||
LocalDateTime stm = LocalDateTime.of(vo.getYear(), 1, 1, 0, 0, 0);
|
||||
LocalDateTime etm = LocalDateTime.of(vo.getYear(), 12, 31, 23, 59, 59);
|
||||
return R.ok(service.lambdaQuery().between(ResMonthEcoFlow::getModitime,stm,etm).orderByAsc(ResMonthEcoFlow::getMonth).list());
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ public interface FileAssociationsMapper extends BaseMapper<FileAssociations> {
|
|||
SELECT
|
||||
fa.*,
|
||||
fd.file_name,
|
||||
fd.file_size,
|
||||
fd.file_path
|
||||
FROM
|
||||
file_associations fa
|
||||
|
|
|
|||
|
|
@ -493,6 +493,34 @@ public class AttResBase implements Serializable {
|
|||
@Schema(description="堰顶高程,m")
|
||||
private BigDecimal wcrstel;
|
||||
|
||||
/**
|
||||
* feedPop
|
||||
*/
|
||||
@TableField(value="feed_pop")
|
||||
@Schema(description="受益人口(人)")
|
||||
private Integer feedPop;
|
||||
|
||||
/**
|
||||
* design_irr_area
|
||||
*/
|
||||
@TableField(value="design_irr_area")
|
||||
@Schema(description="设计灌溉面积(亩)")
|
||||
private Integer designIrrArea;
|
||||
|
||||
/**
|
||||
* actual_irr_area
|
||||
*/
|
||||
@TableField(value="actual_irr_area")
|
||||
@Schema(description="实际灌溉面积(亩)")
|
||||
private BigDecimal actualIrrArea;
|
||||
|
||||
/**
|
||||
* actual_irr_area
|
||||
*/
|
||||
@TableField(value="benefit")
|
||||
@Schema(description="供水效益")
|
||||
private String benefit;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "文件集合")
|
||||
|
|
|
|||
|
|
@ -104,4 +104,8 @@ public class FileAssociations implements Serializable {
|
|||
@Schema(description = "文件名称")
|
||||
private String fileName;
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "文件大小 (byte)")
|
||||
private String fileSize;
|
||||
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
|
|||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.gunshi.core.dateformat.DateFormatString;
|
||||
import com.gunshi.project.xyt.validate.markers.Update;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
|
@ -35,7 +36,7 @@ public class ResSafePersonB implements Serializable {
|
|||
@TableId(value="id", type= IdType.AUTO)
|
||||
@Schema(description="主键")
|
||||
// @Size(max = 0,message = "主键最大长度要小于 0")
|
||||
@NotNull(message = "主键不能为空")
|
||||
@NotNull(message = "主键不能为空",groups = {Update.class})
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ public class FileAssociationsService extends ServiceImpl<FileAssociationsMapper,
|
|||
.filter(fileAssociations -> !fileIds.remove(fileAssociations.getFileId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isNotEmpty(files)) {
|
||||
// if (CollectionUtils.isNotEmpty(files)) {
|
||||
|
||||
// 删除
|
||||
if (this.lambdaUpdate()
|
||||
|
|
@ -63,7 +63,7 @@ public class FileAssociationsService extends ServiceImpl<FileAssociationsMapper,
|
|||
log.info("delete file {} success!", fileIds);
|
||||
}
|
||||
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,247 @@
|
|||
package com.gunshi.project.xyt.system;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.gunshi.core.annotation.Get;
|
||||
import com.gunshi.core.annotation.Post;
|
||||
import com.gunshi.core.result.R;
|
||||
import com.gunshi.project.xyt.system.model.SysUserLoginLog;
|
||||
import com.gunshi.project.xyt.system.model.SysVisitMenuLog;
|
||||
import com.gunshi.project.xyt.system.mapper.SysUserLoginLogMapper;
|
||||
import com.gunshi.project.xyt.system.mapper.SysVisitMenuLogMapper;
|
||||
import com.gunshi.project.xyt.system.so.UserLoginLogPageSo;
|
||||
import com.gunshi.project.xyt.system.so.UserLoginLogSo;
|
||||
import com.gunshi.project.xyt.system.vo.TodayCountVo;
|
||||
import com.gunshi.project.xyt.system.vo.UserCountVo;
|
||||
import com.gunshi.project.xyt.system.vo.VisitCountVo;
|
||||
import com.gunshi.project.xyt.util.DateUtil;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Description:
|
||||
* Created by XuSan on 2024/6/20.
|
||||
*
|
||||
* @author XuSan
|
||||
* @version 1.0
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userLoginLog")
|
||||
@Tag(name = "用户访问记录")
|
||||
public class SysUserLoginLogController {
|
||||
|
||||
@Autowired
|
||||
private SysUserLoginLogMapper thisMapper;
|
||||
|
||||
@Autowired
|
||||
private SysVisitMenuLogMapper thisMenuMapper;
|
||||
|
||||
// @Autowired
|
||||
// private ProjectCommonService projectCommonService;
|
||||
|
||||
@Post(path = "/page", summary = "分页查询")
|
||||
public R<Page<SysUserLoginLog>> page(@RequestBody @Validated UserLoginLogPageSo dto) {
|
||||
LambdaQueryWrapper<SysUserLoginLog> queryWrapper = Wrappers.lambdaQuery();
|
||||
|
||||
if (dto.getName() != null) {
|
||||
queryWrapper.eq(SysUserLoginLog::getCreateId, dto.getName());
|
||||
}
|
||||
|
||||
return R.ok(thisMapper.selectPage(dto.getPageSo().toPage(), queryWrapper));
|
||||
}
|
||||
|
||||
@Get(path = "/todayCount", summary = "今日数据总览")
|
||||
public R<TodayCountVo> todayCount() {
|
||||
|
||||
LambdaQueryWrapper<SysUserLoginLog> wrapper = Wrappers.lambdaQuery(SysUserLoginLog.class)
|
||||
.between(SysUserLoginLog::getCreateDate, DateUtil.convertStringToDate(LocalDate.now().toString() + " 00:00:00"), new Date());
|
||||
|
||||
List<SysUserLoginLog> logs = thisMapper.selectList(wrapper);
|
||||
|
||||
if (CollectionUtils.isEmpty(logs)) {
|
||||
return R.ok(null);
|
||||
}
|
||||
|
||||
TodayCountVo vo = new TodayCountVo();
|
||||
|
||||
vo.setWeb1Count(
|
||||
logs.stream()
|
||||
.filter(o -> "0".equals(o.getLoginType()))
|
||||
.count());
|
||||
|
||||
List<Long> webTimes = logs.stream()
|
||||
.filter(o -> "0".equals(o.getLoginType()))
|
||||
.filter(o -> o.getLogoutTime() != null && o.getLoginTime() != null)
|
||||
.map(o -> o.getLogoutTime().getTime() - o.getLoginTime().getTime())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
BigDecimal divisor = BigDecimal.valueOf(1000 * 60 * 60);
|
||||
vo.setWeb3Count(
|
||||
BigDecimal.valueOf(webTimes.stream().mapToLong(o -> o).sum())
|
||||
.divide(BigDecimal.valueOf(webTimes.size()), 2, RoundingMode.HALF_UP)
|
||||
.divide(divisor, 2, RoundingMode.HALF_UP)
|
||||
);
|
||||
|
||||
vo.setApp1Count(
|
||||
logs.stream()
|
||||
.filter(o -> "1".equals(o.getLoginType()))
|
||||
.count()
|
||||
);
|
||||
|
||||
List<Long> appTimes = logs.stream()
|
||||
.filter(o -> "0".equals(o.getLoginType()))
|
||||
.filter(o -> o.getLogoutTime() != null && o.getLoginTime() != null)
|
||||
.map(o -> o.getLogoutTime().getTime() - o.getLoginTime().getTime())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
vo.setApp3Count(
|
||||
BigDecimal.valueOf(appTimes.stream().mapToLong(o -> o).sum())
|
||||
.divide(BigDecimal.valueOf(appTimes.size()),2, RoundingMode.HALF_UP)
|
||||
.divide(divisor,2, RoundingMode.HALF_UP)
|
||||
);
|
||||
|
||||
LambdaQueryWrapper<SysVisitMenuLog> wrapperMenuLog = Wrappers.lambdaQuery(SysVisitMenuLog.class)
|
||||
.eq(SysVisitMenuLog::getCreateTime, new Date());
|
||||
|
||||
vo.setWeb2Count(0L);
|
||||
vo.setApp2Count(0L);
|
||||
|
||||
List<SysVisitMenuLog> wrapperMenuLogs = thisMenuMapper.selectList(wrapperMenuLog);
|
||||
if (CollectionUtils.isNotEmpty(wrapperMenuLogs)) {
|
||||
vo.setWeb2Count(
|
||||
wrapperMenuLogs.stream()
|
||||
.filter(o -> "0".equals(o.getLoginType()))
|
||||
.count()
|
||||
);
|
||||
|
||||
vo.setApp2Count(
|
||||
wrapperMenuLogs.stream()
|
||||
.filter(o -> "1".equals(o.getLoginType()))
|
||||
.count()
|
||||
);
|
||||
}
|
||||
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
|
||||
@Post(path = "/visitCount", summary = "访问用户前十")
|
||||
public R<VisitCountVo> visitCount(@RequestBody @Validated UserLoginLogSo so) {
|
||||
|
||||
List<SysUserLoginLog> logs = thisMapper.getUserLoginLog(so.getStm(), so.getEtm());
|
||||
|
||||
VisitCountVo vo = new VisitCountVo();
|
||||
if (CollectionUtils.isEmpty(logs)) {
|
||||
return R.ok(vo);
|
||||
}
|
||||
vo.setWebList(logs.stream()
|
||||
.filter(o -> "0".equals(o.getLoginType()))
|
||||
.collect(Collectors.groupingBy(SysUserLoginLog::getUserName, Collectors.counting()))
|
||||
.entrySet().stream()
|
||||
.map(o -> {
|
||||
VisitCountVo.VisitCountDataVo dataVo = new VisitCountVo.VisitCountDataVo();
|
||||
dataVo.setCount(o.getValue());
|
||||
dataVo.setName(o.getKey());
|
||||
return dataVo;
|
||||
}).collect(Collectors.toList())
|
||||
);
|
||||
vo.setAppList(logs.stream()
|
||||
.filter(o -> "1".equals(o.getLoginType()))
|
||||
.collect(Collectors.groupingBy(SysUserLoginLog::getUserName, Collectors.counting()))
|
||||
.entrySet().stream()
|
||||
.map(o -> {
|
||||
VisitCountVo.VisitCountDataVo dataVo = new VisitCountVo.VisitCountDataVo();
|
||||
dataVo.setCount(o.getValue());
|
||||
dataVo.setName(o.getKey());
|
||||
return dataVo;
|
||||
})
|
||||
.limit(10)
|
||||
.collect(Collectors.toList())
|
||||
|
||||
);
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
@Post(path = "/userCount", summary = "日活跃用户数")
|
||||
public R<UserCountVo> userCount(@RequestBody @Validated UserLoginLogSo so) {
|
||||
|
||||
List<SysUserLoginLog> logs = thisMapper.getUserLoginLog(so.getStm(), so.getEtm());
|
||||
|
||||
UserCountVo vo = new UserCountVo();
|
||||
if (CollectionUtils.isEmpty(logs)) {
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
vo.setWebList(logs.stream()
|
||||
.filter(o -> "0".equals(o.getLoginType()))
|
||||
.collect(Collectors.groupingBy(SysUserLoginLog::getCreateDate, Collectors.counting()))
|
||||
.entrySet().stream()
|
||||
.map(o -> {
|
||||
UserCountVo.UserCountDataVo dataVo = new UserCountVo.UserCountDataVo();
|
||||
dataVo.setCount(o.getValue());
|
||||
dataVo.setCreateDate(o.getKey());
|
||||
return dataVo;
|
||||
}).collect(Collectors.toList())
|
||||
);
|
||||
|
||||
vo.setAppList(logs.stream()
|
||||
.filter(o -> "1".equals(o.getLoginType()))
|
||||
.collect(Collectors.groupingBy(SysUserLoginLog::getCreateDate, Collectors.counting()))
|
||||
.entrySet().stream()
|
||||
.map(o -> {
|
||||
UserCountVo.UserCountDataVo dataVo = new UserCountVo.UserCountDataVo();
|
||||
dataVo.setCount(o.getValue());
|
||||
dataVo.setCreateDate(o.getKey());
|
||||
return dataVo;
|
||||
}).collect(Collectors.toList())
|
||||
);
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
@Post(path = "/insert", summary = "添加")
|
||||
public R<Boolean> insert(@RequestBody @Validated SysUserLoginLog dto) {
|
||||
|
||||
if (Objects.isNull(dto.getCreateId())) {
|
||||
// Long loginUserId = projectCommonService.getLoginUserId();
|
||||
// dto.setCreateId(loginUserId);
|
||||
}
|
||||
|
||||
// 查询当前时间是否存在
|
||||
List<SysUserLoginLog> uLogs = thisMapper.selectList(
|
||||
Wrappers
|
||||
.lambdaQuery(SysUserLoginLog.class)
|
||||
.eq(SysUserLoginLog::getCreateId,dto.getCreateId())
|
||||
.eq(SysUserLoginLog::getCreateDate, new Date()));
|
||||
|
||||
|
||||
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(uLogs)) {
|
||||
throw new RuntimeException("当前数据已存在");
|
||||
}
|
||||
|
||||
Date date = new Date();
|
||||
|
||||
|
||||
// 第一次登录
|
||||
dto
|
||||
.setCreateDate(date)
|
||||
.setLoginTime(date)
|
||||
.setLogoutTime(date);
|
||||
|
||||
return R.ok(thisMapper.insert(dto) == 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package com.gunshi.project.xyt.system;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.gunshi.core.annotation.Post;
|
||||
import com.gunshi.core.result.R;
|
||||
import com.gunshi.core.result.exception.NeedLoginException;
|
||||
import com.gunshi.project.xyt.system.model.SysVisitMenuLog;
|
||||
import com.gunshi.project.xyt.system.mapper.SysVisitMenuLogMapper;
|
||||
import com.gunshi.project.xyt.system.so.VisitMenuLogPageSo;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Description:
|
||||
* Created by XuSan on 2024/6/20.
|
||||
*
|
||||
* @author XuSan
|
||||
* @version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/visitMenuLog")
|
||||
@Tag(name = "页面访问记录")
|
||||
public class SysVisitMenuLogController {
|
||||
|
||||
@Autowired
|
||||
private SysVisitMenuLogMapper thisMapper;
|
||||
|
||||
|
||||
// @Resource
|
||||
// private ProjectCommonService projectCommonService;
|
||||
@Post(path = "/page", summary = "分页查询")
|
||||
public R<Page<SysVisitMenuLog>> page(@RequestBody @Validated VisitMenuLogPageSo dto) {
|
||||
LambdaQueryWrapper<SysVisitMenuLog> queryWrapper = Wrappers.lambdaQuery();
|
||||
|
||||
if (dto.getMenu() != null) {
|
||||
queryWrapper.like(SysVisitMenuLog::getMenu1, dto.getMenu());
|
||||
queryWrapper.like(SysVisitMenuLog::getMenu2, dto.getMenu());
|
||||
queryWrapper.like(SysVisitMenuLog::getMenu3, dto.getMenu());
|
||||
}
|
||||
|
||||
return R.ok(thisMapper.selectPage(dto.getPageSo().toPage(), queryWrapper));
|
||||
}
|
||||
|
||||
@Post(path = "/count", summary = "统计查询")
|
||||
public R<List<SysVisitMenuLog>> count(@RequestBody @Validated VisitMenuLogPageSo dto) {
|
||||
|
||||
LambdaQueryWrapper<SysVisitMenuLog> queryWrapper = Wrappers.query(SysVisitMenuLog.class)
|
||||
.select("COUNT(ID) COUNT, menu2, menu1")
|
||||
.lambda();
|
||||
|
||||
if (dto.getStm() != null) {
|
||||
queryWrapper.ge(SysVisitMenuLog::getCreateTime, dto.getStm());
|
||||
}
|
||||
|
||||
if (dto.getEtm() != null) {
|
||||
queryWrapper.le(SysVisitMenuLog::getCreateTime, dto.getEtm());
|
||||
}
|
||||
|
||||
queryWrapper.groupBy(SysVisitMenuLog::getMenu2, SysVisitMenuLog::getMenu1);
|
||||
|
||||
List<SysVisitMenuLog> list = thisMapper.selectList(queryWrapper);
|
||||
|
||||
|
||||
return R.ok(
|
||||
list
|
||||
.stream()
|
||||
.sorted(
|
||||
Comparator
|
||||
.comparing(SysVisitMenuLog::getCount)
|
||||
.reversed()
|
||||
)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
@Post(path = "/insert", summary = "添加")
|
||||
public R<Boolean> insert(@RequestBody @Validated SysVisitMenuLog dto) {
|
||||
|
||||
Long loginUserId = null;
|
||||
// 获取用户id
|
||||
try {
|
||||
// loginUserId = projectCommonService.getLoginUserId();
|
||||
} catch (NeedLoginException e) {
|
||||
log.info("获取登录账号id," + e.getMessage(), e);
|
||||
}
|
||||
// if (null == dto.getCreateId() && null != loginUserId){
|
||||
// dto.setCreateId(loginUserId);
|
||||
// }
|
||||
return R.ok(thisMapper.insert(dto) == 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
package com.gunshi.project.xyt.system.aspect;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.gunshi.core.result.exception.NeedLoginException;
|
||||
import com.gunshi.project.xyt.system.model.SysUserLoginLog;
|
||||
import com.gunshi.project.xyt.system.mapper.SysUserLoginLogMapper;
|
||||
import com.gunshi.project.xyt.system.utils.ReqUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Description:
|
||||
* Created by XuSan on 2024/6/20.
|
||||
*
|
||||
* @author XuSan
|
||||
* @version 1.0
|
||||
*/
|
||||
@Aspect
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SysUserLogAspect {
|
||||
|
||||
@Autowired
|
||||
private SysUserLoginLogMapper userLoginLogMapper;
|
||||
|
||||
// @Autowired
|
||||
// private ProjectCommonService projectCommonService;
|
||||
|
||||
|
||||
@Pointcut("execution(public * com.gunshi.project.xyt.controller..*Controller.*(..))")
|
||||
public void controllerPointcut() {
|
||||
}
|
||||
|
||||
@Before("controllerPointcut()")
|
||||
public void doBefore(JoinPoint joinPoint) throws Throwable {
|
||||
|
||||
log.info("进入记录日志切面");
|
||||
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
|
||||
Long loginUserId = null;
|
||||
// 获取用户id
|
||||
try {
|
||||
// loginUserId = projectCommonService.getLoginUserId();
|
||||
} catch (NeedLoginException e) {
|
||||
log.info("获取登录账号id," + e.getMessage(), e);
|
||||
}
|
||||
if (loginUserId != null) {
|
||||
|
||||
String loginType = request.getHeader("loginType");
|
||||
if (StringUtils.isBlank(loginType)){
|
||||
loginType = "0";
|
||||
}
|
||||
|
||||
// 查询当前时间是否存在
|
||||
List<SysUserLoginLog> uLogs = userLoginLogMapper.selectList(
|
||||
Wrappers
|
||||
.lambdaQuery(SysUserLoginLog.class)
|
||||
.eq(SysUserLoginLog::getLoginType, loginType)
|
||||
.eq(SysUserLoginLog::getCreateDate, new Date())
|
||||
.eq(SysUserLoginLog::getCreateId, loginUserId));
|
||||
|
||||
Integer id = null;
|
||||
SysUserLoginLog o = new SysUserLoginLog();
|
||||
if (CollectionUtils.isNotEmpty(uLogs)) {
|
||||
o = uLogs.getFirst();
|
||||
id = o.getId();
|
||||
}
|
||||
|
||||
Date date = new Date();
|
||||
|
||||
|
||||
if (Objects.isNull(id)) {
|
||||
String ip = request.getHeader("ClientIp");
|
||||
|
||||
if (StringUtils.isBlank(ip)) {
|
||||
ip = ReqUtil.getIpAddress(request);
|
||||
}
|
||||
|
||||
// 第一次登录
|
||||
o.setLoginType(loginType);
|
||||
o.setCreateId(loginUserId)
|
||||
.setCreateDate(date)
|
||||
.setLoginTime(date)
|
||||
.setIp(ip)
|
||||
.setLogoutTime(date);
|
||||
if (userLoginLogMapper.insert(o) != 1) {
|
||||
log.error("插入用户登录日志失败");
|
||||
}
|
||||
} else {
|
||||
o.setId(id);
|
||||
o.setLogoutTime(date);
|
||||
if (userLoginLogMapper.updateById(o) != 1) {
|
||||
log.error("更新用户登录日志失败");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
log.info("记录日志切面结束");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.gunshi.project.xyt.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.gunshi.project.xyt.system.model.SysUserLoginLog;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SysUserLoginLogMapper extends BaseMapper<SysUserLoginLog> {
|
||||
|
||||
@Select("""
|
||||
<script>
|
||||
SELECT su.*,ub.user_name
|
||||
FROM sys_user_login_log su LEFT JOIN uams_user_b ub on su.createId = ub.user_id
|
||||
WHERE su.create_date between #{stm} and #{etm}
|
||||
</script>
|
||||
""")
|
||||
List<SysUserLoginLog> getUserLoginLog(@Param("stm") Date stm , @Param("etm") Date etm);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.gunshi.project.xyt.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.gunshi.project.xyt.system.model.SysVisitMenuLog;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysVisitMenuLogMapper extends BaseMapper<SysVisitMenuLog> {
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.gunshi.project.xyt.system.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.gunshi.core.dateformat.DateFormatString;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流域基础信息表
|
||||
*/
|
||||
@Schema(description="用户登录日志")
|
||||
@Data
|
||||
@TableName(value = "public.sys_user_login_log")
|
||||
@Accessors(chain = true)
|
||||
public class SysUserLoginLog implements Serializable {
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@Schema(description="主键id")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||
private Integer id;
|
||||
|
||||
@TableField(value = "create_id")
|
||||
@Schema(description="用户编号")
|
||||
private Long createId;
|
||||
|
||||
@TableField(value = "login_type")
|
||||
@Schema(description="登录类型, 0: web, 1:app")
|
||||
private String loginType;
|
||||
|
||||
@TableField(value = "ip")
|
||||
@Schema(description="ip")
|
||||
private String ip;
|
||||
|
||||
@TableField(value = "create_date")
|
||||
@Schema(description="日期")
|
||||
@JsonFormat(pattern = DateFormatString.YYYY_MM_DD, timezone = "GMT+8")
|
||||
private Date createDate;
|
||||
|
||||
|
||||
@TableField(value = "login_time")
|
||||
@Schema(description="登录时间")
|
||||
@JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8")
|
||||
private Date loginTime;
|
||||
|
||||
|
||||
@TableField(value = "logout_time")
|
||||
@Schema(description="登出时间")
|
||||
@JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8")
|
||||
private Date logoutTime;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description="用户名称")
|
||||
private String userName;
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package com.gunshi.project.xyt.system.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.gunshi.core.dateformat.DateFormatString;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流域基础信息表
|
||||
*/
|
||||
@Schema(description="菜单访问日志")
|
||||
@Data
|
||||
@TableName(value = "public.sys_visit_menu_log")
|
||||
public class SysVisitMenuLog implements Serializable {
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@Schema(description="主键id")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||
private Integer id;
|
||||
|
||||
@TableField(value = "create_id")
|
||||
@Schema(description="用户编号")
|
||||
private Long createId;
|
||||
|
||||
@TableField(value = "login_type")
|
||||
@Schema(description="登录类型, 0: web, 1:app")
|
||||
private String loginType;
|
||||
|
||||
@TableField(value = "create_time")
|
||||
@Schema(description="创建时间")
|
||||
@JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8")
|
||||
private Date createTime;
|
||||
|
||||
@TableField(value = "menu1")
|
||||
@Schema(description="菜单1")
|
||||
private String menu1;
|
||||
|
||||
@TableField(value = "menu2")
|
||||
@Schema(description="菜单2")
|
||||
private String menu2;
|
||||
|
||||
@TableField(value = "menu3")
|
||||
@Schema(description="菜单3")
|
||||
private String menu3;
|
||||
|
||||
@TableField(exist = false)
|
||||
@Schema(description="统计数量")
|
||||
private String count;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.gunshi.project.xyt.system.so;
|
||||
|
||||
import com.gunshi.db.dto.PageSo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* Created by wanyan on 2024/4/7.
|
||||
*
|
||||
* @author wanyan
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "用户访问记录分页查询条件")
|
||||
public class UserLoginLogPageSo {
|
||||
|
||||
@NotNull(message = "分页参数不能为空")
|
||||
@Schema(description = "分页参数")
|
||||
private PageSo pageSo;
|
||||
|
||||
@Schema(description="名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description="开始时间 yyyy-MM-dd HH:mm:ss")
|
||||
private Date stm;
|
||||
|
||||
@Schema(description="结束时间 yyyy-MM-dd HH:mm:ss")
|
||||
private Date etm;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.gunshi.project.xyt.system.so;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* Created by wanyan on 2024/4/7.
|
||||
*
|
||||
* @author wanyan
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "用户访问记录统计查询条件")
|
||||
public class UserLoginLogSo {
|
||||
|
||||
|
||||
@Schema(description="开始时间 yyyy-MM-dd HH:mm:ss")
|
||||
@NotNull
|
||||
private Date stm;
|
||||
|
||||
@Schema(description="结束时间 yyyy-MM-dd HH:mm:ss")
|
||||
@NotNull
|
||||
private Date etm;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.gunshi.project.xyt.system.so;
|
||||
|
||||
import com.gunshi.db.dto.PageSo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* Created by wanyan on 2024/4/7.
|
||||
*
|
||||
* @author wanyan
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "页面访问记录分页查询条件")
|
||||
public class VisitMenuLogPageSo {
|
||||
|
||||
@NotNull(message = "分页参数不能为空")
|
||||
@Schema(description = "分页参数")
|
||||
private PageSo pageSo;
|
||||
|
||||
@Schema(description="菜单名")
|
||||
private String menu;
|
||||
|
||||
@Schema(description="名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description="开始时间 yyyy-MM-dd HH:mm:ss")
|
||||
private Date stm;
|
||||
|
||||
@Schema(description="结束时间 yyyy-MM-dd HH:mm:ss")
|
||||
private Date etm;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
package com.gunshi.project.xyt.system.utils;
|
||||
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
public class ReqUtil {
|
||||
// private static DbConfig config = null;
|
||||
private static String dbPath = null;
|
||||
|
||||
// private static DbSearcher searcher = null;
|
||||
|
||||
/**
|
||||
* 获取用户真实IP地址,不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
|
||||
* 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值,究竟哪个才是真正的用户端的真实IP呢?
|
||||
* 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
|
||||
* 如:X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130, 192.168.1.100
|
||||
* 用户真实IP为: 192.168.1.110
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public static String getIpAddress(HttpServletRequest request) {// 获取客户端ip地址
|
||||
String clientIp = request.getHeader("x-forwarded-for");
|
||||
|
||||
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
|
||||
clientIp = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
|
||||
clientIp = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
|
||||
clientIp = request.getRemoteAddr();
|
||||
}
|
||||
/*
|
||||
* 对于获取到多ip的情况下,找到公网ip.
|
||||
*/
|
||||
String sIP = null;
|
||||
if (clientIp != null && !clientIp.contains("unknown") && clientIp.indexOf(",") > 0) {
|
||||
String[] ipsz = clientIp.split(",");
|
||||
for (String anIpsz : ipsz) {
|
||||
if (!isInnerIP(anIpsz.trim())) {
|
||||
sIP = anIpsz.trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 如果多ip都是内网ip,则取第一个ip.
|
||||
*/
|
||||
if (null == sIP) {
|
||||
sIP = ipsz[0].trim();
|
||||
}
|
||||
clientIp = sIP;
|
||||
}
|
||||
if (clientIp != null && clientIp.contains("unknown")) {
|
||||
clientIp = clientIp.replaceAll("unknown,", "");
|
||||
clientIp = clientIp.trim();
|
||||
}
|
||||
if ("".equals(clientIp) || null == clientIp) {
|
||||
clientIp = "127.0.0.1";
|
||||
}
|
||||
return clientIp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断IP是否是内网地址
|
||||
*
|
||||
* @param ipAddress ip地址
|
||||
* @return 是否是内网地址
|
||||
*/
|
||||
public static boolean isInnerIP(String ipAddress) {
|
||||
boolean isInnerIp;
|
||||
long ipNum = getIpNum(ipAddress);
|
||||
/**
|
||||
私有IP:A类 10.0.0.0-10.255.255.255
|
||||
B类 172.16.0.0-172.31.255.255
|
||||
C类 192.168.0.0-192.168.255.255
|
||||
当然,还有127这个网段是环回地址
|
||||
**/
|
||||
long aBegin = getIpNum("10.0.0.0");
|
||||
long aEnd = getIpNum("10.255.255.255");
|
||||
|
||||
long bBegin = getIpNum("172.16.0.0");
|
||||
long bEnd = getIpNum("172.31.255.255");
|
||||
|
||||
long cBegin = getIpNum("192.168.0.0");
|
||||
long cEnd = getIpNum("192.168.255.255");
|
||||
isInnerIp =
|
||||
isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || ipAddress.equals("127.0.0.1");
|
||||
return isInnerIp;
|
||||
}
|
||||
|
||||
private static long getIpNum(String ipAddress) {
|
||||
String[] ip = ipAddress.split("\\.");
|
||||
long a = Integer.parseInt(ip[0]);
|
||||
long b = Integer.parseInt(ip[1]);
|
||||
long c = Integer.parseInt(ip[2]);
|
||||
long d = Integer.parseInt(ip[3]);
|
||||
|
||||
return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;
|
||||
}
|
||||
|
||||
private static boolean isInner(long userIp, long begin, long end) {
|
||||
return (userIp >= begin) && (userIp <= end);
|
||||
}
|
||||
|
||||
public static String getRealIP(HttpServletRequest request) {
|
||||
// 获取客户端ip地址
|
||||
String clientIp = request.getHeader("x-forwarded-for");
|
||||
|
||||
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
|
||||
clientIp = request.getRemoteAddr();
|
||||
}
|
||||
|
||||
String[] clientIps = clientIp.split(",");
|
||||
if (clientIps.length <= 1) return clientIp.trim();
|
||||
|
||||
// 判断是否来自CDN
|
||||
if (isComefromCDN(request)) {
|
||||
if (clientIps.length >= 2) return clientIps[clientIps.length - 2].trim();
|
||||
}
|
||||
|
||||
return clientIps[clientIps.length - 1].trim();
|
||||
}
|
||||
|
||||
private static boolean isComefromCDN(HttpServletRequest request) {
|
||||
String host = request.getHeader("host");
|
||||
return host.contains("www.189.cn") || host.contains("shouji.189.cn") || host.contains("image2.chinatelecom-ec" +
|
||||
".com") || host.contains("image1.chinatelecom-ec.com");
|
||||
}
|
||||
|
||||
// public static synchronized String getRegion(String ip) {
|
||||
// if (StrKit.isBlank(ip)) return null;
|
||||
// boolean isIpAddress = Util.isIpAddress(ip);
|
||||
// if (!isIpAddress) return null;
|
||||
// try {
|
||||
// if (searcher == null) {
|
||||
// if (null == config) config = new DbConfig();
|
||||
// if (null == dbPath) dbPath = ReqUtil.class.getResource("/ip2region/ip2region.db").getPath();
|
||||
// searcher = new DbSearcher(config, dbPath);
|
||||
// }
|
||||
//
|
||||
// DataBlock dataBlock = searcher.binarySearch(ip);
|
||||
// return dataBlock.getRegion();
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.gunshi.project.xyt.system.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Description:
|
||||
* Created by XuSan on 2024/6/25.
|
||||
*
|
||||
* @author XuSan
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class TodayCountVo {
|
||||
|
||||
@Schema(description = "WEB端访问次数")
|
||||
private Long web1Count;
|
||||
|
||||
@Schema(description = "WEB端浏览次数")
|
||||
private Long web2Count;
|
||||
|
||||
@Schema(description = "WEB端平均访问时长")
|
||||
private BigDecimal web3Count;
|
||||
|
||||
@Schema(description = "移动端访问次数")
|
||||
private Long app1Count;
|
||||
|
||||
@Schema(description = "移动端浏览次数")
|
||||
private Long app2Count;
|
||||
|
||||
@Schema(description = "移动端平均访问时长")
|
||||
private BigDecimal app3Count;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.gunshi.project.xyt.system.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.gunshi.core.dateformat.DateFormatString;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Description:
|
||||
* Created by XuSan on 2024/6/25.
|
||||
*
|
||||
* @author XuSan
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class UserCountVo {
|
||||
|
||||
@Schema(description = "web统计数据")
|
||||
private List<UserCountDataVo> webList;
|
||||
|
||||
@Schema(description = "app统计数据")
|
||||
private List<UserCountDataVo> appList;
|
||||
|
||||
@Data
|
||||
public static class UserCountDataVo {
|
||||
|
||||
@Schema(description="日期")
|
||||
@JsonFormat(pattern = DateFormatString.YYYY_MM_DD, timezone = "GMT+8")
|
||||
private Date createDate;
|
||||
|
||||
@Schema(description = "统计数据")
|
||||
private Long count;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.gunshi.project.xyt.system.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Description:
|
||||
* Created by XuSan on 2024/6/25.
|
||||
*
|
||||
* @author XuSan
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class VisitCountVo {
|
||||
|
||||
@Schema(description = "web统计数据")
|
||||
private List<VisitCountDataVo> webList;
|
||||
|
||||
@Schema(description = "app统计数据")
|
||||
private List<VisitCountDataVo> appList;
|
||||
|
||||
@Data
|
||||
public static class VisitCountDataVo {
|
||||
|
||||
@Schema(description = "名字")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "统计数据")
|
||||
private Long count;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.gunshi.project.xf.flood.controller.system.mapper.SysUserLoginLogMapper">
|
||||
|
||||
</mapper>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.gunshi.project.xf.flood.controller.system.mapper.SysVisitMenuLogMapper">
|
||||
|
||||
</mapper>
|
||||
Loading…
Reference in New Issue