diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/model/entity/KeyValDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/model/entity/KeyValDTO.java
new file mode 100644
index 0000000..c932655
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/model/entity/KeyValDTO.java
@@ -0,0 +1,28 @@
+package com.ningdatech.pmapi.common.model.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ *
+ * KeyValueDTO
+ *
+ *
+ * @author WendyYang
+ * @since 16:40 2022/8/31
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class KeyValDTO {
+
+ private K key;
+
+ private V value;
+
+ public static KeyValDTO of(K k, V v) {
+ return new KeyValDTO<>(k, v);
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/expert/model/dto/ModifyApplyExtraInfoDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/expert/model/dto/ModifyApplyExtraInfoDTO.java
new file mode 100644
index 0000000..082c5fc
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/expert/model/dto/ModifyApplyExtraInfoDTO.java
@@ -0,0 +1,25 @@
+package com.ningdatech.pmapi.expert.model.dto;
+
+import com.ningdatech.pmapi.common.model.FileBasicInfo;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.util.List;
+
+/**
+ * @author liuxinxin
+ * @date 2022/7/28 下午3:48
+ */
+@Data
+public class ModifyApplyExtraInfoDTO {
+ /**
+ * 情况说明
+ */
+ @NotBlank
+ private String factSheet;
+
+ /**
+ * 证明材料
+ */
+ private List evidenceList;
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/controller/ExpertLeaveController.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/controller/ExpertLeaveController.java
new file mode 100644
index 0000000..df7443b
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/controller/ExpertLeaveController.java
@@ -0,0 +1,70 @@
+package com.ningdatech.pmapi.leave.controller;
+
+
+import com.ningdatech.basic.exception.BizException;
+import com.ningdatech.basic.model.IdVo;
+import com.ningdatech.basic.model.PageVo;
+import com.ningdatech.pmapi.leave.entity.po.LeaveCreateReq;
+import com.ningdatech.pmapi.leave.entity.po.LeaveListByCreatorReq;
+import com.ningdatech.pmapi.leave.entity.vo.LeaveDetailVO;
+import com.ningdatech.pmapi.leave.entity.vo.LeaveListItemVO;
+import com.ningdatech.pmapi.leave.manage.LeaveManage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @author WendyYang
+ * @since 2022-08-11
+ */
+@Api(tags = "请假管理控制器")
+@RestController
+@AllArgsConstructor
+@RequestMapping("/api/v1/leave/")
+public class ExpertLeaveController {
+
+ private final LeaveManage leaveManage;
+
+ @ApiOperation("请假")
+ @PostMapping("/save")
+ public IdVo askForLeave(@Valid @RequestBody LeaveCreateReq po) {
+ return leaveManage.askForLeave(po);
+ }
+
+ @ApiOperation("请假详情")
+ @GetMapping(value = {"/detail/{leaveId}", "/detail/{auditId}/byApply"})
+ public LeaveDetailVO detail(@PathVariable(required = false) Long leaveId,
+ @PathVariable(required = false) Long auditId) {
+ if (ObjectUtils.allNull(leaveId, auditId)) {
+ throw BizException.wrap("请假ID或申请ID不能为空");
+ }
+ return leaveManage.leaveDetail(leaveId, auditId);
+ }
+
+ @ApiOperation("我的请假列表(发起人)")
+ @GetMapping("/leaveListByCreator")
+ public PageVo leaveListByCreator(LeaveListByCreatorReq po) {
+ return leaveManage.leaveListByCreator(po);
+ }
+
+ @ApiOperation("销假")
+ @GetMapping("/endLeave")
+ public void endLeave(Long leaveId) {
+ leaveManage.endLeave(leaveId);
+ }
+
+ @ApiOperation("撤销")
+ @GetMapping("/cancel")
+ public void cancelLeave(Long leaveId) {
+ leaveManage.cancel(leaveId);
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/domain/ExpertLeave.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/domain/ExpertLeave.java
new file mode 100644
index 0000000..4aca8d3
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/domain/ExpertLeave.java
@@ -0,0 +1,83 @@
+package com.ningdatech.pmapi.leave.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ * 请假记录表
+ *
+ *
+ * @author WendyYang
+ * @since 2022-08-11
+ */
+@Data
+@TableName("expert_leave")
+@ApiModel(value = "ExpertLeave对象", description = "请假记录表")
+public class ExpertLeave implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty("主键")
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty("请假类型")
+ private Integer type;
+
+ @ApiModelProperty("请假说明")
+ private String remark;
+
+ @ApiModelProperty("附件ID")
+ private String attachment;
+
+ @ApiModelProperty("审核表ID")
+ private Long auditId;
+
+ @ApiModelProperty("请假人ID")
+ private Long leaveUserId;
+
+ @ApiModelProperty("创建人名称")
+ private String creator;
+
+ @ApiModelProperty("创建人")
+ private Long createBy;
+
+ @ApiModelProperty("创建时间")
+ private LocalDateTime createOn;
+
+ @ApiModelProperty("修改人")
+ private Long updateBy;
+
+ @ApiModelProperty("修改时间")
+ private LocalDateTime updateOn;
+
+ @ApiModelProperty("请假开始时间")
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("请假结束时间")
+ private LocalDateTime endTime;
+
+ @ApiModelProperty("销假时间")
+ private LocalDateTime cancelTime;
+
+ @ApiModelProperty("固定时段模式")
+ private String fixedType;
+
+ private Long meetingId;
+
+ private Integer status;
+
+ public void setUpdateAndCreate(Long createBy, LocalDateTime createOn) {
+ this.updateBy = this.createBy = createBy;
+ this.updateOn = this.createOn = createOn;
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/domain/ExpertLeaveDetail.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/domain/ExpertLeaveDetail.java
new file mode 100644
index 0000000..f252b58
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/domain/ExpertLeaveDetail.java
@@ -0,0 +1,49 @@
+package com.ningdatech.pmapi.leave.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ * 专家请假详情表(维度:天)
+ *
+ *
+ * @author WendyYang
+ * @since 2022-08-11
+ */
+@Data
+@NoArgsConstructor
+@TableName("expert_leave_detail")
+@ApiModel(value = "ExpertLeaveDetail对象", description = "专家请假详情表(维度:天)")
+public class ExpertLeaveDetail implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty("主键")
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty("专家请假ID")
+ private Long expertLeaveId;
+
+ @ApiModelProperty("开始时间")
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("结束时间")
+ private LocalDateTime endTime;
+
+ public ExpertLeaveDetail(Long expertLeaveId, LocalDateTime startTime, LocalDateTime endTime) {
+ this.expertLeaveId = expertLeaveId;
+ this.startTime = startTime;
+ this.endTime = endTime;
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/enumeration/LeaveStatusEnum.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/enumeration/LeaveStatusEnum.java
new file mode 100644
index 0000000..5581add
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/enumeration/LeaveStatusEnum.java
@@ -0,0 +1,45 @@
+package com.ningdatech.pmapi.leave.entity.enumeration;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ *
+ * LeaveStatus
+ *
+ *
+ * @author WendyYang
+ * @since 09:39 2022/8/12
+ */
+@Getter
+public enum LeaveStatusEnum {
+
+ /**
+ * 请假状态
+ */
+ APPLYING(1, "审核中"),
+ PASSED(2, "审核通过"),
+ PASSED_END(3, "审核通过且销假"),
+ UN_PASSED(4, "审核不通过"),
+ CANCELED(5, "发起人撤销");
+ private final Integer code;
+ private final String name;
+
+ public boolean eq(Integer code) {
+ return this.getCode().equals(code);
+ }
+
+ LeaveStatusEnum(Integer code, String name) {
+ this.code = code;
+ this.name = name;
+ }
+
+ public static LeaveStatusEnum getByCode(Integer code) {
+ return Arrays.stream(values())
+ .filter(w -> w.getCode().equals(code))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException("无效的请假状态"));
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/enumeration/LeaveTypeEnum.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/enumeration/LeaveTypeEnum.java
new file mode 100644
index 0000000..11b6467
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/enumeration/LeaveTypeEnum.java
@@ -0,0 +1,41 @@
+package com.ningdatech.pmapi.leave.entity.enumeration;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ *
+ * LeaveType-请假类型
+ *
+ *
+ * @author WendyYang
+ * @since 10:23 2022/8/11
+ */
+@Getter
+public enum LeaveTypeEnum {
+
+ TEMPORARY(3, "临时请假"),
+ LONG_TERM(1, "长期请假"),
+ FIXED_TERM(2, "固定时段请假");
+
+ private final Integer code;
+ private final String name;
+
+ public boolean eq(Integer code) {
+ return this.getCode().equals(code);
+ }
+
+ LeaveTypeEnum(Integer code, String name) {
+ this.code = code;
+ this.name = name;
+ }
+
+ public static LeaveTypeEnum getByCode(Integer code) {
+ return Arrays.stream(values())
+ .filter(w -> w.getCode().equals(code))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException("无效的请假类型"));
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/po/LeaveCreateReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/po/LeaveCreateReq.java
new file mode 100644
index 0000000..fa4f0e0
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/po/LeaveCreateReq.java
@@ -0,0 +1,73 @@
+package com.ningdatech.pmapi.leave.entity.po;
+
+import com.ningdatech.basic.exception.BizException;
+import com.ningdatech.pmapi.leave.entity.enumeration.LeaveTypeEnum;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.apache.commons.lang3.ObjectUtils;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ *
+ * LeaveCreatePo
+ *
+ *
+ * @author WendyYang
+ * @since 10:30 2022/8/11
+ */
+@Data
+@ApiModel("请假创建实体")
+public class LeaveCreateReq {
+
+ @ApiModelProperty("请假类型:1 长期请假、2 固定时段请假、3 临时请假")
+ @NotNull(message = "请假类型不能为空")
+ private Integer type;
+
+ @ApiModelProperty("请假开始时间")
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("请假结束时间")
+ private LocalDateTime endTime;
+
+ @ApiModelProperty("请假说明")
+ @NotBlank(message = "请假说明不能为空")
+ private String postscript;
+
+ @ApiModelProperty("附件ID")
+ private List attachments;
+
+ @ApiModelProperty("固定时段")
+ private List fixedType;
+
+ @ApiModelProperty("会议ID")
+ private Long meetingId;
+
+ @ApiModelProperty("专家ID:管理员替专家请假时传参")
+ private Long expertId;
+
+ public void paramCheck(LeaveTypeEnum leaveTypeEnum) {
+ if (leaveTypeEnum.equals(LeaveTypeEnum.TEMPORARY)) {
+ if (this.getMeetingId() == null) {
+ throw new BizException("会议ID不能为空");
+ }
+ } else {
+ if (ObjectUtils.anyNull(this.getStartTime(), this.getEndTime())) {
+ throw new BizException("开始时间或结束时间不能为空");
+ }
+ if (!this.getStartTime().isBefore(this.getEndTime())) {
+ throw new BizException("无效的请假时间");
+ }
+ if (leaveTypeEnum.equals(LeaveTypeEnum.FIXED_TERM)) {
+ if (this.getFixedType() == null || this.getFixedType().isEmpty()) {
+ throw new BizException("固定时段不能为空");
+ }
+ }
+ }
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/po/LeaveListByCreatorReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/po/LeaveListByCreatorReq.java
new file mode 100644
index 0000000..3661c62
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/po/LeaveListByCreatorReq.java
@@ -0,0 +1,43 @@
+package com.ningdatech.pmapi.leave.entity.po;
+
+import com.ningdatech.basic.model.PagePo;
+import com.ningdatech.pmapi.sms.constant.DatePattern;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+/**
+ *
+ * LeaveListByCreatorPo
+ *
+ *
+ * @author WendyYang
+ * @since 19:32 2022/8/11
+ */
+@Data
+@ApiModel("我的请假列表参数实体")
+@EqualsAndHashCode(callSuper = true)
+public class LeaveListByCreatorReq extends PagePo {
+
+ @ApiModelProperty("开始时间")
+ @DateTimeFormat(pattern = DatePattern.YMD_HMS)
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("结束时间")
+ @DateTimeFormat(pattern = DatePattern.YMD_HMS)
+ private LocalDateTime endTime;
+
+ @ApiModelProperty("请假类型")
+ private Integer leaveType;
+
+ @ApiModelProperty("审核状态")
+ private String auditStatus;
+
+ @ApiModelProperty("专家ID")
+ private Long expertId;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/vo/LeaveDetailVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/vo/LeaveDetailVO.java
new file mode 100644
index 0000000..ce91b39
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/vo/LeaveDetailVO.java
@@ -0,0 +1,46 @@
+package com.ningdatech.pmapi.leave.entity.vo;
+
+import com.ningdatech.file.entity.vo.result.AttachFileVo;
+import lombok.Builder;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ *
+ * LeaveDetailVo
+ *
+ *
+ * @author WendyYang
+ * @since 11:48 2022/8/12
+ */
+@Data
+@Builder
+public class LeaveDetailVO {
+
+ private Long id;
+
+ private String postscript;
+
+ private LocalDateTime startTime;
+
+ private LocalDateTime endTime;
+
+ private LocalDateTime actualEndTime;
+
+ private Integer status;
+
+ private List attachments;
+
+ private Integer type;
+
+ private List fixedType;
+
+ private LocalDateTime createOn;
+
+ private String createBy;
+
+ private Long auditId;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/vo/LeaveListItemVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/vo/LeaveListItemVO.java
new file mode 100644
index 0000000..ec9320f
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/entity/vo/LeaveListItemVO.java
@@ -0,0 +1,61 @@
+package com.ningdatech.pmapi.leave.entity.vo;
+
+import com.ningdatech.file.entity.vo.result.AttachFileVo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ *
+ * LeaveListItemByCreatorVo
+ *
+ *
+ * @author WendyYang
+ * @since 20:53 2022/8/11
+ */
+@Data
+@ApiModel("我得请假列表实体(发起人)")
+public class LeaveListItemVO {
+
+ @ApiModelProperty("请假ID")
+ private Long leaveId;
+
+ @ApiModelProperty("审核ID")
+ private Long auditId;
+
+ @ApiModelProperty("开始时间")
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("结束时间")
+ private LocalDateTime endTime;
+
+ @ApiModelProperty("实际结束时间")
+ private LocalDateTime actualEndTime;
+
+ @ApiModelProperty("请假说明")
+ private String postscript;
+
+ @ApiModelProperty("说明材料")
+ private List attachments;
+
+ @ApiModelProperty("请假类型")
+ private Integer leaveType;
+
+ @ApiModelProperty("相关会议")
+ private String meetingName;
+
+ @ApiModelProperty("审核状态")
+ private String auditStatus;
+
+ @ApiModelProperty("状态")
+ private Integer status;
+
+ @ApiModelProperty("审核意见")
+ private String auditOption;
+
+ private LocalDateTime createOn;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/manage/LeaveManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/manage/LeaveManage.java
new file mode 100644
index 0000000..e5df123
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/manage/LeaveManage.java
@@ -0,0 +1,514 @@
+package com.ningdatech.pmapi.leave.manage;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ningdatech.basic.exception.BizException;
+import com.ningdatech.basic.model.IdVo;
+import com.ningdatech.basic.model.PagePo;
+import com.ningdatech.basic.model.PageVo;
+import com.ningdatech.basic.util.CollUtils;
+import com.ningdatech.file.entity.vo.result.AttachFileVo;
+import com.ningdatech.file.service.FileService;
+import com.ningdatech.pmapi.common.model.FileBasicInfo;
+import com.ningdatech.pmapi.common.model.entity.KeyValDTO;
+import com.ningdatech.pmapi.common.util.BizUtils;
+import com.ningdatech.pmapi.common.util.StrUtils;
+import com.ningdatech.pmapi.expert.constant.ExpertApplyStatusEnum;
+import com.ningdatech.pmapi.expert.constant.ExpertApplyTypeEnum;
+import com.ningdatech.pmapi.expert.entity.ExpertMetaApply;
+import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo;
+import com.ningdatech.pmapi.expert.model.dto.ModifyApplyExtraInfoDTO;
+import com.ningdatech.pmapi.expert.service.IExpertMetaApplyService;
+import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService;
+import com.ningdatech.pmapi.leave.entity.domain.ExpertLeave;
+import com.ningdatech.pmapi.leave.entity.domain.ExpertLeaveDetail;
+import com.ningdatech.pmapi.leave.entity.enumeration.LeaveStatusEnum;
+import com.ningdatech.pmapi.leave.entity.enumeration.LeaveTypeEnum;
+import com.ningdatech.pmapi.leave.entity.po.LeaveCreateReq;
+import com.ningdatech.pmapi.leave.entity.po.LeaveListByCreatorReq;
+import com.ningdatech.pmapi.leave.entity.vo.LeaveDetailVO;
+import com.ningdatech.pmapi.leave.entity.vo.LeaveListItemVO;
+import com.ningdatech.pmapi.leave.service.IExpertLeaveDetailService;
+import com.ningdatech.pmapi.leave.service.IExpertLeaveService;
+import com.ningdatech.pmapi.meeting.entity.domain.Meeting;
+import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert;
+import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatusEnum;
+import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatusEnum;
+import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper;
+import com.ningdatech.pmapi.meeting.service.IMeetingExpertService;
+import com.ningdatech.pmapi.meeting.service.IMeetingService;
+import com.ningdatech.pmapi.meeting.task.ExpertInviteTask;
+import com.ningdatech.pmapi.sms.utils.DateUtil;
+import com.ningdatech.pmapi.user.service.IUserInfoService;
+import com.ningdatech.pmapi.user.util.LoginUserUtil;
+import lombok.AllArgsConstructor;
+import org.springframework.aop.framework.AopContext;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+/**
+ *
+ * LeaveManage
+ *
+ *
+ * @author WendyYang
+ * @since 10:38 2022/8/11
+ */
+@Component
+@AllArgsConstructor
+public class LeaveManage {
+
+ private final ExpertInviteTask inviteTask;
+ private final IMeetingService meetingService;
+ private final IMeetingExpertService meetingExpertService;
+ private final IExpertLeaveService leaveService;
+ private final IExpertLeaveDetailService leaveDetailService;
+ private final IExpertMetaApplyService metaApplyService;
+ private final FileService fileService;
+ private final IExpertUserFullInfoService userFullInfoService;
+ private final YxtCallOrSmsHelper yxtCallOrSmsHelper;
+ private final IUserInfoService userInfoService;
+
+ private static final int HOURS_BEFORE_MEETING = 12;
+
+ public void cancelMeetingExpertByLeave(Long meetingExpertId, ExpertAttendStatusEnum status) {
+ MeetingExpert update = buildMeetingExpertUpdate(meetingExpertId, status);
+ meetingExpertService.updateById(update);
+ }
+
+ private MeetingExpert buildMeetingExpertUpdate(Long meetingExpertId, ExpertAttendStatusEnum status) {
+ MeetingExpert expert = new MeetingExpert();
+ expert.setId(meetingExpertId);
+ expert.setStatus(status.getCode());
+ return expert;
+ }
+
+ private List listMeetingExpert(Long expertId, List> leaveTimes) {
+ // 先查询专家参与的所有会议
+ LambdaQueryWrapper meetingExpertQuery = Wrappers.lambdaQuery(MeetingExpert.class)
+ .eq(MeetingExpert::getExpertId, expertId)
+ .in(MeetingExpert::getStatus, Arrays.asList(ExpertAttendStatusEnum.NOTICING.getCode(),
+ ExpertAttendStatusEnum.AGREED.getCode()));
+ List meetingExperts = meetingExpertService.list(meetingExpertQuery);
+ if (meetingExperts.isEmpty()) {
+ return Collections.emptyList();
+ }
+ // 只需要查询待确认的或者是同意参加的
+ Map expertMap = meetingExperts.stream()
+ .collect(Collectors.groupingBy(MeetingExpert::getMeetingId,
+ Collectors.collectingAndThen(Collectors.toList(), w -> {
+ w.sort(Comparator.comparing(MeetingExpert::getUpdateOn).reversed());
+ return w.get(0);
+ })));
+ List meetingIds = CollUtils.fieldList(expertMap.values(), MeetingExpert::getMeetingId);
+ LocalDateTime startTime = leaveTimes.get(0).getKey(), endTime = leaveTimes.get(leaveTimes.size() - 1).getValue();
+ LambdaQueryWrapper meetingQuery = Wrappers.lambdaQuery(Meeting.class)
+ .in(Meeting::getId, meetingIds)
+ .ne(Meeting::getStatus, MeetingStatusEnum.CANCELED.getCode())
+ .and(w -> w.between(Meeting::getStartTime, startTime, endTime)
+ .or(or -> or.between(Meeting::getEndTime, startTime, endTime)));
+ List meetingList = meetingService.list(meetingQuery);
+ List matchMeetingIds = meetingList.stream()
+ .filter(w -> leaveTimes.stream()
+ .anyMatch(tp -> DateUtil.intersect(w.getStartTime(), w.getEndTime(), tp.getKey(), tp.getValue())))
+ .map(Meeting::getId).collect(Collectors.toList());
+ if (matchMeetingIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return matchMeetingIds.stream().map(expertMap::get).collect(Collectors.toList());
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ public IdVo askForLeave(LeaveCreateReq po) {
+ Long leaveUserId, applyUserId = Objects.requireNonNull(LoginUserUtil.getUserId());
+ leaveUserId = po.getExpertId() != null ? po.getExpertId() : applyUserId;
+ boolean leaveForSelf = leaveUserId.equals(applyUserId);
+ if (!leaveForSelf) {
+ Assert.isFalse(leaveService.existsToBeReviewed(leaveUserId), "该专家存在待审核请假申请,请及时审核");
+ }
+ LeaveTypeEnum type = LeaveTypeEnum.getByCode(po.getType());
+ // 校验参数是否合法
+ po.paramCheck(type);
+ ExpertLeave leave = new ExpertLeave();
+ if (po.getAttachments() != null) {
+ leave.setAttachment(CollUtils.joinByComma(po.getAttachments()));
+ }
+ LocalDateTime now = LocalDateTime.now();
+ leave.setType(po.getType());
+ leave.setRemark(po.getPostscript());
+ leave.setLeaveUserId(leaveUserId);
+ leave.setUpdateAndCreate(applyUserId, now);
+ List> leaveDetailTimes = new ArrayList<>();
+ if (type.equals(LeaveTypeEnum.FIXED_TERM) || type.equals(LeaveTypeEnum.LONG_TERM)) {
+ boolean fixedTerm = CollUtil.isNotEmpty(po.getFixedType());
+ if (fixedTerm) {
+ // 固定时段请假
+ leave.setFixedType(CollUtils.joinByComma(po.getFixedType()));
+ }
+ LocalDateTime tempStart = po.getStartTime();
+ while (!tempStart.isAfter(po.getEndTime())) {
+ boolean add = true;
+ if (fixedTerm) {
+ int weekday = tempStart.getDayOfWeek().getValue();
+ add = po.getFixedType().contains(weekday);
+ }
+ if (add) {
+ LocalDateTime tempEnd = tempStart.toLocalDate().atTime(DateUtil.LOCAL_TIME_3D);
+ leaveDetailTimes.add(KeyValDTO.of(tempStart, DateUtil.min(tempEnd, po.getEndTime())));
+ }
+ tempStart = tempStart.plusDays(1).toLocalDate().atStartOfDay();
+ }
+ if (leaveDetailTimes.isEmpty()) {
+ throw BizException.wrap("请假时间无效");
+ }
+ if (leaveDetailService.existsLeaveByUserIdAndTime(leaveUserId, leaveDetailTimes)) {
+ throw BizException.wrap("该请假时段内已存在请假");
+ }
+ List meetingExperts = listMeetingExpert(leaveUserId, leaveDetailTimes);
+ if (!meetingExperts.isEmpty()) {
+ if (meetingExperts.stream().anyMatch(w -> ExpertAttendStatusEnum.AGREED.eq(w.getStatus()))) {
+ throw BizException.wrap("有待参加会议,请先处理完会议,再发起请假");
+ }
+ List expertsUpdate = meetingExperts.stream()
+ .map(w -> buildMeetingExpertUpdate(w.getExpertId(), ExpertAttendStatusEnum.ON_LEAVE))
+ .collect(Collectors.toList());
+ meetingExpertService.updateBatchById(expertsUpdate);
+ }
+ leave.setStatus(LeaveStatusEnum.APPLYING.getCode());
+ } else if (type.equals(LeaveTypeEnum.TEMPORARY)) {
+ // 临时请假
+ Meeting meeting = meetingService.getById(po.getMeetingId());
+ if (meeting.getStatus().equals(MeetingStatusEnum.CANCELED.getCode())) {
+ throw BizException.wrap("该会议已取消");
+ }
+ po.setStartTime(meeting.getStartTime());
+ po.setEndTime(meeting.getEndTime());
+ if (now.plusHours(HOURS_BEFORE_MEETING).isAfter(po.getStartTime())) {
+ throw BizException.wrap("会议临期" + HOURS_BEFORE_MEETING + "小时内,不能在线请假,请电话该主题事务的联系人。");
+ }
+ MeetingExpert expert = meetingExpertService.getByMeetingIdAndExpertId(po.getMeetingId(), leaveUserId);
+ if (!expert.getStatus().equals(ExpertAttendStatusEnum.AGREED.getCode())) {
+ // 非确认参加状态无法临时请假
+ throw BizException.wrap("未同意参加该会议,无法临时请假");
+ }
+ LocalDateTime tempStart = po.getStartTime();
+ while (!tempStart.isAfter(po.getEndTime())) {
+ LocalDateTime tempEnd = tempStart.toLocalDate().atTime(DateUtil.LOCAL_TIME_3D);
+ leaveDetailTimes.add(KeyValDTO.of(tempStart, DateUtil.min(tempEnd, po.getEndTime())));
+ tempStart = tempStart.plusDays(1).toLocalDate().atStartOfDay();
+ }
+ LeaveManage proxy = (LeaveManage) AopContext.currentProxy();
+ proxy.cancelMeetingExpertByLeave(expert.getId(), ExpertAttendStatusEnum.ON_LEAVE);
+ inviteTask.notifyInviteTask(meeting.getId(), Boolean.FALSE);
+ // 临时请假无需审核
+ leave.setAuditId(0L);
+ leave.setStatus(LeaveStatusEnum.PASSED.getCode());
+ // 临时请假需通知专家管理进行专家补抽
+ }
+ if (type != LeaveTypeEnum.TEMPORARY) {
+ ExpertMetaApply apply = getExpertMetaApply(po, leaveUserId, applyUserId, now);
+ leave.setAuditId(apply.getId());
+ if (!leaveForSelf) {
+ leave.setStatus(LeaveStatusEnum.PASSED.getCode());
+ }
+ }
+ leave.setStartTime(po.getStartTime());
+ leave.setEndTime(po.getEndTime());
+ leave.setCancelTime(po.getEndTime());
+ leaveService.save(leave);
+ List detailList = CollUtils.convert(leaveDetailTimes, w -> new ExpertLeaveDetail(leave.getId(), w.getKey(), w.getValue()));
+ leaveDetailService.saveBatch(detailList);
+ return IdVo.of(leave.getId());
+ }
+
+ private ExpertMetaApply getExpertMetaApply(LeaveCreateReq po, Long leaveUserId, Long applyUserId, LocalDateTime now) {
+ // 非临时请假需要审批
+ ExpertMetaApply apply = new ExpertMetaApply();
+ apply.setCreateOn(now);
+ apply.setUpdateOn(now);
+ apply.setApplyType(ExpertApplyTypeEnum.LONG_TERM_LEAVE.getKey());
+ if (applyUserId.equals(leaveUserId)) {
+ apply.setApplyStatus(ExpertApplyStatusEnum.PENDING_REVIEW.getKey());
+ } else {
+ // 专家管理员发起请假自动通过
+ apply.setReviewTime(now);
+ apply.setApprover(LoginUserUtil.getUsername());
+ apply.setApproverUserId(applyUserId);
+ apply.setApplyStatus(ExpertApplyStatusEnum.PASSED.getKey());
+ }
+ apply.setUserId(leaveUserId);
+ apply.setApplicantId(applyUserId);
+ ExpertUserFullInfo userInfo = userFullInfoService.getByUserId(apply.getUserId());
+ apply.setRegionCode(userInfo.getRegionCode());
+ apply.setRegionLevel(userInfo.getRegionLevel());
+ ModifyApplyExtraInfoDTO extraInfo = new ModifyApplyExtraInfoDTO();
+ extraInfo.setFactSheet(po.getPostscript());
+ if (po.getAttachments() != null) {
+ List infoList = CollUtils.convert(po.getAttachments(), w -> {
+ FileBasicInfo info = new FileBasicInfo();
+ info.setFileId(w);
+ return info;
+ });
+ extraInfo.setEvidenceList(infoList);
+ }
+ apply.setExtraMaterial(JSONUtil.toJsonStr(extraInfo));
+ metaApplyService.save(apply);
+ return apply;
+ }
+
+ public PageVo leaveListByCreator(LeaveListByCreatorReq po) {
+ if (po.getExpertId() == null) {
+ po.setExpertId(LoginUserUtil.getUserId());
+ }
+ LambdaQueryWrapper query = Wrappers.lambdaQuery(ExpertLeave.class)
+ .orderByDesc(ExpertLeave::getCreateOn);
+ if (po.getLeaveType() != null && po.getLeaveType().equals(LeaveTypeEnum.TEMPORARY.getCode())) {
+ // 临时请假
+ if (po.getAuditStatus() != null && !po.getAuditStatus().equals(ExpertApplyStatusEnum.PASSED.getKey())) {
+ return PageVo.empty();
+ }
+ query.eq(ExpertLeave::getAuditId, 0L);
+ query.eq(ExpertLeave::getLeaveUserId, po.getExpertId());
+ } else {
+ if (StrUtils.isNotBlank(po.getAuditStatus())) {
+ LambdaQueryWrapper queryApply = Wrappers.lambdaQuery(ExpertMetaApply.class)
+ .select(ExpertMetaApply::getId)
+ .eq(ExpertMetaApply::getUserId, po.getExpertId())
+ .eq(ExpertMetaApply::getApplyStatus, po.getAuditStatus());
+ List applyList = metaApplyService.list(queryApply);
+ List auditIds = CollUtils.fieldList(applyList, ExpertMetaApply::getId);
+ if (po.getAuditStatus().equals(ExpertApplyStatusEnum.PASSED.getKey())) {
+ query.eq(ExpertLeave::getLeaveUserId, po.getExpertId());
+ auditIds.add(0L);
+ }
+ if (auditIds.isEmpty()) {
+ return PageVo.empty();
+ }
+ query.in(ExpertLeave::getAuditId, auditIds);
+ } else {
+ query.eq(ExpertLeave::getLeaveUserId, po.getExpertId());
+ }
+ query.eq(po.getLeaveType() != null, ExpertLeave::getType, po.getLeaveType());
+ }
+ if (po.getStartTime() != null && po.getEndTime() != null) {
+ query.and(wrapper -> wrapper.between(ExpertLeave::getStartTime, po.getStartTime(), po.getEndTime())
+ .or(or -> or.between(ExpertLeave::getEndTime, po.getStartTime(), po.getEndTime())));
+ }
+ Page page = leaveService.page(po.page(), query);
+ if (page.getTotal() == 0) {
+ return PageVo.empty();
+ }
+ List meetingIds = new ArrayList<>(), auditIds = new ArrayList<>(), fileIds = new ArrayList<>();
+ page.getRecords().forEach(w -> {
+ if (w.getMeetingId() != 0) {
+ meetingIds.add(w.getMeetingId());
+ }
+ if (w.getAuditId() != 0) {
+ auditIds.add(w.getAuditId());
+ }
+ if (!w.getAttachment().isEmpty()) {
+ List tempFileIds = BizUtils.splitToLong(w.getAttachment());
+ fileIds.addAll(tempFileIds);
+ }
+ });
+ Map meetingMap = new HashMap<>(16);
+ if (!meetingIds.isEmpty()) {
+ meetingMap.putAll(CollUtils.listToMap(meetingService.listByIds(meetingIds), Meeting::getId));
+ }
+ Map applyMap = new HashMap<>(16);
+ if (!auditIds.isEmpty()) {
+ applyMap.putAll(CollUtils.listToMap(metaApplyService.listByIds(auditIds), ExpertMetaApply::getId));
+ }
+ Map fileMap = new HashMap<>(fileIds.size());
+ if (!fileIds.isEmpty()) {
+ fileMap.putAll(CollUtils.listToMap(fileService.getByIds(fileIds), AttachFileVo::getFileId));
+ }
+ List dataList = CollUtils.convert(page.getRecords(), w -> {
+ LeaveListItemVO item = new LeaveListItemVO();
+ item.setLeaveType(w.getType());
+ item.setPostscript(w.getRemark());
+ item.setAuditId(w.getAuditId());
+ item.setLeaveId(w.getId());
+ item.setStartTime(w.getStartTime());
+ item.setEndTime(w.getEndTime());
+ ExpertMetaApply apply = applyMap.get(w.getAuditId());
+ item.setAuditOption(apply != null ? apply.getAuditOpinion() : StrUtil.EMPTY);
+ item.setStatus(w.getStatus());
+ item.setAuditStatus(apply != null ? apply.getApplyStatus() : ExpertApplyStatusEnum.PASSED.getKey());
+ item.setActualEndTime(w.getCancelTime());
+ Meeting meeting = meetingMap.get(w.getMeetingId());
+ item.setMeetingName(meeting != null ? meeting.getName() : StrUtil.EMPTY);
+ item.setAttachments(new ArrayList<>());
+ if (!w.getAttachment().isEmpty()) {
+ Arrays.stream(w.getAttachment().split(",")).forEach(fileId -> item.getAttachments().add(fileMap.get(Long.parseLong(fileId))));
+ }
+ return item;
+ });
+ return PageVo.of(dataList, page.getTotal());
+ }
+
+ public void endLeave(Long leaveId) {
+ ExpertLeave leave = leaveService.getById(leaveId);
+ if (LeaveTypeEnum.TEMPORARY.eq(leave.getType())) {
+ throw BizException.wrap("临时请假不支持销假");
+ }
+ LeaveStatusEnum status = LeaveStatusEnum.getByCode(leave.getStatus());
+ if (!status.equals(LeaveStatusEnum.PASSED) || LocalDateTime.now().isAfter(leave.getEndTime())) {
+ throw BizException.wrap("该请假不支持销假");
+ }
+ LocalDateTime actualEndTime = LocalDateTime.now();
+ LambdaUpdateWrapper updater = Wrappers.lambdaUpdate(ExpertLeave.class)
+ .set(ExpertLeave::getCancelTime, actualEndTime)
+ .set(ExpertLeave::getUpdateOn, actualEndTime)
+ .set(ExpertLeave::getUpdateBy, LoginUserUtil.getUserId())
+ .set(ExpertLeave::getStatus, LeaveStatusEnum.PASSED_END.getCode())
+ .eq(ExpertLeave::getId, leave.getId());
+ leaveService.update(updater);
+ LambdaQueryWrapper deleter = Wrappers.lambdaQuery(ExpertLeaveDetail.class)
+ .ge(ExpertLeaveDetail::getStartTime, actualEndTime.toLocalDate())
+ .eq(ExpertLeaveDetail::getExpertLeaveId, leaveId);
+ leaveDetailService.remove(deleter);
+ }
+
+ public void cancel(Long leaveId) {
+ ExpertLeave leave = leaveService.getById(leaveId);
+ if (LeaveTypeEnum.TEMPORARY.eq(leave.getType())) {
+ throw BizException.wrap("临时请假不支持撤销");
+ }
+ if (LeaveStatusEnum.APPLYING.eq(leave.getStatus())) {
+ throw BizException.wrap("该请假不支持撤销");
+ }
+ LocalDateTime actualEndTime = LocalDateTime.now();
+ // 修改请假状态
+ LambdaUpdateWrapper updater = Wrappers.lambdaUpdate(ExpertLeave.class)
+ .set(ExpertLeave::getUpdateOn, actualEndTime)
+ .set(ExpertLeave::getUpdateBy, LoginUserUtil.getUserId())
+ .set(ExpertLeave::getStatus, LeaveStatusEnum.CANCELED.getCode())
+ .eq(ExpertLeave::getId, leave.getId());
+ leaveService.update(updater);
+ // 删除请假详情
+ LambdaQueryWrapper deleter = Wrappers.lambdaQuery(ExpertLeaveDetail.class)
+ .eq(ExpertLeaveDetail::getExpertLeaveId, leaveId);
+ leaveDetailService.remove(deleter);
+ // 修改审核表
+ LambdaUpdateWrapper updaterApply = Wrappers.lambdaUpdate(ExpertMetaApply.class)
+ .set(ExpertMetaApply::getApplyStatus, ExpertApplyStatusEnum.REVOKED.getKey())
+ .set(ExpertMetaApply::getUpdateOn, LocalDateTime.now())
+ .set(ExpertMetaApply::getAuditOpinion, "发起人撤销")
+ .eq(ExpertMetaApply::getId, leave.getAuditId());
+ metaApplyService.update(updaterApply);
+ }
+
+ public LeaveDetailVO leaveDetail(Long leaveId, Long auditId) {
+ ExpertLeave leave;
+ if (leaveId != null) {
+ leave = leaveService.getById(leaveId);
+ } else {
+ leave = leaveService.getByAuditId(auditId);
+ }
+ LeaveDetailVO detail = LeaveDetailVO.builder()
+ .createOn(leave.getCreateOn())
+ .createBy(leave.getCreator())
+ .postscript(leave.getRemark())
+ .id(leave.getId())
+ .status(leave.getStatus())
+ .startTime(leave.getStartTime())
+ .endTime(leave.getEndTime())
+ .attachments(new ArrayList<>())
+ .type(leave.getType())
+ .actualEndTime(leave.getCancelTime())
+ .auditId(leave.getAuditId())
+ .build();
+ if (LeaveTypeEnum.FIXED_TERM.eq(leave.getType())) {
+ detail.setFixedType(BizUtils.splitToNum(leave.getFixedType(), Integer.class));
+ }
+ if (StrUtils.isNotBlank(leave.getAttachment())) {
+ List fileIds = BizUtils.splitToLong(leave.getAttachment());
+ List files = fileService.getByIds(fileIds);
+ detail.getAttachments().addAll(files);
+ }
+ return detail;
+ }
+
+ public List listLeaveUserIdByTime(LocalDateTime start, LocalDateTime end) {
+ LambdaQueryWrapper leaveDetailQuery = Wrappers.lambdaQuery(ExpertLeaveDetail.class)
+ .select(ExpertLeaveDetail::getExpertLeaveId)
+ .and(wrapper -> wrapper.between(ExpertLeaveDetail::getStartTime, start, end)
+ .or(wrapper1 -> wrapper1.between(ExpertLeaveDetail::getEndTime, start, end)));
+ List detailList = leaveDetailService.list(leaveDetailQuery);
+ if (detailList.isEmpty()) {
+ return new ArrayList<>();
+ }
+ List leaveIdList = CollUtils.fieldList(detailList, ExpertLeaveDetail::getExpertLeaveId);
+ LambdaQueryWrapper leaveQuery = Wrappers.lambdaQuery(ExpertLeave.class)
+ .select(ExpertLeave::getCreateBy)
+ .in(ExpertLeave::getId, leaveIdList)
+ .in(ExpertLeave::getStatus,
+ LeaveStatusEnum.APPLYING.getCode(),
+ LeaveStatusEnum.PASSED.getCode(),
+ LeaveStatusEnum.PASSED_END.getCode());
+ List leaveList = leaveService.list(leaveQuery);
+ return CollUtils.fieldList(leaveList, ExpertLeave::getCreateBy);
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ public void leaveAuditCallback(boolean status, Long applyId) {
+ LambdaUpdateWrapper update = Wrappers.lambdaUpdate(ExpertLeave.class)
+ .set(ExpertLeave::getUpdateBy, LoginUserUtil.getUserId())
+ .set(ExpertLeave::getUpdateOn, LocalDateTime.now())
+ .eq(ExpertLeave::getAuditId, applyId);
+ ExpertLeave leave = leaveService.getByAuditId(applyId);
+ ExpertUserFullInfo leaveUser = userFullInfoService.getByUserId(leave.getLeaveUserId());
+ if (status) {
+ update.set(ExpertLeave::getStatus, LeaveStatusEnum.PASSED.getCode());
+ } else {
+ ExpertMetaApply metaApply = metaApplyService.getById(applyId);
+ update.set(ExpertLeave::getStatus, LeaveStatusEnum.UN_PASSED.getCode());
+ LambdaQueryWrapper delete = Wrappers.lambdaQuery(ExpertLeaveDetail.class)
+ .eq(ExpertLeaveDetail::getExpertLeaveId, leave.getId());
+ leaveDetailService.remove(delete);
+ }
+ leaveService.update(update);
+ }
+
+ public Map> listLeaveIdByDate(LocalDate startDate, LocalDate endDate, Long expertId) {
+ List leaveDetails = leaveDetailService.listByDateAndLeaveUserId(startDate, endDate, expertId);
+ return leaveDetails.stream().collect(Collectors.groupingBy(w -> w.getStartTime().toLocalDate(),
+ Collectors.mapping(ExpertLeaveDetail::getExpertLeaveId, Collectors.toSet())));
+ }
+
+ public PageVo listLeaveApplyingAndCouldBeStop(PagePo po) {
+ LambdaQueryWrapper query = Wrappers.lambdaQuery(ExpertLeave.class)
+ .eq(ExpertLeave::getLeaveUserId, LoginUserUtil.getUserId())
+ .and(wrapper -> wrapper.eq(ExpertLeave::getStatus, LeaveStatusEnum.APPLYING.getCode())
+ .or(wrapper1 -> wrapper1.eq(ExpertLeave::getStatus, LeaveStatusEnum.PASSED.getCode())
+ .gt(ExpertLeave::getCancelTime, LocalDateTime.now())));
+ Page page = leaveService.page(new Page<>(po.getPageNumber(), po.getPageSize()), query);
+ if (page.getTotal() == 0) {
+ return PageVo.empty();
+ }
+ List result = CollUtils.convert(page.getRecords(), w -> {
+ LeaveListItemVO item = new LeaveListItemVO();
+ item.setStartTime(w.getStartTime());
+ item.setEndTime(w.getEndTime());
+ item.setStatus(w.getStatus());
+ item.setLeaveType(w.getType());
+ item.setLeaveId(w.getId());
+ return item;
+ });
+ return PageVo.of(result, page.getTotal());
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/mapper/ExpertLeaveDetailMapper.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/mapper/ExpertLeaveDetailMapper.java
new file mode 100644
index 0000000..7e86713
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/mapper/ExpertLeaveDetailMapper.java
@@ -0,0 +1,46 @@
+package com.ningdatech.pmapi.leave.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ningdatech.pmapi.common.model.entity.KeyValDTO;
+import com.ningdatech.pmapi.leave.entity.domain.ExpertLeaveDetail;
+import org.apache.ibatis.annotations.Param;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ *
+ * 专家请假详情表(维度:天) Mapper 接口
+ *
+ *
+ * @author WendyYang
+ * @since 2022-08-11
+ */
+public interface ExpertLeaveDetailMapper extends BaseMapper {
+
+ /**
+ * 查询时间段之内的请假信息(请假状态:已通过、销假)
+ *
+ * @param leaveUserId 请假人ID
+ * @param startDate 开始时间
+ * @param endDate 结束时间
+ * @return 请假详情
+ * @author WendyYang
+ **/
+ List selectLeaveIdByDateAndExpertId(@Param("leaveUserId") Long leaveUserId,
+ @Param("startDate") LocalDate startDate,
+ @Param("endDate") LocalDate endDate);
+
+ /**
+ * 查询用户在指定时间之内是否有请假
+ *
+ * @param leaveUserId 用户ID
+ * @param times 时间集合
+ * @return 请假天数
+ * @author WendyYang
+ **/
+ Integer existsLeaveByLeaveUserIdAndTime(@Param("leaveUserId") Long leaveUserId,
+ @Param("times") List> times);
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/mapper/ExpertLeaveDetailMapper.xml b/pmapi/src/main/java/com/ningdatech/pmapi/leave/mapper/ExpertLeaveDetailMapper.xml
new file mode 100644
index 0000000..4d5b63e
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/mapper/ExpertLeaveDetailMapper.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/mapper/ExpertLeaveMapper.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/mapper/ExpertLeaveMapper.java
new file mode 100644
index 0000000..4b78046
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/mapper/ExpertLeaveMapper.java
@@ -0,0 +1,16 @@
+package com.ningdatech.pmapi.leave.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ningdatech.pmapi.leave.entity.domain.ExpertLeave;
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author WendyYang
+ * @since 2022-08-11
+ */
+public interface ExpertLeaveMapper extends BaseMapper {
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/mapper/ExpertLeaveMapper.xml b/pmapi/src/main/java/com/ningdatech/pmapi/leave/mapper/ExpertLeaveMapper.xml
new file mode 100644
index 0000000..c95f146
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/mapper/ExpertLeaveMapper.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/service/IExpertLeaveDetailService.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/service/IExpertLeaveDetailService.java
new file mode 100644
index 0000000..b1df329
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/service/IExpertLeaveDetailService.java
@@ -0,0 +1,25 @@
+package com.ningdatech.pmapi.leave.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ningdatech.pmapi.common.model.entity.KeyValDTO;
+import com.ningdatech.pmapi.leave.entity.domain.ExpertLeaveDetail;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ *
+ * 专家请假详情表(维度:天) 服务类
+ *
+ *
+ * @author WendyYang
+ * @since 2022-08-11
+ */
+public interface IExpertLeaveDetailService extends IService {
+
+ List listByDateAndLeaveUserId(LocalDate startDate, LocalDate endDate, Long leaveUserId);
+
+ boolean existsLeaveByUserIdAndTime(Long userId, List> times);
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/service/IExpertLeaveService.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/service/IExpertLeaveService.java
new file mode 100644
index 0000000..f54512c
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/service/IExpertLeaveService.java
@@ -0,0 +1,26 @@
+package com.ningdatech.pmapi.leave.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ningdatech.pmapi.leave.entity.domain.ExpertLeave;
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author WendyYang
+ * @since 2022-08-11
+ */
+public interface IExpertLeaveService extends IService {
+
+ ExpertLeave getByAuditId(Long auditId);
+
+ /**
+ * 是否存在待审核请假记录
+ *
+ * @param expertId 专家ID
+ * @return boolean
+ */
+ boolean existsToBeReviewed(Long expertId);
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/service/impl/ExpertLeaveDetailServiceImpl.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/service/impl/ExpertLeaveDetailServiceImpl.java
new file mode 100644
index 0000000..937100f
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/service/impl/ExpertLeaveDetailServiceImpl.java
@@ -0,0 +1,35 @@
+package com.ningdatech.pmapi.leave.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ningdatech.pmapi.common.model.entity.KeyValDTO;
+import com.ningdatech.pmapi.leave.entity.domain.ExpertLeaveDetail;
+import com.ningdatech.pmapi.leave.mapper.ExpertLeaveDetailMapper;
+import com.ningdatech.pmapi.leave.service.IExpertLeaveDetailService;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ *
+ * 专家请假详情表(维度:天) 服务实现类
+ *
+ *
+ * @author WendyYang
+ * @since 2022-08-11
+ */
+@Service
+public class ExpertLeaveDetailServiceImpl extends ServiceImpl implements IExpertLeaveDetailService {
+
+ @Override
+ public List listByDateAndLeaveUserId(LocalDate startDate, LocalDate endDate, Long leaveUserId) {
+ return baseMapper.selectLeaveIdByDateAndExpertId(leaveUserId, startDate, endDate.plusDays(1));
+ }
+
+ @Override
+ public boolean existsLeaveByUserIdAndTime(Long userId, List> times) {
+ return baseMapper.existsLeaveByLeaveUserIdAndTime(userId, times) != null;
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/leave/service/impl/ExpertLeaveServiceImpl.java b/pmapi/src/main/java/com/ningdatech/pmapi/leave/service/impl/ExpertLeaveServiceImpl.java
new file mode 100644
index 0000000..dda0f17
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/leave/service/impl/ExpertLeaveServiceImpl.java
@@ -0,0 +1,41 @@
+package com.ningdatech.pmapi.leave.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ningdatech.pmapi.leave.entity.domain.ExpertLeave;
+import com.ningdatech.pmapi.leave.entity.enumeration.LeaveStatusEnum;
+import com.ningdatech.pmapi.leave.mapper.ExpertLeaveMapper;
+import com.ningdatech.pmapi.leave.service.IExpertLeaveService;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author WendyYang
+ * @since 2022-08-11
+ */
+@Service
+public class ExpertLeaveServiceImpl extends ServiceImpl implements IExpertLeaveService {
+
+ @Override
+ public ExpertLeave getByAuditId(Long auditId) {
+ if (auditId == 0) {
+ return null;
+ }
+ LambdaQueryWrapper query = Wrappers.lambdaQuery(ExpertLeave.class)
+ .eq(ExpertLeave::getAuditId, auditId);
+ return getOne(query);
+ }
+
+ @Override
+ public boolean existsToBeReviewed(Long expertId) {
+ LambdaQueryWrapper query = Wrappers.lambdaQuery(ExpertLeave.class)
+ .eq(ExpertLeave::getLeaveUserId, expertId)
+ .eq(ExpertLeave::getStatus, LeaveStatusEnum.APPLYING.getCode());
+ return baseMapper.exists(query);
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertAttendStatusEnum.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertAttendStatusEnum.java
index 7f34237..a0f8746 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertAttendStatusEnum.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertAttendStatusEnum.java
@@ -21,6 +21,7 @@ public enum ExpertAttendStatusEnum {
UNANSWERED("未应答", 1),
AGREED("同意参加", 3),
REFUSED("拒绝参加", 4),
+ ON_LEAVE("已请假", 5),
RELEASED("已释放", 7);
private final String value;
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingListReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingListReq.java
index 7375f3a..2d206dd 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingListReq.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingListReq.java
@@ -33,8 +33,7 @@ public class MeetingListReq extends PagePo {
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime endTime;
- @ApiModelProperty("事务状态:1 未完成、2 已完成、3 已取消\n" +
- "专家参与状态:1 待参加、2 已参加、3 已请假")
+ @ApiModelProperty("事务状态")
private Integer status;
@ApiModelProperty("会议类型")
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingByManagerVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingByManagerVO.java
index 2997259..a906367 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingByManagerVO.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingByManagerVO.java
@@ -49,9 +49,6 @@ public class MeetingByManagerVO {
@ApiModelProperty("名单确认状态")
private Boolean confirmedRoster;
- @ApiModelProperty("会议参加状态:1 待参加、2 已参加、3 已请假")
- private Integer attendStatus;
-
@ApiModelProperty("会议名称")
private String meetingName;
@@ -61,4 +58,7 @@ public class MeetingByManagerVO {
@ApiModelProperty("会议类型名称")
private String meetingTypeName;
+ @ApiModelProperty("专家状态")
+ private Integer expertStatus;
+
}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java
index 3a02ad2..30f61d5 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java
@@ -284,15 +284,16 @@ public class MeetingManage {
**/
public PageVo meetingListByExpert(MeetingListReq req) {
Long expertId = req.getExpertId() != null ? req.getExpertId() : LoginUserUtil.getUserId();
- List expertDtoList = meetingExpertService.listByExpertIdAndStatus(expertId, req.getStatus(), null);
- if (expertDtoList.isEmpty()) {
+ List meetings = meetingExpertService.listByExpertIdAndStatus(expertId, null, null);
+ if (meetings.isEmpty()) {
return PageVo.empty();
}
Map mapByMeetingId = new HashMap<>(16);
- expertDtoList.forEach(w -> mapByMeetingId.put(w.getMeetingId(), w));
+ meetings.forEach(w -> mapByMeetingId.put(w.getMeetingId(), w));
LambdaQueryWrapper query = new LambdaQueryWrapper()
.orderByDesc(Meeting::getCreateOn)
.in(Meeting::getId, mapByMeetingId.keySet())
+ .eq(Meeting::getConfirmedRoster, Boolean.TRUE)
.ne(Meeting::getStatus, MeetingStatusEnum.CANCELED.getCode());
if (req.getExpertId() == null) {
meetingManageHelper.buildMeetingQuery(query, req);
@@ -305,7 +306,7 @@ public class MeetingManage {
page.getRecords().forEach(meeting -> {
MeetingByManagerVO item = meetingManageHelper.buildByMeeting(meeting);
MeetingAndAttendStatusDTO info = mapByMeetingId.get(meeting.getId());
- item.setAttendStatus(meetingManageHelper.getExpertAttendStatus(info));
+ item.setExpertStatus(info.getStatus());
result.getRecords().add(item);
});
return result;
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertInviteTask.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertInviteTask.java
index 3caf61b..f58915e 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertInviteTask.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/task/ExpertInviteTask.java
@@ -1,5 +1,6 @@
package com.ningdatech.pmapi.meeting.task;
+import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -21,7 +22,6 @@ import com.ningdatech.pmapi.meeting.service.IExpertInviteAvoidRuleService;
import com.ningdatech.pmapi.meeting.service.IExpertInviteRuleService;
import com.ningdatech.pmapi.meeting.service.IMeetingExpertService;
import com.ningdatech.pmapi.meeting.service.IMeetingService;
-import com.ningdatech.pmapi.user.util.LoginUserUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@@ -146,18 +146,23 @@ public class ExpertInviteTask {
/**
* 唤醒某个会议的抽取任务
*
- * @param meetingId 会议ID
+ * @param meetingId 会议ID
+ * @param invitedRefused 是否可邀请已拒绝的专家
* @author WendyYang
**/
- public void notifyInviteTask(Long meetingId) {
+ public void notifyInviteTask(Long meetingId, boolean... invitedRefused) {
+ boolean tmpInvitedRefused = true;
+ if (ArrayUtil.isNotEmpty(invitedRefused)) {
+ tmpInvitedRefused = invitedRefused[0];
+ }
if (!INVITE_MAP.containsKey(meetingId)) {
- addInviteExpertTask(meetingId, false, properties.getInviteDelay(), true);
+ addInviteExpertTask(meetingId, false, properties.getInviteDelay(), tmpInvitedRefused);
log.info("重置会议的随机抽取状态:{}", meetingId);
LambdaUpdateWrapper update = Wrappers.lambdaUpdate(Meeting.class);
update.set(Meeting::getInviteStatus, false);
update.eq(Meeting::getId, meetingId);
meetingService.update(update);
- InviteCacheDTO cacheVal = InviteCacheDTO.of(meetingId, true);
+ InviteCacheDTO cacheVal = InviteCacheDTO.of(meetingId, tmpInvitedRefused);
cachePlusOps.hSet(getCacheKey(meetingId), cacheVal);
}
}
@@ -252,11 +257,7 @@ public class ExpertInviteTask {
});
if (notIgnoreCnt.get() == 0 || notIgnoreCnt.get() == notSupportCnt.get()) {
if (notSupportCnt.get() > 0) {
- // TODO
- /*UserInfo inviterBasic = userInfoService.getById(meeting.getCreateBy());
- UserInfo inviter = userInfoService.getById(inviterBasic.getId());
- SendSmsContext context = YxtSmsContextBuilder.smsByRandomInviteStop(inviter.getNickname(), meeting.getName(), inviterBasic.getPhoneNo());
- yxtCallOrSmsHelper.sendSms(context);*/
+ // TODO 发送邀请停止短信
}
log.info("停止会议随机邀请:{} 未完成抽取规则数量 {} 无可抽取专家规则数量 {}", meetingId, notIgnoreCnt, notSupportCnt);
currProxy().cancelByMeetingId(meetingId);
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/controller/DeclaredProjectController.java b/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/controller/DeclaredProjectController.java
index 3881b56..bf99653 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/controller/DeclaredProjectController.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/controller/DeclaredProjectController.java
@@ -1,13 +1,11 @@
package com.ningdatech.pmapi.projectdeclared.controller;
import com.ningdatech.basic.model.PageVo;
-import com.ningdatech.pmapi.projectdeclared.manage.DefaultDeclaredProjectManage;
import com.ningdatech.pmapi.projectdeclared.model.dto.DeclaredProjectListParamDTO;
import com.ningdatech.pmapi.projectdeclared.model.dto.DefaultDeclaredDTO;
import com.ningdatech.pmapi.projectdeclared.model.dto.ProjectDraftSaveDTO;
import com.ningdatech.pmapi.projectdeclared.model.vo.ProjectDraftVO;
import com.ningdatech.pmapi.projectdeclared.manage.DeclaredProjectManage;
-import com.ningdatech.pmapi.projectlib.manage.ProjectLibManage;
import com.ningdatech.pmapi.projectlib.model.req.ProjectListReq;
import com.ningdatech.pmapi.projectlib.model.vo.ProjectLibListItemVO;
import io.swagger.annotations.Api;
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ConstructionPlanManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ConstructionPlanManage.java
index 2bf9ab0..900a988 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ConstructionPlanManage.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ConstructionPlanManage.java
@@ -117,8 +117,8 @@ public class ConstructionPlanManage {
})
);
params.setFormData(dto.getFormData());
- // 获取发起单位、发起单位主管单位信息
- Map orgModelMap = defaultDeclaredProjectManage.getOrgModelInfo(userId, model);
+ // 获取发起单位、发起单位主管单位、发起单位上级条线主管单位信息
+ Map orgModelMap = defaultDeclaredProjectManage.getOrgModelInfo(userId);
String instanceId = processService.newStartProcess(model.getProcessDefId(),model.getFormId(), params,orgModelMap);
log.info("建设方案项目申报成功 【{}】", instanceId);
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DeclaredProjectManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DeclaredProjectManage.java
index 47b456a..bd5c3bc 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DeclaredProjectManage.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DeclaredProjectManage.java
@@ -143,8 +143,8 @@ public class DeclaredProjectManage {
);
params.setFormData(dto.getFormData());
//开始申报
- // 获取发起单位、发起单位主管单位流程信息map
- Map orgModelMap = defaultDeclaredProjectManage.getOrgModelInfo(userId, model);
+ // 获取发起单位、发起单位主管单位、发起单位上级主管条线单位信息
+ Map orgModelMap = defaultDeclaredProjectManage.getOrgModelInfo(userId);
String instanceId = processService.newStartProcess(model.getProcessDefId(),model.getFormId(), params,orgModelMap);
log.info("申报项目成功 【{}】", instanceId);
@@ -207,8 +207,8 @@ public class DeclaredProjectManage {
})
);
params.setFormData(dto.getFormData());
- // 获取发起单位、发起单位主管单位流程信息map
- Map orgModelMap = defaultDeclaredProjectManage.getOrgModelInfo(userId, model);
+ // 获取发起单位、发起单位主管单位、发起单位上级主管条线单位信息
+ Map orgModelMap = defaultDeclaredProjectManage.getOrgModelInfo(userId);
String instanceId = processService.newStartProcess(model.getProcessDefId(),model.getFormId(), params,orgModelMap);
log.info("重新申报项目成功 【{}】", instanceId);
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DefaultDeclaredProjectManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DefaultDeclaredProjectManage.java
index 7842f1f..0754d51 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DefaultDeclaredProjectManage.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/DefaultDeclaredProjectManage.java
@@ -67,7 +67,7 @@ public class DefaultDeclaredProjectManage {
.build();
}
- public Map getOrgModelInfo(Long userId, WflowModels model) {
+ public Map getOrgModelInfo(Long userId) {
Map orgMap = new HashMap<>();
// 查出所有的单位流程配置
@@ -78,8 +78,16 @@ public class DefaultDeclaredProjectManage {
.eq(DingOrganization::getOrganizationCode, userFullInfo.getOrganizationCode()));
String startOrgCode = startOrg.getOrganizationCode();
String startOrgName = startOrg.getOrganizationName();
- String startOrgParentCode = startOrg.getParentCode();
- String startOrgParentName = startOrg.getParentName();
+ String startOrgParentCode;
+ String startOrgParentName;
+ // 如果没有上级主管单位,由该单位自己审核
+ if (Objects.isNull(startOrg.getParentCode())){
+ startOrgParentCode = startOrgCode;
+ startOrgParentName = startOrgName;
+ }else {
+ startOrgParentCode = startOrg.getParentCode();
+ startOrgParentName = startOrg.getParentName();
+ }
//查询 当前发起人及主管单位所在区域的 单位流程配置
OrgInfoDTO startOrgInfoDto = new OrgInfoDTO();
startOrgInfoDto.setOrganizationCode(startOrgCode);
@@ -105,6 +113,8 @@ public class DefaultDeclaredProjectManage {
orgMap.put(OrgTypeEnum.TARGET_OWNER.name(),startOrgInfoDto);
orgMap.put(OrgTypeEnum.TARGET_MANAGEMENT.name(),parentOrgInfoDto);
+ // TODO 上级条线主管单位信息(可能是多个)
+
// 如果是指定单位,直接根据流程定义ID放入map
OrgInfoDTO orgInfoDTO = new OrgInfoDTO();
orgInfoDTO.setOrgModelMap(orgModelsList.stream()
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/PrequalificationDeclaredProjectManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/PrequalificationDeclaredProjectManage.java
index 9653119..85c2156 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/PrequalificationDeclaredProjectManage.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/PrequalificationDeclaredProjectManage.java
@@ -139,8 +139,8 @@ public class PrequalificationDeclaredProjectManage {
);
params.setFormData(dto.getFormData());
- // 获取发起单位、发起单位主管单位信息
- Map orgModelMap = defaultDeclaredProjectManage.getOrgModelInfo(userId, model);
+ // 获取发起单位、发起单位主管单位、发起单位上级主管条线单位信息
+ Map orgModelMap = defaultDeclaredProjectManage.getOrgModelInfo(userId);
instanceId = processService.newStartProcess(model.getProcessDefId(),model.getFormId(), params,orgModelMap);
log.info("提交预审项目成功 【{}】", instanceId);
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ReviewByDeptJointManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ReviewByDeptJointManage.java
index 911c6fe..5be0b00 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ReviewByDeptJointManage.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/projectdeclared/manage/ReviewByDeptJointManage.java
@@ -104,8 +104,8 @@ public class ReviewByDeptJointManage {
);
params.setFormData(formData);
- // 获取发起单位、发起单位主管单位信息
- Map orgModelMap = defaultDeclaredProjectManage.getOrgModelInfo(userId, model);
+ // 获取发起单位、发起单位主管单位、发起单位上级主管条线单位信息
+ Map orgModelMap = defaultDeclaredProjectManage.getOrgModelInfo(userId);
String instanceId = processService.newStartProcess(model.getProcessDefId(),model.getFormId(), params,orgModelMap);
log.info("部门联审申报成功 【{}】", instanceId);
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/helper/ProjectHelper.java b/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/helper/ProjectHelper.java
index b6fda91..2f43b1e 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/helper/ProjectHelper.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/helper/ProjectHelper.java
@@ -50,7 +50,8 @@ public class ProjectHelper {
.in(CollUtil.isNotEmpty(req.getStageList()),Project::getStage,req.getStageList())
.in(CollUtil.isNotEmpty(req.getStatusList()),Project::getStatus,req.getStatusList())
//实例code
- .in(CollUtil.isNotEmpty(req.getInstCodes()),Project::getInstCode,req.getInstCodes());
+ .in(CollUtil.isNotEmpty(req.getInstCodes()),Project::getInstCode,req.getInstCodes())
+ .orderByDesc(Project::getCreateOn);
return query;
}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/InitProcessTask.java b/pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/InitProcessTask.java
index 0218dda..c1cfbe1 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/InitProcessTask.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/scheduler/task/InitProcessTask.java
@@ -12,12 +12,10 @@ import com.ningdatech.pmapi.common.enumeration.ProjectProcessStageEnum;
import com.ningdatech.pmapi.common.helper.RegionCacheHelper;
import com.ningdatech.pmapi.scheduler.contants.TaskContant;
import com.ningdatech.pmapi.sys.model.dto.RegionDTO;
-import com.ningdatech.pmapi.sys.model.entity.Region;
import com.ningdatech.pmapi.sys.service.IRegionService;
-import com.wflow.bean.dto.WflowModelHistorysDto;
+import com.wflow.bean.dto.WflowModelHistorysInsertDto;
import com.wflow.bean.entity.WflowForms;
import com.wflow.bean.entity.WflowModels;
-import com.wflow.workflow.bean.dto.OrgInfoDTO;
import com.wflow.workflow.bean.process.ProcessNode;
import com.wflow.workflow.service.ProcessModelService;
import com.wflow.workflow.service.WflowFormsService;
@@ -111,9 +109,9 @@ public class InitProcessTask {
Integer[] processTypeList = TaskContant.Wflow.DEFAULT_PROCESS_TYPE_LIST;
for(Integer processType : processTypeList){
String formName = ProjectProcessStageEnum.getDesc(processType);
- WflowModelHistorysDto models = new WflowModelHistorysDto();
+ WflowModelHistorysInsertDto models = new WflowModelHistorysInsertDto();
// models.setFormId("wf" + IdUtil.objectId());
- models.setVersion(1);
+// models.setVersion(1);
models.setGroupId(1);
models.setProcessDefId("pd" + IdUtil.objectId());
models.setFormName(formName);
@@ -125,7 +123,7 @@ public class InitProcessTask {
models.setSettings("{\"sign\":false,\"admin\":[],\"notify\":{},\"commiter\":[]}");
models.setFormItems("[]");
- String formId = processModelService.saveProcess(models);
+ String formId = processModelService.insertProcess(models);
if(StringUtils.isNotBlank(formId)){
//初始的流程在部署表也存一份,用来查询
if(StringUtils.isNotBlank(processModelService.deployProcess(formId,null))){
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java
index 488232c..d11230d 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java
@@ -215,7 +215,7 @@ public class TodoCenterManage {
Project declaredProject = projectService.getOne(Wrappers.lambdaQuery(Project.class)
.eq(Project::getInstCode, processInstanceId)
.eq(Project::getId, projectId));
- VUtils.isTrue(Objects.isNull(projectId)).throwMessage("获取项目ID失败!");
+ VUtils.isTrue(Objects.isNull(declaredProject)).throwMessage("获取项目失败!");
// 获取当前项目名称
String projectName = declaredProject.getProjectName();
// 获取当前项目状态