diff --git a/src/main/java/com/gunshi/project/xyt/controller/AttResBaseController.java b/src/main/java/com/gunshi/project/xyt/controller/AttResBaseController.java index 59f0da0..4ddabbe 100644 --- a/src/main/java/com/gunshi/project/xyt/controller/AttResBaseController.java +++ b/src/main/java/com/gunshi/project/xyt/controller/AttResBaseController.java @@ -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(@PathVariable("resCode") String resCode) { + List files = fileService.getFiles(getGroupId(), resCode); + if (CollectionUtils.isEmpty(files)){ + return R.ok(files); + } + List datas = files.stream().filter(o -> "1".equals(o.getType())) + .collect(Collectors.toList()); + return R.ok(datas); + } + // @Operation(summary = "分页") // @PostMapping("/page") public R> page() { diff --git a/src/main/java/com/gunshi/project/xyt/controller/ResMonthEcoFlowController.java b/src/main/java/com/gunshi/project/xyt/controller/ResMonthEcoFlowController.java index 870dfc6..ab7f5c1 100644 --- a/src/main/java/com/gunshi/project/xyt/controller/ResMonthEcoFlowController.java +++ b/src/main/java/com/gunshi/project/xyt/controller/ResMonthEcoFlowController.java @@ -62,7 +62,7 @@ public class ResMonthEcoFlowController { @Operation(summary = "列表") @PostMapping("/list") - public R> list(@Validated ResMonthEcoFlowListSo vo) { + public R> 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()); diff --git a/src/main/java/com/gunshi/project/xyt/mapper/FileAssociationsMapper.java b/src/main/java/com/gunshi/project/xyt/mapper/FileAssociationsMapper.java index 47caa75..a3e37e1 100644 --- a/src/main/java/com/gunshi/project/xyt/mapper/FileAssociationsMapper.java +++ b/src/main/java/com/gunshi/project/xyt/mapper/FileAssociationsMapper.java @@ -21,6 +21,7 @@ public interface FileAssociationsMapper extends BaseMapper { SELECT fa.*, fd.file_name, + fd.file_size, fd.file_path FROM file_associations fa diff --git a/src/main/java/com/gunshi/project/xyt/model/AttResBase.java b/src/main/java/com/gunshi/project/xyt/model/AttResBase.java index 1086a1c..6e33a71 100644 --- a/src/main/java/com/gunshi/project/xyt/model/AttResBase.java +++ b/src/main/java/com/gunshi/project/xyt/model/AttResBase.java @@ -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 = "文件集合") diff --git a/src/main/java/com/gunshi/project/xyt/model/FileAssociations.java b/src/main/java/com/gunshi/project/xyt/model/FileAssociations.java index 01385b5..069a7d8 100644 --- a/src/main/java/com/gunshi/project/xyt/model/FileAssociations.java +++ b/src/main/java/com/gunshi/project/xyt/model/FileAssociations.java @@ -104,4 +104,8 @@ public class FileAssociations implements Serializable { @Schema(description = "文件名称") private String fileName; + @TableField(exist = false) + @Schema(description = "文件大小 (byte)") + private String fileSize; + } \ No newline at end of file diff --git a/src/main/java/com/gunshi/project/xyt/model/ResSafePersonB.java b/src/main/java/com/gunshi/project/xyt/model/ResSafePersonB.java index 71f32dc..5d6dcb0 100644 --- a/src/main/java/com/gunshi/project/xyt/model/ResSafePersonB.java +++ b/src/main/java/com/gunshi/project/xyt/model/ResSafePersonB.java @@ -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; /** diff --git a/src/main/java/com/gunshi/project/xyt/service/FileAssociationsService.java b/src/main/java/com/gunshi/project/xyt/service/FileAssociationsService.java index a0025b0..ea534d0 100644 --- a/src/main/java/com/gunshi/project/xyt/service/FileAssociationsService.java +++ b/src/main/java/com/gunshi/project/xyt/service/FileAssociationsService.java @@ -51,7 +51,7 @@ public class FileAssociationsService extends ServiceImpl !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> page(@RequestBody @Validated UserLoginLogPageSo dto) { + LambdaQueryWrapper 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 todayCount() { + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(SysUserLoginLog.class) + .between(SysUserLoginLog::getCreateDate, DateUtil.convertStringToDate(LocalDate.now().toString() + " 00:00:00"), new Date()); + + List 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 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 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 wrapperMenuLog = Wrappers.lambdaQuery(SysVisitMenuLog.class) + .eq(SysVisitMenuLog::getCreateTime, new Date()); + + vo.setWeb2Count(0L); + vo.setApp2Count(0L); + + List 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 visitCount(@RequestBody @Validated UserLoginLogSo so) { + + List 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 userCount(@RequestBody @Validated UserLoginLogSo so) { + + List 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 insert(@RequestBody @Validated SysUserLoginLog dto) { + + if (Objects.isNull(dto.getCreateId())) { +// Long loginUserId = projectCommonService.getLoginUserId(); +// dto.setCreateId(loginUserId); + } + + // 查询当前时间是否存在 + List 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); + } + +} diff --git a/src/main/java/com/gunshi/project/xyt/system/SysVisitMenuLogController.java b/src/main/java/com/gunshi/project/xyt/system/SysVisitMenuLogController.java new file mode 100644 index 0000000..7d03965 --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/SysVisitMenuLogController.java @@ -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(@RequestBody @Validated VisitMenuLogPageSo dto) { + LambdaQueryWrapper 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> count(@RequestBody @Validated VisitMenuLogPageSo dto) { + + LambdaQueryWrapper 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 list = thisMapper.selectList(queryWrapper); + + + return R.ok( + list + .stream() + .sorted( + Comparator + .comparing(SysVisitMenuLog::getCount) + .reversed() + ) + .collect(Collectors.toList()) + ); + } + + @Post(path = "/insert", summary = "添加") + public R 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); + } + +} diff --git a/src/main/java/com/gunshi/project/xyt/system/aspect/SysUserLogAspect.java b/src/main/java/com/gunshi/project/xyt/system/aspect/SysUserLogAspect.java new file mode 100644 index 0000000..3bacf00 --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/aspect/SysUserLogAspect.java @@ -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 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("记录日志切面结束"); + + } + + +} diff --git a/src/main/java/com/gunshi/project/xyt/system/mapper/SysUserLoginLogMapper.java b/src/main/java/com/gunshi/project/xyt/system/mapper/SysUserLoginLogMapper.java new file mode 100644 index 0000000..082c235 --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/mapper/SysUserLoginLogMapper.java @@ -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 { + + @Select(""" + + """) + List getUserLoginLog(@Param("stm") Date stm , @Param("etm") Date etm); + +} \ No newline at end of file diff --git a/src/main/java/com/gunshi/project/xyt/system/mapper/SysVisitMenuLogMapper.java b/src/main/java/com/gunshi/project/xyt/system/mapper/SysVisitMenuLogMapper.java new file mode 100644 index 0000000..a2f86ba --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/mapper/SysVisitMenuLogMapper.java @@ -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 { +} \ No newline at end of file diff --git a/src/main/java/com/gunshi/project/xyt/system/model/SysUserLoginLog.java b/src/main/java/com/gunshi/project/xyt/system/model/SysUserLoginLog.java new file mode 100644 index 0000000..aabe067 --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/model/SysUserLoginLog.java @@ -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; +} \ No newline at end of file diff --git a/src/main/java/com/gunshi/project/xyt/system/model/SysVisitMenuLog.java b/src/main/java/com/gunshi/project/xyt/system/model/SysVisitMenuLog.java new file mode 100644 index 0000000..6b211e4 --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/model/SysVisitMenuLog.java @@ -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; + +} \ No newline at end of file diff --git a/src/main/java/com/gunshi/project/xyt/system/so/UserLoginLogPageSo.java b/src/main/java/com/gunshi/project/xyt/system/so/UserLoginLogPageSo.java new file mode 100644 index 0000000..eceb8d1 --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/so/UserLoginLogPageSo.java @@ -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; + +} diff --git a/src/main/java/com/gunshi/project/xyt/system/so/UserLoginLogSo.java b/src/main/java/com/gunshi/project/xyt/system/so/UserLoginLogSo.java new file mode 100644 index 0000000..2e245e1 --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/so/UserLoginLogSo.java @@ -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; + +} diff --git a/src/main/java/com/gunshi/project/xyt/system/so/VisitMenuLogPageSo.java b/src/main/java/com/gunshi/project/xyt/system/so/VisitMenuLogPageSo.java new file mode 100644 index 0000000..d1d8cf5 --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/so/VisitMenuLogPageSo.java @@ -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; + +} diff --git a/src/main/java/com/gunshi/project/xyt/system/utils/ReqUtil.java b/src/main/java/com/gunshi/project/xyt/system/utils/ReqUtil.java new file mode 100644 index 0000000..f2e22a5 --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/utils/ReqUtil.java @@ -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; +// } +} diff --git a/src/main/java/com/gunshi/project/xyt/system/vo/TodayCountVo.java b/src/main/java/com/gunshi/project/xyt/system/vo/TodayCountVo.java new file mode 100644 index 0000000..9e56315 --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/vo/TodayCountVo.java @@ -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; + +} diff --git a/src/main/java/com/gunshi/project/xyt/system/vo/UserCountVo.java b/src/main/java/com/gunshi/project/xyt/system/vo/UserCountVo.java new file mode 100644 index 0000000..20c4567 --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/vo/UserCountVo.java @@ -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 webList; + + @Schema(description = "app统计数据") + private List 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; + } +} diff --git a/src/main/java/com/gunshi/project/xyt/system/vo/VisitCountVo.java b/src/main/java/com/gunshi/project/xyt/system/vo/VisitCountVo.java new file mode 100644 index 0000000..644af7d --- /dev/null +++ b/src/main/java/com/gunshi/project/xyt/system/vo/VisitCountVo.java @@ -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 webList; + + @Schema(description = "app统计数据") + private List appList; + + @Data + public static class VisitCountDataVo { + + @Schema(description = "名字") + private String name; + + @Schema(description = "统计数据") + private Long count; + } +} diff --git a/src/main/resources/mapper/SysUserLoginLogMapper.xml b/src/main/resources/mapper/SysUserLoginLogMapper.xml new file mode 100644 index 0000000..7d18ef1 --- /dev/null +++ b/src/main/resources/mapper/SysUserLoginLogMapper.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/SysVisitMenuLogMapper.xml b/src/main/resources/mapper/SysVisitMenuLogMapper.xml new file mode 100644 index 0000000..728220b --- /dev/null +++ b/src/main/resources/mapper/SysVisitMenuLogMapper.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file