czh-20260609-增加门户卡片获取“待办事项、本月已办、平均时长、超时预警”后端接口
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
# CodeGraph data files
|
||||||
|
# These are local to each machine and should not be committed
|
||||||
|
|
||||||
|
# Database
|
||||||
|
*.db
|
||||||
|
*.db-wal
|
||||||
|
*.db-shm
|
||||||
|
|
||||||
|
# Cache
|
||||||
|
cache/
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Hook markers
|
||||||
|
.dirty
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
package org.jeecg.modules.dashboard.controller;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
|
import org.jeecg.modules.dashboard.dto.ProcessPortalStatsDTO;
|
||||||
|
import org.jeecg.modules.dashboard.service.IProcessPortalService;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
@Tag(name = "流程门户")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/dashboard/processPortal")
|
||||||
|
@Slf4j
|
||||||
|
public class ProcessPortalController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IProcessPortalService processPortalService;
|
||||||
|
|
||||||
|
@Operation(summary = "流程门户-获取统计卡片数据")
|
||||||
|
@GetMapping("/stats")
|
||||||
|
public Result<ProcessPortalStatsDTO> getStats() {
|
||||||
|
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
|
String userId = sysUser.getUsername();
|
||||||
|
ProcessPortalStatsDTO stats = processPortalService.getStats(userId);
|
||||||
|
return Result.OK(stats);
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
package org.jeecg.modules.dashboard.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程门户 - 统计卡片 DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ProcessPortalStatsDTO {
|
||||||
|
|
||||||
|
/** 待办事项数 */
|
||||||
|
private Long todoCount;
|
||||||
|
|
||||||
|
/** 本月已办数 */
|
||||||
|
private Long doneThisMonth;
|
||||||
|
|
||||||
|
/** 平均时长 */
|
||||||
|
private String avgDuration;
|
||||||
|
|
||||||
|
/** 超时预警数 */
|
||||||
|
private Long overdueCount;
|
||||||
|
}
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
package org.jeecg.modules.dashboard.mapper;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ProcessPortalMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前用户待办任务数(直接分配 + 候选人/候选组)
|
||||||
|
* 与 ActivitiServiceImpl#findBaseTodoTasks 逻辑一致
|
||||||
|
*/
|
||||||
|
@Select("SELECT COUNT(*) FROM ("
|
||||||
|
+ "(SELECT DISTINCT RES.ID_ FROM ACT_RU_TASK RES "
|
||||||
|
+ "INNER JOIN ACT_RU_IDENTITYLINK I ON I.TASK_ID_ = RES.ID_ "
|
||||||
|
+ "WHERE RES.ASSIGNEE_ IS NULL AND I.TYPE_ = 'candidate' "
|
||||||
|
+ "AND (I.USER_ID_ = #{userId} OR I.GROUP_ID_ IN (SELECT g.GROUP_ID_ FROM ACT_ID_MEMBERSHIP g WHERE g.USER_ID_ = #{userId})) "
|
||||||
|
+ "AND RES.SUSPENSION_STATE_ = 1) "
|
||||||
|
+ "UNION "
|
||||||
|
+ "(SELECT DISTINCT RES.ID_ FROM ACT_RU_TASK RES "
|
||||||
|
+ "WHERE RES.ASSIGNEE_ = #{userId} AND RES.SUSPENSION_STATE_ = 1)"
|
||||||
|
+ ") T")
|
||||||
|
Long countTodo(@Param("userId") String userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前用户本月已办任务数
|
||||||
|
* 与 ActivitiMapper#getHistoryTasks 逻辑一致:用 DURATION_ > 0 判定已完成
|
||||||
|
*/
|
||||||
|
@Select("SELECT COUNT(*) FROM ACT_HI_TASKINST "
|
||||||
|
+ "WHERE ASSIGNEE_ = #{userId} AND DURATION_ > 0 AND END_TIME_ >= #{startOfMonth}")
|
||||||
|
Long countDoneThisMonth(@Param("userId") String userId, @Param("startOfMonth") String startOfMonth);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前用户任务平均处理时长(毫秒)
|
||||||
|
*/
|
||||||
|
@Select("SELECT COALESCE(AVG(DURATION_), 0) FROM ACT_HI_TASKINST "
|
||||||
|
+ "WHERE ASSIGNEE_ = #{userId} AND DURATION_ > 0")
|
||||||
|
Long avgDurationMillis(@Param("userId") String userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前用户超时未完成任务数(直接分配 + 候选人/候选组)
|
||||||
|
* deadline 变量类型为 localdatetime,存储在 LONG_ 列(epoch millis)
|
||||||
|
*/
|
||||||
|
@Select("SELECT COUNT(DISTINCT T.ID_) FROM ACT_RU_TASK T "
|
||||||
|
+ "INNER JOIN ACT_RU_VARIABLE V ON V.PROC_INST_ID_ = T.PROC_INST_ID_ AND V.NAME_ = 'deadline' "
|
||||||
|
+ "WHERE T.SUSPENSION_STATE_ = 1 "
|
||||||
|
+ "AND (T.ASSIGNEE_ = #{userId} "
|
||||||
|
+ " OR T.ID_ IN ("
|
||||||
|
+ " SELECT I.TASK_ID_ FROM ACT_RU_IDENTITYLINK I "
|
||||||
|
+ " WHERE I.TYPE_ = 'candidate' "
|
||||||
|
+ " AND (I.USER_ID_ = #{userId} OR I.GROUP_ID_ IN (SELECT g.GROUP_ID_ FROM ACT_ID_MEMBERSHIP g WHERE g.USER_ID_ = #{userId}))"
|
||||||
|
+ " )) "
|
||||||
|
+ "AND V.LONG_ IS NOT NULL "
|
||||||
|
+ "AND FROM_UNIXTIME(V.LONG_ / 1000) < CURDATE()")
|
||||||
|
Long countOverdue(@Param("userId") String userId);
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package org.jeecg.modules.dashboard.service;
|
||||||
|
|
||||||
|
import org.jeecg.modules.dashboard.dto.ProcessPortalStatsDTO;
|
||||||
|
|
||||||
|
public interface IProcessPortalService {
|
||||||
|
|
||||||
|
ProcessPortalStatsDTO getStats(String userId);
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
package org.jeecg.modules.dashboard.service.impl;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.modules.dashboard.dto.ProcessPortalStatsDTO;
|
||||||
|
import org.jeecg.modules.dashboard.mapper.ProcessPortalMapper;
|
||||||
|
import org.jeecg.modules.dashboard.service.IProcessPortalService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class ProcessPortalServiceImpl implements IProcessPortalService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ProcessPortalMapper processPortalMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProcessPortalStatsDTO getStats(String userId) {
|
||||||
|
ProcessPortalStatsDTO dto = new ProcessPortalStatsDTO();
|
||||||
|
|
||||||
|
String startOfMonth = LocalDate.now().withDayOfMonth(1).format(DateTimeFormatter.ISO_LOCAL_DATE) + " 00:00:00";
|
||||||
|
|
||||||
|
dto.setTodoCount(processPortalMapper.countTodo(userId));
|
||||||
|
dto.setDoneThisMonth(processPortalMapper.countDoneThisMonth(userId, startOfMonth));
|
||||||
|
|
||||||
|
Long avgMillis = processPortalMapper.avgDurationMillis(userId);
|
||||||
|
dto.setAvgDuration(formatDuration(avgMillis));
|
||||||
|
|
||||||
|
dto.setOverdueCount(processPortalMapper.countOverdue(userId));
|
||||||
|
|
||||||
|
log.info("【流程门户-统计】查询统计完成, userId: {}, 待办: {}, 已办: {}, 平均时长: {}, 超时: {}",
|
||||||
|
userId, dto.getTodoCount(), dto.getDoneThisMonth(), dto.getAvgDuration(), dto.getOverdueCount());
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatDuration(Long millis) {
|
||||||
|
if (millis == null || millis == 0) {
|
||||||
|
return "0时";
|
||||||
|
}
|
||||||
|
double hours = millis / (1000.0 * 60 * 60);
|
||||||
|
if (hours < 1) {
|
||||||
|
return String.format("%.0f分", millis / (1000.0 * 60));
|
||||||
|
}
|
||||||
|
if (hours < 24) {
|
||||||
|
return String.format("%.1f时", hours);
|
||||||
|
}
|
||||||
|
return String.format("%.1f天", hours / 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user