Merge remote-tracking branch 'origin/master'
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
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package org.jeecg.inspectcloseout;
|
||||||
|
|
||||||
|
public class InspectCloseoutConstant {
|
||||||
|
public static final String JJ_DEPT_ID = "2054466800692432898";
|
||||||
|
public static final String JJ_DEPT_LEADER_ROLE_ID = "2044680793306591234";
|
||||||
|
public static final String JJ_DEPT_WORKER_ROLE_ID = "2047511967494213633";
|
||||||
|
public static final String SLD_DEPT_ID = "2044677562460508161";
|
||||||
|
public static final String SLD_JWSJ_ROLE_ID = "2063902766943363073";
|
||||||
|
public static final int ZERO_INDEX = 0;
|
||||||
|
}
|
||||||
+81
-3
@@ -1,12 +1,16 @@
|
|||||||
package org.jeecg.inspectcloseout;
|
package org.jeecg.inspectcloseout;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.jeecg.weibo.exception.BusinessException;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.jeecg.common.system.api.ISysBaseAPI;
|
||||||
|
import org.jeecg.inspectimprove.InspectImproveConfig;
|
||||||
import org.jeecg.modules.extbpm.process.common.expression.FlowNodeExpression;
|
import org.jeecg.modules.extbpm.process.common.expression.FlowNodeExpression;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -18,6 +22,7 @@ public class InspectCloseoutFlow {
|
|||||||
|
|
||||||
private final InspectCloseoutConfig inspectCloseoutConfig;
|
private final InspectCloseoutConfig inspectCloseoutConfig;
|
||||||
private final FlowNodeExpression flowNodeExpression;
|
private final FlowNodeExpression flowNodeExpression;
|
||||||
|
private final ISysBaseAPI iSysBaseAPI;
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
// 通用工具方法
|
// 通用工具方法
|
||||||
@@ -47,8 +52,77 @@ public class InspectCloseoutFlow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//流程表达式内用法 ${inspectImproveFlow.getJJDeptLdUserIdList()}
|
||||||
|
public List<String> getJJDeptLdUserIdList() {
|
||||||
|
|
||||||
|
log.info("【巡视整改销号-流程表达式】查询部门角色用户列表, deptId: {}, roleId: {}", InspectCloseoutConstant.JJ_DEPT_ID, InspectCloseoutConstant.JJ_DEPT_LEADER_ROLE_ID);
|
||||||
|
List<String> userList = iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi(
|
||||||
|
InspectCloseoutConstant.JJ_DEPT_ID,
|
||||||
|
InspectCloseoutConstant.JJ_DEPT_LEADER_ROLE_ID
|
||||||
|
);
|
||||||
|
log.info("【巡视整改销号-流程表达式】查询到用户列表, userList: {}", userList);
|
||||||
|
return userList;
|
||||||
|
}
|
||||||
|
|
||||||
|
//流程表达式内用法 ${inspectCloseoutFlow.getJJDeptLdUserIdListLength()}
|
||||||
|
public int getJJDeptLdUserIdListLength() {
|
||||||
|
List<String> jjDeptLdUserIdList = this.getJJDeptLdUserIdList();
|
||||||
|
if (jjDeptLdUserIdList != null && !jjDeptLdUserIdList.isEmpty()) {
|
||||||
|
return jjDeptLdUserIdList.size();
|
||||||
|
}
|
||||||
|
log.error("【巡视整改销号-流程表达式】JJ部门LD角色没有对应用户");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//流程表达式内用法 ${inspectCloseoutFlow.getJJDeptLdWorkerIdList()}
|
||||||
|
public List<String> getJJDeptLdWorkerIdList() {
|
||||||
|
|
||||||
|
log.info("【巡视整改销号-流程表达式】查询部门角色用户列表, deptId: {}, roleId: {}", InspectCloseoutConstant.JJ_DEPT_ID, InspectCloseoutConstant.JJ_DEPT_LEADER_ROLE_ID);
|
||||||
|
List<String> userList = iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi(
|
||||||
|
InspectCloseoutConstant.JJ_DEPT_ID,
|
||||||
|
InspectCloseoutConstant.JJ_DEPT_WORKER_ROLE_ID
|
||||||
|
);
|
||||||
|
log.info("【巡视整改销号-流程表达式】查询到用户列表, userList: {}", userList);
|
||||||
|
return userList;
|
||||||
|
}
|
||||||
|
|
||||||
|
//流程表达式内用法 ${inspectCloseoutFlow.getJWSJUser()}
|
||||||
|
public String getJWSJUser() {
|
||||||
|
String deptId = InspectCloseoutConstant.SLD_DEPT_ID;
|
||||||
|
String roleId = InspectCloseoutConstant.SLD_JWSJ_ROLE_ID;
|
||||||
|
|
||||||
|
log.info("【巡视整改销号-流程表达式】查询纪委书记用户, deptId: {}, roleId: {}", deptId, roleId);
|
||||||
|
|
||||||
|
List<String> userList = iSysBaseAPI.getUsersListByDeptIdAndRoleIdLocalApi(deptId, roleId);
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(userList)) {
|
||||||
|
log.error("【巡视整改销号-流程表达式】未查询到纪委书记用户, deptId: {}, roleId: {}", deptId, roleId);
|
||||||
|
throw new BusinessException("流程流转失败:未配置纪委书记用户,请联系管理员!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userList.size() > 1) {
|
||||||
|
log.error("【巡视整改销号-流程表达式】查询到多个纪委书记用户, 数量: {}, 用户列表: {}", userList.size(), userList);
|
||||||
|
throw new BusinessException("流程流转失败:存在多个纪委书记用户,数据不唯一,请检查角色配置!");
|
||||||
|
}
|
||||||
|
|
||||||
|
String targetUser = userList.get(InspectCloseoutConstant.ZERO_INDEX);
|
||||||
|
log.info("【巡视整改销号-流程表达式】匹配到纪委书记用户: {}", targetUser);
|
||||||
|
return targetUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
//流程表达式内用法 ${inspectCloseoutFlow.getJJDeptLdWorkerIdListLength()}
|
||||||
|
public int getJJDeptLdWorkerIdListLength() {
|
||||||
|
List<String> jjDeptLdUserIdList = this.getJJDeptLdUserIdList();
|
||||||
|
if (jjDeptLdUserIdList != null && !jjDeptLdUserIdList.isEmpty()) {
|
||||||
|
return jjDeptLdUserIdList.size();
|
||||||
|
}
|
||||||
|
log.error("【巡视整改销号-流程表达式】JJ部门WORKER角色没有对应用户");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private List<String> getListFromData(Object jsonData, String codeName, String logLabel) {
|
private List<String> getListFromData(Object jsonData, String codeName, String logLabel) {
|
||||||
if (jsonData == null || StringUtils.isBlank(codeName)) {
|
if (jsonData == null || StringUtils.isBlank(codeName)) {
|
||||||
|
log.warn("【巡视整改销号-流程表达式】{}解析参数为空, codeName: {}", logLabel, codeName);
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -57,23 +131,27 @@ public class InspectCloseoutFlow {
|
|||||||
data = (JSONObject) jsonData;
|
data = (JSONObject) jsonData;
|
||||||
} else if (jsonData instanceof String) {
|
} else if (jsonData instanceof String) {
|
||||||
String jsonStr = (String) jsonData;
|
String jsonStr = (String) jsonData;
|
||||||
if (StringUtils.isBlank(jsonStr)) return Collections.emptyList();
|
if (StringUtils.isBlank(jsonStr)) {
|
||||||
|
log.warn("【巡视整改销号-流程表达式】{}JSON字符串为空", logLabel);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
data = JSONObject.parseObject(jsonStr);
|
data = JSONObject.parseObject(jsonStr);
|
||||||
} else {
|
} else {
|
||||||
data = JSONObject.parseObject(JSONObject.toJSONString(jsonData));
|
data = JSONObject.parseObject(JSONObject.toJSONString(jsonData));
|
||||||
}
|
}
|
||||||
String rawValue = data.getString(codeName);
|
String rawValue = data.getString(codeName);
|
||||||
if (StringUtils.isBlank(rawValue)) {
|
if (StringUtils.isBlank(rawValue)) {
|
||||||
|
log.warn("【巡视整改销号-流程表达式】{}字段值为空, codeName: {}", logLabel, codeName);
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
List<String> result = Arrays.stream(rawValue.split(","))
|
List<String> result = Arrays.stream(rawValue.split(","))
|
||||||
.map(String::trim)
|
.map(String::trim)
|
||||||
.filter(StringUtils::isNotBlank)
|
.filter(StringUtils::isNotBlank)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
log.info("{} 解析结果: {}", logLabel, result);
|
log.info("【巡视整改销号-流程表达式】{}解析结果: {}", logLabel, result);
|
||||||
return result;
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("JSON解析失败: label={}, key={}", logLabel, codeName, e);
|
log.error("【巡视整改销号-流程表达式】{}JSON解析失败, codeName: {}", logLabel, codeName, e);
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
@@ -111,6 +111,26 @@ public class InspectImproveFlow {
|
|||||||
return InspectConstant.NEED_APPROVE_STR;
|
return InspectConstant.NEED_APPROVE_STR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 流程表达式内用法 ${inspectImproveFlow.getMeasureResLeader(execution)}
|
||||||
|
public String getMeasureResLeader(DelegateExecution execution) {
|
||||||
|
DqInspectTask temDqInspectTask = this.getDqInspectTask(execution);
|
||||||
|
|
||||||
|
if (temDqInspectTask == null) {
|
||||||
|
log.error("【巡视整改-流程表达式】获取措施责任领导时未找到业务表单数据, processInstanceId: {}", execution.getProcessInstanceId());
|
||||||
|
throw new IllegalStateException("无法获取措施责任领导:未找到对应的业务表单数据,流程暂停。");
|
||||||
|
}
|
||||||
|
|
||||||
|
String measureResLeader = temDqInspectTask.getMeasureResLeader();
|
||||||
|
if (StringUtils.isBlank(measureResLeader)) {
|
||||||
|
log.warn("【巡视整改-流程表达式】措施责任领导为空, businessKey: {}, processInstanceId: {}",
|
||||||
|
temDqInspectTask.getId(), execution.getProcessInstanceId());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("【巡视整改-流程表达式】获取到措施责任领导: {}, businessKey: {}", measureResLeader, temDqInspectTask.getId());
|
||||||
|
return measureResLeader;
|
||||||
|
}
|
||||||
|
|
||||||
// 流程表达式内用法:${inspectImproveFlow.getImplDeptLeaderList(execution)}
|
// 流程表达式内用法:${inspectImproveFlow.getImplDeptLeaderList(execution)}
|
||||||
public List<String> getImplDeptLeaderList(DelegateExecution execution) {
|
public List<String> getImplDeptLeaderList(DelegateExecution execution) {
|
||||||
|
|
||||||
|
|||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
package org.jeecg.inspectimprove.listener;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.flowable.engine.delegate.TaskListener;
|
||||||
|
import org.flowable.task.service.delegate.DelegateTask;
|
||||||
|
import org.jeecg.inspectimprove.InspectImproveConfig;
|
||||||
|
import org.jeecg.modules.demo.dqinspecttask.entity.DqInspectTask;
|
||||||
|
import org.jeecg.modules.demo.dqinspecttask.service.IDqInspectTaskService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡视整改-措施责任领导监听器:任务完成后将当前审批人写入 DqInspectTask.measureResLeader
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component("AfterMeasureResLeaderStoreListener")
|
||||||
|
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||||
|
public class AfterMeasureResLeaderStoreListener implements TaskListener {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final InspectImproveConfig inspectImproveConfig;
|
||||||
|
private final IDqInspectTaskService dqInspectTaskService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notify(DelegateTask delegateTask) {
|
||||||
|
String assignee = delegateTask.getAssignee();
|
||||||
|
String taskId = delegateTask.getId();
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(assignee)) {
|
||||||
|
log.error("【巡视整改-措施责任领导存储监听器】未获取到审批人, taskId: {}", taskId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object businessKeyObj = delegateTask.getVariable(inspectImproveConfig.getInspectImprove().getBusinessKey());
|
||||||
|
if (businessKeyObj == null || StringUtils.isBlank(businessKeyObj.toString())) {
|
||||||
|
log.error("【巡视整改-措施责任领导存储监听器】未获取到业务表单ID, taskId: {}", taskId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String businessKey = businessKeyObj.toString();
|
||||||
|
DqInspectTask task = dqInspectTaskService.getById(businessKey);
|
||||||
|
if (task == null) {
|
||||||
|
log.error("【巡视整改-措施责任领导存储监听器】未查询到业务表单记录, businessKey: {}", businessKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
task.setMeasureResLeader(assignee);
|
||||||
|
dqInspectTaskService.updateById(task);
|
||||||
|
|
||||||
|
log.info("【巡视整改-措施责任领导存储监听器】已将审批人 {} 写入 DqInspectTask.measureResLeader, businessKey: {}, taskId: {}",
|
||||||
|
assignee, businessKey, taskId);
|
||||||
|
}
|
||||||
|
}
|
||||||
+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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -84,7 +84,7 @@ public class DqInspectProgress implements Serializable {
|
|||||||
@Excel(name = "删除标识", width = 15)
|
@Excel(name = "删除标识", width = 15)
|
||||||
@Schema(description = "删除标识")
|
@Schema(description = "删除标识")
|
||||||
@TableLogic
|
@TableLogic
|
||||||
private java.lang.String delFlag;
|
private java.lang.String delFlag = "0";
|
||||||
/**整改措施任务ID*/
|
/**整改措施任务ID*/
|
||||||
@Schema(description = "整改措施任务ID")
|
@Schema(description = "整改措施任务ID")
|
||||||
private java.lang.String mainId;
|
private java.lang.String mainId;
|
||||||
|
|||||||
+22
-21
@@ -80,26 +80,25 @@ public class LoginController {
|
|||||||
return result.error500("该用户登录失败次数过多,请于10分钟后再次登录!");
|
return result.error500("该用户登录失败次数过多,请于10分钟后再次登录!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// step.1 验证码check
|
// step.1 验证码check(前端已隐藏验证码,后台兼容跳过校验)
|
||||||
String captcha = sysLoginModel.getCaptcha();
|
String captcha = sysLoginModel.getCaptcha();
|
||||||
if(captcha==null){
|
String realKey = null;
|
||||||
result.error500("验证码无效");
|
if (oConvertUtils.isNotEmpty(captcha)) {
|
||||||
return result;
|
String lowerCaseCaptcha = captcha.toLowerCase();
|
||||||
}
|
// 加入密钥作为混淆,避免简单的拼接,被外部利用,用户自定义该密钥即可
|
||||||
String lowerCaseCaptcha = captcha.toLowerCase();
|
//update-begin---author:chenrui ---date:20250107 for:[QQYUN-10775]验证码可以复用 #7674------------
|
||||||
// 加入密钥作为混淆,避免简单的拼接,被外部利用,用户自定义该密钥即可
|
String keyPrefix = Md5Util.md5Encode(sysLoginModel.getCheckKey()+jeecgBaseConfig.getSignatureSecret(), "utf-8");
|
||||||
//update-begin---author:chenrui ---date:20250107 for:[QQYUN-10775]验证码可以复用 #7674------------
|
realKey = keyPrefix + lowerCaseCaptcha;
|
||||||
String keyPrefix = Md5Util.md5Encode(sysLoginModel.getCheckKey()+jeecgBaseConfig.getSignatureSecret(), "utf-8");
|
//update-end---author:chenrui ---date:20250107 for:[QQYUN-10775]验证码可以复用 #7674------------
|
||||||
String realKey = keyPrefix + lowerCaseCaptcha;
|
Object checkCode = redisUtil.get(realKey);
|
||||||
//update-end---author:chenrui ---date:20250107 for:[QQYUN-10775]验证码可以复用 #7674------------
|
//当进入登录页时,有一定几率出现验证码错误 #1714
|
||||||
Object checkCode = redisUtil.get(realKey);
|
if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
|
||||||
//当进入登录页时,有一定几率出现验证码错误 #1714
|
log.warn("验证码错误,key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);
|
||||||
if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
|
result.error500("验证码错误");
|
||||||
log.warn("验证码错误,key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);
|
// 改成特殊的code 便于前端判断
|
||||||
result.error500("验证码错误");
|
result.setCode(HttpStatus.PRECONDITION_FAILED.value());
|
||||||
// 改成特殊的code 便于前端判断
|
return result;
|
||||||
result.setCode(HttpStatus.PRECONDITION_FAILED.value());
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// step.2 校验用户是否存在且有效
|
// step.2 校验用户是否存在且有效
|
||||||
@@ -124,7 +123,9 @@ public class LoginController {
|
|||||||
userInfo(sysUser, result, request);
|
userInfo(sysUser, result, request);
|
||||||
|
|
||||||
// step.5 登录成功删除验证码
|
// step.5 登录成功删除验证码
|
||||||
redisUtil.del(realKey);
|
if (oConvertUtils.isNotEmpty(realKey)) {
|
||||||
|
redisUtil.del(realKey);
|
||||||
|
}
|
||||||
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
|
redisUtil.del(CommonConstant.LOGIN_FAIL + username);
|
||||||
|
|
||||||
// step.6 记录用户登录日志
|
// step.6 记录用户登录日志
|
||||||
|
|||||||
Reference in New Issue
Block a user