feat(oa): 新增用户活跃统计功能并完善个人报告统计
- 新增用户活跃统计模块,包括实体类、业务接口和实现、控制器及Mapper - 实现用户登录时记录当日活跃数据 - 在个人报告中增加活跃天数、报工信息、出差信息、项目信息等统计维度 - 添加工程异常统计和关键采购任务统计功能 - 完善任务信息统计,包括发放任务、承担任务及其状态分析 -优化个人报告接口,支持更全面的工作数据展示
This commit is contained in:
@@ -15,6 +15,7 @@ import com.ruoyi.fadapp.domain.vo.NickDeptVo;
|
||||
import com.ruoyi.fadapp.service.IFadAppAuthService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
import com.ruoyi.system.service.SysPermissionService;
|
||||
import com.ruoyi.oa.service.IOaUserActiveService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -35,6 +36,7 @@ public class FadAppAuthServiceImpl implements IFadAppAuthService {
|
||||
|
||||
private final ISysUserService userService;
|
||||
private final SysPermissionService permissionService;
|
||||
private final IOaUserActiveService userActiveService;
|
||||
|
||||
/**
|
||||
* 验证码缓存前缀
|
||||
@@ -106,6 +108,11 @@ public class FadAppAuthServiceImpl implements IFadAppAuthService {
|
||||
LoginHelper.loginByDevice(loginUser, DeviceType.APP);
|
||||
String token = StpUtil.getTokenValue();
|
||||
|
||||
// 记录用户当日活跃(登录)
|
||||
if (user.getUserId() != null) {
|
||||
userActiveService.recordTodayLogin(user.getUserId());
|
||||
}
|
||||
|
||||
// 构建登录结果
|
||||
LoginResultVo result = new LoginResultVo();
|
||||
result.setToken(token);
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.ruoyi.system.domain.vo.RouterVo;
|
||||
import com.ruoyi.system.service.ISysMenuService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
import com.ruoyi.system.service.SysLoginService;
|
||||
import com.ruoyi.oa.service.IOaUserActiveService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -39,6 +40,7 @@ public class SysLoginController {
|
||||
private final SysLoginService loginService;
|
||||
private final ISysMenuService menuService;
|
||||
private final ISysUserService userService;
|
||||
private final IOaUserActiveService userActiveService;
|
||||
|
||||
/**
|
||||
* 登录方法
|
||||
@@ -54,6 +56,10 @@ public class SysLoginController {
|
||||
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
|
||||
loginBody.getUuid());
|
||||
ajax.put(Constants.TOKEN, token);
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (userId != null) {
|
||||
userActiveService.recordTodayLogin(userId);
|
||||
}
|
||||
return R.ok(ajax);
|
||||
}
|
||||
|
||||
|
||||
@@ -135,4 +135,5 @@ public class OaProjectScheduleStepController extends BaseController {
|
||||
) {
|
||||
return R.ok(iOaProjectScheduleStepService.personalReport(poolId, nickName));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.ruoyi.oa.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.*;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import com.ruoyi.common.annotation.RepeatSubmit;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.PageQuery;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.core.validate.AddGroup;
|
||||
import com.ruoyi.common.core.validate.EditGroup;
|
||||
import com.ruoyi.common.core.validate.QueryGroup;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.oa.domain.vo.OaUserActiveVo;
|
||||
import com.ruoyi.oa.domain.bo.OaUserActiveBo;
|
||||
import com.ruoyi.oa.service.IOaUserActiveService;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 用户活跃统计
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/oa/userActive")
|
||||
public class OaUserActiveController extends BaseController {
|
||||
|
||||
private final IOaUserActiveService iOaUserActiveService;
|
||||
|
||||
/**
|
||||
* 查询用户活跃统计列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<OaUserActiveVo> list(OaUserActiveBo bo, PageQuery pageQuery) {
|
||||
return iOaUserActiveService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出用户活跃统计列表
|
||||
*/
|
||||
@Log(title = "用户活跃统计", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(OaUserActiveBo bo, HttpServletResponse response) {
|
||||
List<OaUserActiveVo> list = iOaUserActiveService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "用户活跃统计", OaUserActiveVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户活跃统计详细信息
|
||||
*
|
||||
* @param activeId 主键
|
||||
*/
|
||||
@GetMapping("/{activeId}")
|
||||
public R<OaUserActiveVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long activeId) {
|
||||
return R.ok(iOaUserActiveService.queryById(activeId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增用户活跃统计
|
||||
*/
|
||||
@Log(title = "用户活跃统计", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody OaUserActiveBo bo) {
|
||||
return toAjax(iOaUserActiveService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户活跃统计
|
||||
*/
|
||||
@Log(title = "用户活跃统计", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody OaUserActiveBo bo) {
|
||||
return toAjax(iOaUserActiveService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户活跃统计
|
||||
*
|
||||
* @param activeIds 主键串
|
||||
*/
|
||||
@Log(title = "用户活跃统计", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{activeIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] activeIds) {
|
||||
return toAjax(iOaUserActiveService.deleteWithValidByIds(Arrays.asList(activeIds), true));
|
||||
}
|
||||
}
|
||||
54
ruoyi-oa/src/main/java/com/ruoyi/oa/domain/OaUserActive.java
Normal file
54
ruoyi-oa/src/main/java/com/ruoyi/oa/domain/OaUserActive.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package com.ruoyi.oa.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 用户活跃统计对象 oa_user_active
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("oa_user_active")
|
||||
public class OaUserActive extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID=1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "active_id")
|
||||
private Long activeId;
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 活跃日期
|
||||
*/
|
||||
private Date activeDate;
|
||||
/**
|
||||
* 当日登录次数
|
||||
*/
|
||||
private Long loginCount;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 删除标志:0=正常,1=已删除
|
||||
*/
|
||||
@TableLogic
|
||||
private Integer delFlag;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.ruoyi.oa.domain.bo;
|
||||
|
||||
import com.ruoyi.common.core.validate.AddGroup;
|
||||
import com.ruoyi.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import javax.validation.constraints.*;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 用户活跃统计业务对象 oa_user_active
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class OaUserActiveBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long activeId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 活跃日期
|
||||
*/
|
||||
private Date activeDate;
|
||||
|
||||
/**
|
||||
* 当日登录次数
|
||||
*/
|
||||
private Long loginCount;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import com.ruoyi.oa.domain.OaProjectScheduleStep;
|
||||
import com.ruoyi.oa.domain.SysOaProject;
|
||||
import com.ruoyi.oa.domain.SysOaTask;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -20,10 +22,35 @@ public class PersonalReportDTO {
|
||||
|
||||
/** 进度统计信息 */
|
||||
private ProgressStats progressStats;
|
||||
/** 用户负责的进度步骤列表 */
|
||||
private List<OaProjectScheduleStep> userSteps;
|
||||
|
||||
//nickname和projectId关联的任务
|
||||
private List<SysOaTask> tasks;
|
||||
|
||||
/** 活跃天数 */
|
||||
private Integer activeDays;
|
||||
|
||||
/** 报工统计 */
|
||||
private PersonalReportDTO.WorkReportStats workReportStats;
|
||||
|
||||
/** 出差统计 */
|
||||
private PersonalReportDTO.BusinessTripStats businessTripStats;
|
||||
|
||||
/** 项目统计 */
|
||||
private PersonalReportDTO.ProjectStats projectStats;
|
||||
|
||||
// /** 进度统计 */
|
||||
// private PersonalReportDTO.ProgressStats progressStats;
|
||||
|
||||
/** 任务统计 */
|
||||
private PersonalReportDTO.TaskStats taskStats;
|
||||
|
||||
/** 工程异常统计 */
|
||||
private PersonalReportDTO.EngineeringExceptionStats exceptionStats;
|
||||
|
||||
/** 关键采购任务统计 */
|
||||
private PersonalReportDTO.ProcurementTaskStats procurementStats;
|
||||
/**
|
||||
* 进度统计内部类(封装total、completed等字段)
|
||||
*/
|
||||
@@ -38,4 +65,206 @@ public class PersonalReportDTO {
|
||||
/** 延期进度数 */
|
||||
private Long delayed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 报工统计
|
||||
*/
|
||||
@Data
|
||||
public static class WorkReportStats {
|
||||
/** 总报工天数 */
|
||||
private BigDecimal totalWorkDays;
|
||||
/** 有效报工天数 */
|
||||
private BigDecimal validWorkDays;
|
||||
/** 报工项目数量 */
|
||||
private Integer reportProjectCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 出差统计
|
||||
*/
|
||||
@Data
|
||||
public static class BusinessTripStats {
|
||||
/** 总出差天数 */
|
||||
private BigDecimal totalTripDays;
|
||||
/** 国内出差天数 */
|
||||
private BigDecimal domesticTripDays;
|
||||
/** 国外出差天数 */
|
||||
private BigDecimal foreignTripDays;
|
||||
/** 出差项目数量 */
|
||||
private Integer tripProjectCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目统计
|
||||
*/
|
||||
@Data
|
||||
public static class ProjectStats {
|
||||
/** 涉及项目总数 */
|
||||
private Integer totalProjects;
|
||||
/** 负责项目数量 */
|
||||
private Integer responsibleProjects;
|
||||
/** 参与项目数量 */
|
||||
private Integer participatedProjects;
|
||||
/** 项目清单 */
|
||||
private List<PersonalReportDTO.ProjectSummary> projectList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目摘要
|
||||
*/
|
||||
@Data
|
||||
public static class ProjectSummary {
|
||||
/** 项目ID */
|
||||
private Long projectId;
|
||||
/** 项目名称 */
|
||||
private String projectName;
|
||||
/** 项目编号 */
|
||||
private String projectNum;
|
||||
/** 参与角色 */
|
||||
private String role;
|
||||
/** 参与天数 */
|
||||
private BigDecimal participationDays;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 进度统计
|
||||
// */
|
||||
// @Data
|
||||
// public static class ProgressStats {
|
||||
// /** 涉及进度总数 */
|
||||
// private Integer totalProgress;
|
||||
// /** 已完成进度数 */
|
||||
// private Integer completedProgress;
|
||||
// /** 进行中进度数 */
|
||||
// private Integer inProgressCount;
|
||||
// /** 延期进度数 */
|
||||
// private Integer delayedProgress;
|
||||
// /** 进度清单 */
|
||||
// private List<PersonalReportDTO.ProgressSummary> progressList;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 进度摘要
|
||||
*/
|
||||
@Data
|
||||
public static class ProgressSummary {
|
||||
/** 进度ID */
|
||||
private Long trackId;
|
||||
/** 步骤名称 */
|
||||
private String stepName;
|
||||
/** 项目名称 */
|
||||
private String projectName;
|
||||
/** 进度状态 */
|
||||
private Long status;
|
||||
/** 是否延期 */
|
||||
private Boolean isDelayed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务统计
|
||||
*/
|
||||
@Data
|
||||
public static class TaskStats {
|
||||
/** 发放任务数量 */
|
||||
private Integer assignedTasks;
|
||||
/** 承担任务数量 */
|
||||
private Integer undertakenTasks;
|
||||
/** 已完成任务数量 */
|
||||
private Integer completedTasks;
|
||||
/** 设置进行中任务数量 */
|
||||
private Integer underwayTasks;
|
||||
/** 待完成任务数量 */
|
||||
private Integer unfinishedTasks;
|
||||
/** 延期任务数量 */
|
||||
private Integer delayedTasks;
|
||||
/** 发放任务清单 */
|
||||
private List<PersonalReportDTO.TaskSummary> assignedTaskList;
|
||||
/** 承担任务清单 */
|
||||
private List<PersonalReportDTO.TaskSummary> undertakenTaskList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务摘要
|
||||
*/
|
||||
@Data
|
||||
public static class TaskSummary {
|
||||
/** 任务ID */
|
||||
private Long taskId;
|
||||
/** 任务主题 */
|
||||
private String taskTitle;
|
||||
/** 项目名称 */
|
||||
private String projectName;
|
||||
/** 任务状态 */
|
||||
private Long state;
|
||||
/** 是否延期 */
|
||||
private Boolean isDelayed;
|
||||
/** 延期次数 */
|
||||
private Long postponements;
|
||||
}
|
||||
|
||||
/**
|
||||
* 工程异常统计
|
||||
*/
|
||||
@Data
|
||||
public static class EngineeringExceptionStats {
|
||||
/** 承担异常数量 */
|
||||
private Integer totalExceptions;
|
||||
/** 延期异常数量 */
|
||||
private Integer delayedExceptions;
|
||||
/** 已解决异常数量 */
|
||||
private Integer resolvedExceptions;
|
||||
/** 异常清单 */
|
||||
private List<PersonalReportDTO.ExceptionSummary> exceptionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常摘要
|
||||
*/
|
||||
@Data
|
||||
public static class ExceptionSummary {
|
||||
/** 异常ID */
|
||||
private Long exceptionId;
|
||||
/** 异常描述 */
|
||||
private String description;
|
||||
/** 项目名称 */
|
||||
private String projectName;
|
||||
/** 异常状态 */
|
||||
private String status;
|
||||
/** 是否延期 */
|
||||
private Boolean isDelayed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关键采购任务统计
|
||||
*/
|
||||
@Data
|
||||
public static class ProcurementTaskStats {
|
||||
/** 关键采购任务总数 */
|
||||
private Integer totalProcurementTasks;
|
||||
/** 已完成采购任务数 */
|
||||
private Integer completedProcurementTasks;
|
||||
/** 延期采购任务数 */
|
||||
private Integer delayedProcurementTasks;
|
||||
/** 采购任务清单 */
|
||||
private List<PersonalReportDTO.ProcurementTaskSummary> procurementTaskList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 采购任务摘要
|
||||
*/
|
||||
@Data
|
||||
public static class ProcurementTaskSummary {
|
||||
/** 采购任务ID */
|
||||
private Long procurementId;
|
||||
/** 采购内容 */
|
||||
private String procurementContent;
|
||||
/** 项目名称 */
|
||||
private String projectName;
|
||||
/** 采购状态 */
|
||||
private String status;
|
||||
/** 是否延期 */
|
||||
private Boolean isDelayed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.ruoyi.oa.domain.vo;
|
||||
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.ruoyi.common.annotation.ExcelDictFormat;
|
||||
import com.ruoyi.common.convert.ExcelDictConvert;
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 用户活跃统计视图对象 oa_user_active
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class OaUserActiveVo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long activeId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 活跃日期
|
||||
*/
|
||||
@ExcelProperty(value = "活跃日期")
|
||||
private Date activeDate;
|
||||
|
||||
/**
|
||||
* 当日登录次数
|
||||
*/
|
||||
@ExcelProperty(value = "当日登录次数")
|
||||
private Long loginCount;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ruoyi.oa.mapper;
|
||||
|
||||
import com.ruoyi.oa.domain.OaUserActive;
|
||||
import com.ruoyi.oa.domain.vo.OaUserActiveVo;
|
||||
import com.ruoyi.common.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 用户活跃统计Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
public interface OaUserActiveMapper extends BaseMapperPlus<OaUserActiveMapper, OaUserActive, OaUserActiveVo> {
|
||||
|
||||
}
|
||||
@@ -73,4 +73,5 @@ public interface IOaProjectScheduleStepService{
|
||||
List<Map<String, Object>> queryProgressByHeader();
|
||||
|
||||
PersonalReportDTO personalReport(Long poolId, String nickName);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.ruoyi.oa.service;
|
||||
|
||||
import com.ruoyi.oa.domain.OaUserActive;
|
||||
import com.ruoyi.oa.domain.vo.OaUserActiveVo;
|
||||
import com.ruoyi.oa.domain.bo.OaUserActiveBo;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.domain.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户活跃统计Service接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
public interface IOaUserActiveService {
|
||||
|
||||
/**
|
||||
* 查询用户活跃统计
|
||||
*/
|
||||
OaUserActiveVo queryById(Long activeId);
|
||||
|
||||
/**
|
||||
* 查询用户活跃统计列表
|
||||
*/
|
||||
TableDataInfo<OaUserActiveVo> queryPageList(OaUserActiveBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询用户活跃统计列表
|
||||
*/
|
||||
List<OaUserActiveVo> queryList(OaUserActiveBo bo);
|
||||
|
||||
/**
|
||||
* 新增用户活跃统计
|
||||
*/
|
||||
Boolean insertByBo(OaUserActiveBo bo);
|
||||
|
||||
/**
|
||||
* 修改用户活跃统计
|
||||
*/
|
||||
Boolean updateByBo(OaUserActiveBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除用户活跃统计信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
boolean hasActiveToday(Long userId);
|
||||
|
||||
void recordTodayLogin(Long userId);
|
||||
}
|
||||
@@ -4,9 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.mapper.BaseMapperPlus;
|
||||
import com.ruoyi.common.helper.LoginHelper;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
@@ -17,11 +15,20 @@ import com.ruoyi.oa.domain.*;
|
||||
import com.ruoyi.oa.domain.bo.BatchBo;
|
||||
import com.ruoyi.oa.domain.dto.NodeDTO;
|
||||
import com.ruoyi.oa.domain.dto.PersonalReportDTO;
|
||||
import com.ruoyi.oa.domain.vo.OaExpressVo;
|
||||
import com.ruoyi.oa.mapper.*;
|
||||
import com.ruoyi.oa.mapper.OaProjectReportMapper;
|
||||
import com.ruoyi.oa.mapper.SysOaTaskMapper;
|
||||
import com.ruoyi.oa.mapper.OaUserActiveMapper;
|
||||
import com.ruoyi.oa.mapper.OaExpressQuestionMapper;
|
||||
import com.ruoyi.oa.mapper.OaRequirementsMapper;
|
||||
import com.ruoyi.oa.service.IOaExpressService;
|
||||
import com.ruoyi.oa.service.ISysOaTaskService;
|
||||
import com.ruoyi.system.mapper.SysUserMapper;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.flowable.job.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.oa.domain.bo.OaProjectScheduleStepBo;
|
||||
import com.ruoyi.oa.domain.vo.OaProjectScheduleStepVo;
|
||||
@@ -59,6 +66,18 @@ public class OaProjectScheduleStepServiceImpl implements IOaProjectScheduleStepS
|
||||
private final OaProjectScheduleStepMapper projectScheduleStepMapper;
|
||||
|
||||
private final ISysOaTaskService sysOaTaskService;
|
||||
|
||||
private final OaProjectReportMapper projectReportMapper;
|
||||
|
||||
private final SysOaTaskMapper taskMapper;
|
||||
|
||||
private final OaUserActiveMapper userActiveMapper;
|
||||
|
||||
private final OaExpressQuestionMapper expressQuestionMapper;
|
||||
|
||||
private final OaRequirementsMapper requirementsMapper;
|
||||
|
||||
private final IOaExpressService oaExpressService;
|
||||
|
||||
|
||||
|
||||
@@ -358,6 +377,7 @@ public class OaProjectScheduleStepServiceImpl implements IOaProjectScheduleStepS
|
||||
if (user == null) {
|
||||
throw new RuntimeException("未找到用户:" + nickName);
|
||||
}
|
||||
Long userId = user.getUserId();
|
||||
|
||||
// 查询奖金池关联的项目ID
|
||||
List<OaBonusProjectRel> rels = bonusProjectRelMapper.selectList(
|
||||
@@ -444,9 +464,474 @@ public class OaProjectScheduleStepServiceImpl implements IOaProjectScheduleStepS
|
||||
result.setProgressStats(progressStats);
|
||||
result.setUserSteps(userSteps); // 此时userSteps已包含每个步骤对应的projectId
|
||||
result.setTasks(tasks);
|
||||
// 统计活跃天数
|
||||
result.setActiveDays(getActiveDays(userId, startTime, endTime));
|
||||
// 1. 统计报工信息
|
||||
result.setWorkReportStats(getWorkReportStats(userId, startTime, endTime));
|
||||
|
||||
// 2. 统计出差信息
|
||||
result.setBusinessTripStats(getBusinessTripStats(userId, startTime, endTime));
|
||||
|
||||
// 3. 统计项目信息
|
||||
result.setProjectStats(getProjectStats(userId, nickName, startTime, endTime));
|
||||
|
||||
// // 4. 统计进度信息
|
||||
// result.setProgressStats(getProgressStats(nickName, startDate, endDate));
|
||||
|
||||
// 5. 统计任务信息
|
||||
result.setTaskStats(getTaskStats(userId, startTime, endTime));
|
||||
|
||||
// 6. 统计工程异常信息
|
||||
result.setExceptionStats(getExceptionStats(nickName, startTime, endTime));
|
||||
|
||||
// 7. 统计关键采购任务信息
|
||||
result.setProcurementStats(getProcurementStats(userId, startTime, endTime));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计用户活跃天数
|
||||
* @param userId 用户ID
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return 活跃天数
|
||||
*/
|
||||
private Integer getActiveDays(Long userId, Date startDate, Date endDate) {
|
||||
// 构建查询条件
|
||||
LambdaQueryWrapper<OaUserActive> wrapper = Wrappers.<OaUserActive>lambdaQuery()
|
||||
.eq(OaUserActive::getUserId, userId)
|
||||
.eq(OaUserActive::getDelFlag, 0);
|
||||
|
||||
// 添加时间范围条件
|
||||
if (startDate != null && endDate != null) {
|
||||
wrapper.between(OaUserActive::getActiveDate, startDate, endDate);
|
||||
}
|
||||
|
||||
// 查询活跃记录数量
|
||||
Long count = userActiveMapper.selectCount(wrapper);
|
||||
|
||||
return count != null ? count.intValue() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计报工信息
|
||||
*/
|
||||
private PersonalReportDTO.WorkReportStats getWorkReportStats(Long userId, Date startDate, Date endDate) {
|
||||
PersonalReportDTO.WorkReportStats stats = new PersonalReportDTO.WorkReportStats();
|
||||
|
||||
LambdaQueryWrapper<OaProjectReport> wrapper = Wrappers.<OaProjectReport>lambdaQuery()
|
||||
.eq(OaProjectReport::getDelFlag, 0)
|
||||
.eq(OaProjectReport::getUserId, userId);
|
||||
|
||||
// 添加时间范围条件
|
||||
if (startDate != null && endDate != null) {
|
||||
wrapper.between(OaProjectReport::getCreateTime, startDate, endDate);
|
||||
}
|
||||
|
||||
List<OaProjectReport> reports = projectReportMapper.selectList(wrapper);
|
||||
|
||||
// 计算报工天数(这里简化处理,实际可能需要按日期去重)
|
||||
stats.setTotalWorkDays(BigDecimal.valueOf(reports.size()));
|
||||
stats.setValidWorkDays(BigDecimal.valueOf(reports.size()));
|
||||
|
||||
// 统计涉及的项目数量
|
||||
Set<Long> projectIds = reports.stream()
|
||||
.map(OaProjectReport::getProjectId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
stats.setReportProjectCount(projectIds.size());
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计出差信息
|
||||
*/
|
||||
private PersonalReportDTO.BusinessTripStats getBusinessTripStats(Long userId, Date startDate, Date endDate) {
|
||||
PersonalReportDTO.BusinessTripStats stats = new PersonalReportDTO.BusinessTripStats();
|
||||
|
||||
LambdaQueryWrapper<OaProjectReport> wrapper = Wrappers.<OaProjectReport>lambdaQuery()
|
||||
.eq(OaProjectReport::getDelFlag, 0)
|
||||
.eq(OaProjectReport::getIsTrip, 1) // 出差标记
|
||||
.eq(OaProjectReport::getUserId, userId);
|
||||
|
||||
// 添加时间范围条件
|
||||
if (startDate != null && endDate != null) {
|
||||
wrapper.between(OaProjectReport::getCreateTime, startDate, endDate);
|
||||
}
|
||||
|
||||
|
||||
// 1. 统计总出差天数(按记录数统计,假设一条记录对应一天)
|
||||
Long totalTripCount = projectReportMapper.selectCount(wrapper);
|
||||
stats.setTotalTripDays(BigDecimal.valueOf(totalTripCount));
|
||||
|
||||
// 国外
|
||||
LambdaQueryWrapper<OaProjectReport> foreignWrapper = Wrappers.<OaProjectReport>lambdaQuery()
|
||||
.eq(OaProjectReport::getDelFlag, 0)
|
||||
.eq(OaProjectReport::getIsTrip, 1)
|
||||
.eq(OaProjectReport::getUserId, userId)
|
||||
.eq(OaProjectReport::getWorkType, 1); // 国外标志
|
||||
if (StringUtils.isNull(startDate) && StringUtils.isNull(endDate)) {
|
||||
foreignWrapper.between(OaProjectReport::getCreateTime, startDate, endDate);
|
||||
}
|
||||
Long foreignTripCount = projectReportMapper.selectCount(foreignWrapper);
|
||||
stats.setForeignTripDays(BigDecimal.valueOf(foreignTripCount));
|
||||
|
||||
// 3. 国内出差天数 = 总出差天数 - 国外出差天数
|
||||
stats.setDomesticTripDays(BigDecimal.valueOf(totalTripCount - foreignTripCount));
|
||||
|
||||
// 统计出差项目数量
|
||||
Set<Long> tripProjectIds = projectReportMapper.selectObjs(wrapper
|
||||
.select(OaProjectReport::getProjectId)) // 只查询project_id字段
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(obj -> (Long) obj)
|
||||
.collect(Collectors.toSet());
|
||||
stats.setTripProjectCount(tripProjectIds.size());
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计项目信息
|
||||
*/
|
||||
private PersonalReportDTO.ProjectStats getProjectStats(Long userId, String nickName, Date startDate, Date endDate) {
|
||||
PersonalReportDTO.ProjectStats stats = new PersonalReportDTO.ProjectStats();
|
||||
|
||||
// 通过报工记录查询参与的项目
|
||||
LambdaQueryWrapper<OaProjectReport> reportWrapper = Wrappers.<OaProjectReport>lambdaQuery()
|
||||
.eq(OaProjectReport::getUserId, userId)
|
||||
.eq(OaProjectReport::getDelFlag, 0);
|
||||
|
||||
// if (startDate != null && endDate != null) {
|
||||
// reportWrapper.between(OaProjectReport::getCreateTime, startDate, endDate);
|
||||
// }
|
||||
|
||||
List<OaProjectReport> reports = projectReportMapper.selectList(reportWrapper);
|
||||
Set<Long> participatedProjectIds = reports.stream()
|
||||
.map(OaProjectReport::getProjectId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 查询负责的项目
|
||||
LambdaQueryWrapper<SysOaProject> projectWrapper = Wrappers.<SysOaProject>lambdaQuery()
|
||||
.eq(SysOaProject::getFunctionary, nickName);
|
||||
List<SysOaProject> responsibleProjectList = projectMapper.selectList(projectWrapper);
|
||||
|
||||
stats.setTotalProjects(participatedProjectIds.size());
|
||||
stats.setResponsibleProjects(responsibleProjectList.size());
|
||||
stats.setParticipatedProjects(participatedProjectIds.size());
|
||||
|
||||
// 构建项目清单
|
||||
List<PersonalReportDTO.ProjectSummary> projectList = new ArrayList<>();
|
||||
|
||||
// 添加负责的项目
|
||||
for (SysOaProject project : responsibleProjectList) {
|
||||
PersonalReportDTO.ProjectSummary summary = new PersonalReportDTO.ProjectSummary();
|
||||
summary.setProjectId(project.getProjectId());
|
||||
summary.setProjectName(project.getProjectName());
|
||||
summary.setProjectNum(project.getProjectNum());
|
||||
summary.setRole("负责人");
|
||||
|
||||
// 计算参与天数
|
||||
//TODO 项目负责人是不报工的
|
||||
long participationDays = reports.stream()
|
||||
.filter(report -> project.getProjectId().equals(report.getProjectId()))
|
||||
.count();
|
||||
summary.setParticipationDays(BigDecimal.valueOf(participationDays));
|
||||
|
||||
projectList.add(summary);
|
||||
}
|
||||
|
||||
// 添加参与的其他项目
|
||||
for (Long projectId : participatedProjectIds) {
|
||||
if (responsibleProjectList.stream().noneMatch(p -> p.getProjectId().equals(projectId))) {
|
||||
SysOaProject project = projectMapper.selectById(projectId);
|
||||
if (project != null) {
|
||||
PersonalReportDTO.ProjectSummary summary = new PersonalReportDTO.ProjectSummary();
|
||||
summary.setProjectId(project.getProjectId());
|
||||
summary.setProjectName(project.getProjectName());
|
||||
summary.setProjectNum(project.getProjectNum());
|
||||
summary.setRole("参与者");
|
||||
|
||||
// 计算参与天数
|
||||
long participationDays = reports.stream()
|
||||
.filter(report -> projectId.equals(report.getProjectId()))
|
||||
.count();
|
||||
summary.setParticipationDays(BigDecimal.valueOf(participationDays));
|
||||
|
||||
projectList.add(summary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stats.setProjectList(projectList);
|
||||
return stats;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 统计任务信息
|
||||
*/
|
||||
private PersonalReportDTO.TaskStats getTaskStats(Long userId, Date startDate, Date endDate) {
|
||||
PersonalReportDTO.TaskStats stats = new PersonalReportDTO.TaskStats();
|
||||
|
||||
// 查询发放的任务(创建的任务)
|
||||
LambdaQueryWrapper<SysOaTask> assignedWrapper = Wrappers.<SysOaTask>lambdaQuery()
|
||||
.eq(SysOaTask::getCreateUserId, userId);
|
||||
|
||||
if (startDate != null && endDate != null) {
|
||||
assignedWrapper.between(SysOaTask::getBeginTime, startDate, endDate);
|
||||
}
|
||||
|
||||
List<SysOaTask> assignedTasks = taskMapper.selectList(assignedWrapper);
|
||||
|
||||
// 查询承担的任务(被分配的任务)
|
||||
LambdaQueryWrapper<SysOaTask> undertakenWrapper = Wrappers.<SysOaTask>lambdaQuery()
|
||||
.eq(SysOaTask::getWorkerId, userId);
|
||||
|
||||
if (startDate != null && endDate != null) {
|
||||
undertakenWrapper.between(SysOaTask::getBeginTime, startDate, endDate);
|
||||
}
|
||||
|
||||
List<SysOaTask> undertakenTasks = taskMapper.selectList(undertakenWrapper);
|
||||
|
||||
// 统计数量
|
||||
stats.setAssignedTasks(assignedTasks.size());
|
||||
stats.setUndertakenTasks(undertakenTasks.size());
|
||||
|
||||
// 统计已完成任务数量(状态为完成)
|
||||
long completedAssigned = assignedTasks.stream().filter(task -> Long.valueOf(2).equals(task.getState())).count();
|
||||
long completedUndertaken = undertakenTasks.stream().filter(task -> Long.valueOf(2).equals(task.getState())).count();
|
||||
stats.setCompletedTasks((int) (completedAssigned + completedUndertaken));
|
||||
|
||||
// 统计进行中任务数量(状态为 1 等待审核)
|
||||
long underwayAssigned = assignedTasks.stream().filter(task -> Long.valueOf(1).equals(task.getState())).count();
|
||||
long underwayUndertaken = undertakenTasks.stream().filter(task -> Long.valueOf(1).equals(task.getState())).count();
|
||||
stats.setUnderwayTasks((int) (underwayAssigned + underwayUndertaken));
|
||||
//未完成的数量
|
||||
long unfinishedAssigned = assignedTasks.stream().filter(task -> Long.valueOf(0).equals(task.getState())).count();
|
||||
long unfinishedUndertaken = undertakenTasks.stream().filter(task -> Long.valueOf(0).equals(task.getState())).count();
|
||||
stats.setUnfinishedTasks((int) (unfinishedAssigned + unfinishedUndertaken));
|
||||
|
||||
// 统计延期任务数量
|
||||
long delayedAssigned = assignedTasks.stream().filter(task -> Long.valueOf(15).equals(task.getState())).count();
|
||||
long delayedUndertaken = undertakenTasks.stream().filter(task -> Long.valueOf(15).equals(task.getState())).count();
|
||||
stats.setDelayedTasks((int) (delayedAssigned + delayedUndertaken));
|
||||
|
||||
// 构建任务清单
|
||||
List<PersonalReportDTO.TaskSummary> assignedTaskList = assignedTasks.stream()
|
||||
.map(this::buildTaskSummary)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<PersonalReportDTO.TaskSummary> undertakenTaskList = undertakenTasks.stream()
|
||||
.map(this::buildTaskSummary)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
stats.setAssignedTaskList(assignedTaskList);
|
||||
stats.setUndertakenTaskList(undertakenTaskList);
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建任务摘要
|
||||
*/
|
||||
private PersonalReportDTO.TaskSummary buildTaskSummary(SysOaTask task) {
|
||||
PersonalReportDTO.TaskSummary summary = new PersonalReportDTO.TaskSummary();
|
||||
summary.setTaskId(task.getTaskId());
|
||||
summary.setTaskTitle(task.getTaskTitle());
|
||||
summary.setState(task.getState());
|
||||
summary.setIsDelayed(task.getPostponements() != null && task.getPostponements() > 0);
|
||||
summary.setPostponements(task.getPostponements());
|
||||
|
||||
// 获取项目名称
|
||||
if (task.getProjectId() != null) {
|
||||
SysOaProject project = projectMapper.selectById(task.getProjectId());
|
||||
if (project != null) {
|
||||
summary.setProjectName(project.getProjectName());
|
||||
}
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计工程异常信息(基于oa_express_question表)
|
||||
*/
|
||||
private PersonalReportDTO.EngineeringExceptionStats getExceptionStats(String nickName, Date startDate, Date endDate) {
|
||||
PersonalReportDTO.EngineeringExceptionStats stats = new PersonalReportDTO.EngineeringExceptionStats();
|
||||
|
||||
|
||||
// 查询快递问题表,通过汇报人匹配
|
||||
LambdaQueryWrapper<OaExpressQuestion> wrapper = Wrappers.<OaExpressQuestion>lambdaQuery()
|
||||
.eq(OaExpressQuestion::getReportBy, nickName)
|
||||
.eq(OaExpressQuestion::getDelFlag, 0);
|
||||
|
||||
// 添加时间范围条件(基于汇报时间)
|
||||
if (startDate != null && endDate != null) {
|
||||
wrapper.between(OaExpressQuestion::getReportTime, startDate, endDate);
|
||||
}
|
||||
|
||||
List<OaExpressQuestion> questions = expressQuestionMapper.selectList(wrapper);
|
||||
|
||||
stats.setTotalExceptions(questions.size());
|
||||
|
||||
// 统计已解决和未解决的异常
|
||||
long resolvedCount = questions.stream().filter(q -> Long.valueOf(1).equals(q.getStatus())).count();
|
||||
long unresolvedCount = questions.stream().filter(q -> Long.valueOf(0).equals(q.getStatus())).count();
|
||||
|
||||
stats.setResolvedExceptions((int) resolvedCount);
|
||||
stats.setDelayedExceptions((int) unresolvedCount); // 未解决的视为延期异常
|
||||
|
||||
// 构建异常清单
|
||||
List<PersonalReportDTO.ExceptionSummary> exceptionList = questions.stream()
|
||||
.map(question -> {
|
||||
PersonalReportDTO.ExceptionSummary summary = new PersonalReportDTO.ExceptionSummary();
|
||||
summary.setExceptionId(question.getQuestionId());
|
||||
summary.setDescription(question.getDescription());
|
||||
summary.setStatus(Long.valueOf(1).equals(question.getStatus()) ? "已解决" : "未解决");
|
||||
summary.setIsDelayed(Long.valueOf(0).equals(question.getStatus())); // 未解决的视为延期
|
||||
|
||||
// 这里可以根据expressId关联获取项目信息
|
||||
summary.setProjectName(oaExpressService.queryById(question.getExpressId()).getProjectName());
|
||||
|
||||
return summary;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
stats.setExceptionList(exceptionList);
|
||||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计关键采购任务信息(基于oa_requirements表)
|
||||
*/
|
||||
private PersonalReportDTO.ProcurementTaskStats getProcurementStats(Long userId, Date startDate, Date endDate) {
|
||||
PersonalReportDTO.ProcurementTaskStats stats = new PersonalReportDTO.ProcurementTaskStats();
|
||||
|
||||
// 查询需求表,通过负责人ID匹配
|
||||
LambdaQueryWrapper<OaRequirements> wrapper = Wrappers.<OaRequirements>lambdaQuery()
|
||||
.eq(OaRequirements::getOwnerId, userId)
|
||||
.eq(OaRequirements::getDelFlag, 0);
|
||||
|
||||
// 添加时间范围条件
|
||||
if (startDate != null && endDate != null) {
|
||||
wrapper.between(OaRequirements::getCreateTime, startDate, endDate);
|
||||
}
|
||||
|
||||
List<OaRequirements> requirements = requirementsMapper.selectList(wrapper);
|
||||
|
||||
stats.setTotalProcurementTasks(requirements.size());
|
||||
|
||||
// 统计已完成和延期的需求
|
||||
long completedCount = requirements.stream().filter(req -> Integer.valueOf(1).equals(req.getStatus())).count();
|
||||
stats.setCompletedProcurementTasks((int) completedCount);
|
||||
|
||||
// 计算延期需求(截止日期已过但未完成的)
|
||||
long delayedCount = requirements.stream()
|
||||
.filter(req -> Integer.valueOf(0).equals(req.getStatus())) // 未完成
|
||||
.filter(req -> req.getDeadline() != null && req.getDeadline().before(new Date())) // 已过期
|
||||
.count();
|
||||
stats.setDelayedProcurementTasks((int) delayedCount);
|
||||
|
||||
// 构建采购任务清单
|
||||
List<PersonalReportDTO.ProcurementTaskSummary> procurementList = requirements.stream()
|
||||
.map(req -> {
|
||||
PersonalReportDTO.ProcurementTaskSummary summary = new PersonalReportDTO.ProcurementTaskSummary();
|
||||
summary.setProcurementId(req.getRequirementId());
|
||||
summary.setProcurementContent(req.getTitle());
|
||||
summary.setStatus(Integer.valueOf(1).equals(req.getStatus()) ? "已完成" : "进行中");
|
||||
|
||||
// 判断是否延期
|
||||
boolean isDelayed = Integer.valueOf(0).equals(req.getStatus()) &&
|
||||
req.getDeadline() != null && req.getDeadline().before(new Date());
|
||||
summary.setIsDelayed(isDelayed);
|
||||
|
||||
// 获取项目名称
|
||||
if (req.getProjectId() != null) {
|
||||
SysOaProject project = projectMapper.selectById(req.getProjectId());
|
||||
if (project != null) {
|
||||
summary.setProjectName(project.getProjectName());
|
||||
}
|
||||
} else {
|
||||
summary.setProjectName("无关联项目");
|
||||
}
|
||||
|
||||
return summary;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
stats.setProcurementTaskList(procurementList);
|
||||
return stats;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 统计进度信息
|
||||
// */
|
||||
// private PersonalReportDTO.ProgressStats getProgressStats(String nickName, String startDate, String endDate) {
|
||||
// PersonalReportDTO.ProgressStats stats = new PersonalReportDTO.ProgressStats();
|
||||
//
|
||||
// // 查询用户负责的进度
|
||||
// LambdaQueryWrapper<OaProjectScheduleStep> wrapper = Wrappers.<OaProjectScheduleStep>lambdaQuery()
|
||||
// .eq(OaProjectScheduleStep::getNodeHeader, nickName)
|
||||
// .eq(OaProjectScheduleStep::getDelFlag, "0");
|
||||
//
|
||||
// if (startDate != null && endDate != null) {
|
||||
// wrapper.between(OaProjectScheduleStep::getCreateTime, startDate, endDate);
|
||||
// }
|
||||
//
|
||||
// List<OaProjectScheduleStep> steps = baseMapper.selectList(wrapper);
|
||||
//
|
||||
// stats.setTotalProgress(steps.size());
|
||||
//
|
||||
// // 统计各状态的进度数量
|
||||
// long completedCount = steps.stream().filter(step -> Long.valueOf(2).equals(step.getStatus())).count();
|
||||
// long inProgressCount = steps.stream().filter(step -> Long.valueOf(1).equals(step.getStatus())).count();
|
||||
//
|
||||
// // 计算延期进度(实际结束时间晚于计划结束时间)
|
||||
// long delayedCount = steps.stream()
|
||||
// .filter(step -> step.getActualEnd() != null && step.getPlanEnd() != null)
|
||||
// .filter(step -> step.getActualEnd().after(step.getPlanEnd()))
|
||||
// .count();
|
||||
//
|
||||
// stats.setCompletedProgress((int) completedCount);
|
||||
// stats.setInProgressCount((int) inProgressCount);
|
||||
// stats.setDelayedProgress((int) delayedCount);
|
||||
//
|
||||
// // 构建进度清单
|
||||
// List<PersonalReportDTO.ProgressSummary> progressList = steps.stream()
|
||||
// .map(step -> {
|
||||
// PersonalReportDTO.ProgressSummary summary = new PersonalReportDTO.ProgressSummary();
|
||||
// summary.setTrackId(step.getTrackId());
|
||||
// summary.setStepName(step.getStepName());
|
||||
// summary.setStatus(step.getStatus());
|
||||
//
|
||||
// // 判断是否延期
|
||||
// boolean isDelayed = step.getActualEnd() != null && step.getPlanEnd() != null &&
|
||||
// step.getActualEnd().after(step.getPlanEnd());
|
||||
// summary.setIsDelayed(isDelayed);
|
||||
//
|
||||
// // 获取项目名称
|
||||
// if (step.getScheduleId() != null) {
|
||||
// OaProjectSchedule schedule = scheduleMapper.selectById(step.getScheduleId());
|
||||
// if (schedule != null && schedule.getProjectId() != null) {
|
||||
// SysOaProject project = projectMapper.selectById(schedule.getProjectId());
|
||||
// if (project != null) {
|
||||
// summary.setProjectName(project.getProjectName());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return summary;
|
||||
// })
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// stats.setProgressList(progressList);
|
||||
// return stats;
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.ruoyi.oa.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.domain.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.oa.domain.bo.OaUserActiveBo;
|
||||
import com.ruoyi.oa.domain.vo.OaUserActiveVo;
|
||||
import com.ruoyi.oa.domain.OaUserActive;
|
||||
import com.ruoyi.oa.mapper.OaUserActiveMapper;
|
||||
import com.ruoyi.oa.service.IOaUserActiveService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.time.LocalDate;
|
||||
import java.sql.Date;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
|
||||
/**
|
||||
* 用户活跃统计Service业务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class OaUserActiveServiceImpl implements IOaUserActiveService {
|
||||
|
||||
private final OaUserActiveMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询用户活跃统计
|
||||
*/
|
||||
@Override
|
||||
public OaUserActiveVo queryById(Long activeId){
|
||||
return baseMapper.selectVoById(activeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户活跃统计列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<OaUserActiveVo> queryPageList(OaUserActiveBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<OaUserActive> lqw = buildQueryWrapper(bo);
|
||||
Page<OaUserActiveVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户活跃统计列表
|
||||
*/
|
||||
@Override
|
||||
public List<OaUserActiveVo> queryList(OaUserActiveBo bo) {
|
||||
LambdaQueryWrapper<OaUserActive> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<OaUserActive> buildQueryWrapper(OaUserActiveBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<OaUserActive> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getUserId() != null, OaUserActive::getUserId, bo.getUserId());
|
||||
lqw.eq(bo.getActiveDate() != null, OaUserActive::getActiveDate, bo.getActiveDate());
|
||||
lqw.eq(bo.getLoginCount() != null, OaUserActive::getLoginCount, bo.getLoginCount());
|
||||
lqw.orderByDesc(OaUserActive::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增用户活跃统计
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(OaUserActiveBo bo) {
|
||||
OaUserActive add = BeanUtil.toBean(bo, OaUserActive.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setActiveId(add.getActiveId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户活跃统计
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(OaUserActiveBo bo) {
|
||||
OaUserActive update = BeanUtil.toBean(bo, OaUserActive.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(OaUserActive entity){
|
||||
//TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除用户活跃统计
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActiveToday(Long userId) {
|
||||
Date today = Date.valueOf(LocalDate.now());
|
||||
LambdaQueryWrapper<OaUserActive> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(OaUserActive::getUserId, userId)
|
||||
.eq(OaUserActive::getActiveDate, today);
|
||||
return baseMapper.selectCount(lqw) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordTodayLogin(Long userId) {
|
||||
Date today = Date.valueOf(LocalDate.now());
|
||||
LambdaUpdateWrapper<OaUserActive> uw = Wrappers.lambdaUpdate();
|
||||
uw.eq(OaUserActive::getUserId, userId)
|
||||
.eq(OaUserActive::getActiveDate, today)
|
||||
.setSql("login_count = login_count + 1");
|
||||
int rows = baseMapper.update(null, uw);
|
||||
if (rows == 0) {
|
||||
OaUserActive entity = new OaUserActive();
|
||||
entity.setUserId(userId);
|
||||
entity.setActiveDate(today);
|
||||
entity.setLoginCount(1L);
|
||||
baseMapper.insert(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@ import com.ruoyi.oa.domain.vo.SysOaTaskVo;
|
||||
import com.ruoyi.oa.mapper.SysOaTaskMapper;
|
||||
import com.ruoyi.oa.service.ISysOaTaskService;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.*;
|
||||
@@ -323,6 +325,7 @@ public class SysOaTaskServiceImpl implements ISysOaTaskService {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
// 增加任务开始时间在奖金池时间范围内的筛选
|
||||
return baseMapper.selectList(Wrappers.<SysOaTask>lambdaQuery()
|
||||
.eq(SysOaTask::getWorkerId, user.getUserId())
|
||||
|
||||
21
ruoyi-oa/src/main/resources/mapper/oa/OaUserActiveMapper.xml
Normal file
21
ruoyi-oa/src/main/resources/mapper/oa/OaUserActiveMapper.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?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.ruoyi.oa.mapper.OaUserActiveMapper">
|
||||
|
||||
<resultMap type="com.ruoyi.oa.domain.OaUserActive" id="OaUserActiveResult">
|
||||
<result property="activeId" column="active_id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="activeDate" column="active_date"/>
|
||||
<result property="loginCount" column="login_count"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
</resultMap>
|
||||
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user