diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/model/entity/CountGroupByDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/model/entity/CountGroupByDTO.java
new file mode 100644
index 0000000..9c4de54
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/model/entity/CountGroupByDTO.java
@@ -0,0 +1,20 @@
+package com.ningdatech.pmapi.common.model.entity;
+
+import lombok.Data;
+
+/**
+ *
{
+
+ private Integer total;
+
+ private T groupKey;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/util/BizUtils.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/util/BizUtils.java
index 66d8e18..15d5ec3 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/common/util/BizUtils.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/util/BizUtils.java
@@ -5,13 +5,13 @@ import com.ningdatech.basic.util.StrPool;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.NumberUtils;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.UUID;
+import java.util.*;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.stream.Collectors;
+import static java.util.stream.Collectors.toList;
+
/**
*
* BizUtils
@@ -26,6 +26,12 @@ public class BizUtils {
}
+ public static > void notEmpty(T objs, Consumer consumer) {
+ if (objs != null && !objs.isEmpty()) {
+ consumer.accept(objs);
+ }
+ }
+
public static List splitToNum(String str, Class aClass) {
if (StrUtil.isEmpty(str)) {
return Collections.emptyList();
@@ -46,7 +52,7 @@ public class BizUtils {
}
}
- public static void notBlank(String str,Consumer consumer) {
+ public static void notBlank(String str, Consumer consumer) {
if (StrUtil.isNotBlank(str)) {
consumer.accept(str);
}
@@ -69,4 +75,34 @@ public class BizUtils {
return UUID.randomUUID().toString().replace("-", "");
}
+ /**
+ * 对象分组取第一条
+ *
+ * @param objs 对象集合
+ * @param group 分组函数
+ * @param comparator 比较器
+ * @return java.util.Collection
+ * @author WendyYang
+ **/
+ public static Collection groupFirst(Collection objs, Function group, Comparator comparator) {
+ return groupFirstMap(objs, group, comparator).values();
+ }
+
+ /**
+ * 对象分组取第一条
+ *
+ * @param objs 对象集合
+ * @param group 分组函数
+ * @param comparator 比较器
+ * @return java.util.Collection
+ * @author WendyYang
+ **/
+ public static Map groupFirstMap(Collection objs, Function group, Comparator comparator) {
+ return objs.stream().collect(Collectors.groupingBy(group,
+ Collectors.collectingAndThen(toList(), w -> {
+ w.sort(comparator);
+ return w.get(0);
+ })));
+ }
+
}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/util/StrUtils.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/util/StrUtils.java
new file mode 100644
index 0000000..f034ed1
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/util/StrUtils.java
@@ -0,0 +1,29 @@
+package com.ningdatech.pmapi.common.util;
+
+import cn.hutool.core.text.StrPool;
+import cn.hutool.core.util.StrUtil;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ *
+ * StrUtils
+ *
+ *
+ * @author WendyYang
+ * @since 21:23 2023/2/23
+ */
+public class StrUtils extends StrUtil {
+
+ private StrUtils() {
+ }
+
+ public static List split(String str) {
+ if (isBlank(str)) {
+ return Collections.emptyList();
+ }
+ return split(str, StrPool.COMMA);
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/expert/helper/PermissionCheckHelper.java b/pmapi/src/main/java/com/ningdatech/pmapi/expert/helper/PermissionCheckHelper.java
new file mode 100644
index 0000000..bb6a413
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/expert/helper/PermissionCheckHelper.java
@@ -0,0 +1,20 @@
+package com.ningdatech.pmapi.expert.helper;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author liuxinxin
+ * @date 2022/8/18 上午10:02
+ * 校验是否一个账号对一个专家有操作的权限
+ */
+@Component
+@RequiredArgsConstructor
+public class PermissionCheckHelper {
+
+ public boolean isSuperAdmin() {
+ // TODO
+ return false;
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IExpertIntentionWorkRegionService.java b/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IExpertIntentionWorkRegionService.java
index 6c1a9b5..b597d54 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IExpertIntentionWorkRegionService.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IExpertIntentionWorkRegionService.java
@@ -3,6 +3,8 @@ package com.ningdatech.pmapi.expert.service;
import com.ningdatech.pmapi.expert.entity.ExpertIntentionWorkRegion;
import com.baomidou.mybatisplus.extension.service.IService;
+import java.util.List;
+
/**
*
* 服务类
@@ -13,4 +15,14 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface IExpertIntentionWorkRegionService extends IService {
+ /**
+ * 根据履职意向地或许满足履职意向地的用户ID集合
+ *
+ * @param regionCode regionCode
+ * @param regionLevel regionLevel
+ * @return java.util.List
+ * @author WendyYang
+ **/
+ List userIdsMatchIntentionRegion(String regionCode, Integer regionLevel);
+
}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IExpertUserFullInfoService.java b/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IExpertUserFullInfoService.java
index 7b5960a..af68be9 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IExpertUserFullInfoService.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/IExpertUserFullInfoService.java
@@ -1,11 +1,13 @@
package com.ningdatech.pmapi.expert.service;
-import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo;
import com.baomidou.mybatisplus.extension.service.IService;
+import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo;
+
+import java.util.List;
/**
*
- * 服务类
+ * 服务类
*
*
* @author Liuxinxin
@@ -21,4 +23,13 @@ public interface IExpertUserFullInfoService extends IService
* @return /
**/
ExpertUserFullInfo getByUserId(Long userId);
+
+ /**
+ * 查询用户信息
+ *
+ * @param userId 用户ID
+ * @return /
+ **/
+ List listByUserId(List userId);
+
}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/impl/ExpertIntentionWorkRegionServiceImpl.java b/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/impl/ExpertIntentionWorkRegionServiceImpl.java
index 74403d9..244f97d 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/impl/ExpertIntentionWorkRegionServiceImpl.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/impl/ExpertIntentionWorkRegionServiceImpl.java
@@ -1,14 +1,19 @@
package com.ningdatech.pmapi.expert.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.basic.util.CollUtils;
import com.ningdatech.pmapi.expert.entity.ExpertIntentionWorkRegion;
import com.ningdatech.pmapi.expert.mapper.ExpertIntentionWorkRegionMapper;
import com.ningdatech.pmapi.expert.service.IExpertIntentionWorkRegionService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
+import java.util.List;
+
/**
*
- * 服务实现类
+ * 服务实现类
*
*
* @author Liuxinxin
@@ -17,4 +22,14 @@ import org.springframework.stereotype.Service;
@Service
public class ExpertIntentionWorkRegionServiceImpl extends ServiceImpl implements IExpertIntentionWorkRegionService {
+ @Override
+ public List userIdsMatchIntentionRegion(String regionCode, Integer regionLevel) {
+ LambdaQueryWrapper intentionQuery = Wrappers.lambdaQuery(ExpertIntentionWorkRegion.class)
+ .eq(ExpertIntentionWorkRegion::getRegionCode, regionCode)
+ .eq(ExpertIntentionWorkRegion::getRegionLevel, regionLevel)
+ .select(ExpertIntentionWorkRegion::getUserId);
+ List userIdMatchIntentionRegion = list(intentionQuery);
+ return CollUtils.fieldList(userIdMatchIntentionRegion, ExpertIntentionWorkRegion::getUserId);
+ }
+
}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/impl/ExpertUserFullInfoServiceImpl.java b/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/impl/ExpertUserFullInfoServiceImpl.java
index 4b22e1f..69544bc 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/impl/ExpertUserFullInfoServiceImpl.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/expert/service/impl/ExpertUserFullInfoServiceImpl.java
@@ -28,4 +28,9 @@ public class ExpertUserFullInfoServiceImpl extends ServiceImpllambdaQuery().eq(ExpertUserFullInfo::getUserId, userId));
}
+ @Override
+ public List listByUserId(List userIds) {
+ return list(Wrappers.lambdaQuery().in(ExpertUserFullInfo::getUserId, userIds));
+ }
+
}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/builder/ExpertInviteBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/builder/ExpertInviteBuilder.java
new file mode 100644
index 0000000..1191f09
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/builder/ExpertInviteBuilder.java
@@ -0,0 +1,40 @@
+package com.ningdatech.pmapi.meeting.builder;
+
+import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo;
+import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert;
+import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteType;
+import com.ningdatech.pmapi.user.entity.UserInfo;
+
+/**
+ *
+ * ExpertInviteBuilder
+ *
+ *
+ * @author WendyYang
+ * @since 21:30 2022/11/21
+ */
+public class ExpertInviteBuilder {
+
+ private ExpertInviteBuilder() {
+ }
+
+ public static MeetingExpert getExpertByRandom(Long meetingId, ExpertUserFullInfo user, Long ruleId) {
+ return getExpertBasic(meetingId, user, ruleId, ExpertInviteType.RANDOM);
+ }
+
+ private static MeetingExpert getExpertBasic(Long meetingId, ExpertUserFullInfo user, Long ruleId, ExpertInviteType type) {
+ MeetingExpert expert = new MeetingExpert();
+ expert.setMeetingId(meetingId);
+ expert.setMobile(user.getPhoneNo());
+ expert.setExpertId(user.getId());
+ expert.setExpertName(user.getExpertName());
+ expert.setRuleId(ruleId);
+ expert.setInviteType(type.getCode());
+ return expert;
+ }
+
+ public static MeetingExpert getExpertByAppoint(Long meetingId, ExpertUserFullInfo user, Long ruleId) {
+ return getExpertBasic(meetingId, user, ruleId, ExpertInviteType.APPOINT);
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/builder/YxtSmsContextBuilder.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/builder/YxtSmsContextBuilder.java
new file mode 100644
index 0000000..4d150cd
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/builder/YxtSmsContextBuilder.java
@@ -0,0 +1,129 @@
+//package com.ningdatech.pmapi.meeting.builder;
+//
+//
+//import com.ningdatech.pmapi.meeting.entity.domain.Meeting;
+//import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert;
+//import com.ningdatech.pmapi.sms.utils.DateUtil;
+//
+//import java.time.format.DateTimeFormatter;
+//import java.util.ArrayList;
+//import java.util.List;
+//
+///**
+// *
+// * YxtSmsContextBuilder
+// *
+// *
+// * @author WendyYang
+// * @since 14:19 2022/11/17
+// */
+//public class YxtSmsContextBuilder {
+//
+// private YxtSmsContextBuilder() {
+// }
+//
+// public static List smsToExpertByCancelMeeting(Meeting meeting, List experts, String meetingType) {
+// String holdCompany = meeting.getHoldCompanyBracket();
+// String meetingTime = meeting.getStartTime().format(DateUtil.DTF_YMD_HM);
+// List contexts = new ArrayList<>();
+// for (MeetingExpert me : experts) {
+// SendSmsContext context = new SendSmsContext();
+// context.setContent(holdCompany + String.format(YxtSmsTemplateConst.MEETING_CANCEL,
+// me.getExpertName(), meeting.getCancelRemark(), meetingTime, meetingType, meeting.getContact()));
+// context.setReceiveNumber(me.getMobile());
+// contexts.add(context);
+// }
+// return contexts;
+// }
+//
+// public static List smsToExpertBySendNotice(Meeting meeting, List experts, String meetingType) {
+// String holdCompany = meeting.getHoldCompanyBracket();
+// String meetingTime = meeting.getStartTime().format(DateUtil.DTF_YMD_HM);
+// List contexts = new ArrayList<>();
+// for (MeetingExpert me : experts) {
+// SendSmsContext context = new SendSmsContext();
+// context.setContent(holdCompany + String.format(YxtSmsTemplateConst.SEND_MEETING_NOTICE,
+// me.getExpertName(), me.getUpdateOn().format(DateUtil.DTF_YMD_HM),
+// meetingType, meetingTime, meeting.getRegionDetail(), meeting.getContact()));
+// context.setReceiveNumber(me.getMobile());
+// contexts.add(context);
+// }
+// return contexts;
+// }
+//
+// public static SendSmsContext smsToExpertByReplace(Meeting meeting, MeetingExpert expert, String meetingType) {
+// SendSmsContext context = new SendSmsContext();
+// String holdCompany = meeting.getHoldCompanyBracket();
+// context.setContent(holdCompany + String.format(YxtSmsTemplateConst.EXPERT_REPLACED,
+// expert.getExpertName(),
+// meeting.getStartTime().format(DateUtil.DTF_YMD_HM),
+// meetingType,
+// meeting.getContact()
+// ));
+// context.setReceiveNumber(expert.getMobile());
+// return context;
+// }
+//
+// public static List smsToExpertByMeetingChange(Meeting old, Meeting curr, List experts, String meetingType) {
+// List contexts = new ArrayList<>();
+// String holdCompany = curr.getHoldCompanyBracket();
+// String sTimeOld = old.getStartTime().format(DateUtil.DTF_YMD_HM);
+// String sTimeNew = curr.getStartTime().format(DateUtil.DTF_YMD_HM);
+// for (MeetingExpert me : experts) {
+// SendSmsContext context = new SendSmsContext();
+// String content = String.format(YxtSmsTemplateConst.MEETING_INGO_CHANGE, me.getExpertName(),
+// sTimeOld, meetingType, sTimeNew, curr.getRegionDetail(), curr.getContact());
+// context.setContent(holdCompany + content);
+// context.setReceiveNumber(me.getMobile());
+// contexts.add(context);
+// }
+// return contexts;
+// }
+//
+// public static SendSmsContext smsToInvitorByExpertLeave(UserBasicInfo invitor, String meetingName, String expertName) {
+// SendSmsContext context = new SendSmsContext();
+// context.setReceiveNumber(invitor.getPhoneNo());
+// context.setContent(String.format(YxtSmsTemplateConst.TEMP_LEAVE_APPLY, invitor.getNickName(),
+// meetingName, expertName, WebProperties.webUrl));
+// return context;
+// }
+//
+// public static SendSmsContext smsToExpertByLeavePassed(ExpertLeave leave, String leaveUser, String mobile) {
+// String smsContent = String.format(YxtSmsTemplateConst.LEAVE_APPLY_PASSED, leaveUser,
+// leave.getStartTime().format(DateTimeFormatter.ofPattern(DatePattern.YMD_HMS)),
+// leave.getEndTime().format(DateTimeFormatter.ofPattern(DatePattern.YMD_HMS)));
+// SendSmsContext context = new SendSmsContext();
+// context.setContent(smsContent);
+// context.setReceiveNumber(mobile);
+// return context;
+// }
+//
+// public static SendSmsContext smsToExpertBtLeaveReject(String leaveUser, String mobile, String opinion) {
+// String smsContent = String.format(YxtSmsTemplateConst.LEAVE_APPLY_REFUSED, leaveUser, opinion);
+// SendSmsContext context = new SendSmsContext();
+// context.setContent(smsContent);
+// context.setReceiveNumber(mobile);
+// return context;
+// }
+//
+// public static SendSmsContext smsByRandomInviteStop(String inviterName, String meetingName, String mobile) {
+// String smsContent = String.format(YxtSmsTemplateConst.RANDOM_INVITE_STOP,
+// inviterName, meetingName, WebProperties.webUrl
+// );
+// SendSmsContext context = new SendSmsContext();
+// context.setContent(smsContent);
+// context.setReceiveNumber(mobile);
+// return context;
+// }
+//
+//
+// public static SendSmsContext meetingInviteCompleteNotice(Meeting meeting) {
+// String smsContent = String.format(YxtSmsTemplateConst.RANDOM_EXTRACTION_COMPLETED,
+// meeting.getConnecter(), meeting.getName(), WebProperties.webUrl
+// );
+// SendSmsContext context = new SendSmsContext();
+// context.setContent(smsContent);
+// context.setReceiveNumber(meeting.getContact());
+// return context;
+// }
+//}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/DashboardController.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/DashboardController.java
new file mode 100644
index 0000000..3841f7c
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/DashboardController.java
@@ -0,0 +1,77 @@
+package com.ningdatech.pmapi.meeting.controller;
+
+import com.ningdatech.basic.model.PagePo;
+import com.ningdatech.basic.model.PageVo;
+import com.ningdatech.log.annotation.WebLog;
+import com.ningdatech.pmapi.meeting.entity.req.MeetingCalenderReq;
+import com.ningdatech.pmapi.meeting.entity.vo.*;
+import com.ningdatech.pmapi.meeting.manage.DashboardManage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ *
+ * DashboardController
+ *
+ *
+ * @author WendyYang
+ * @since 22:19 2022/8/24
+ */
+@Api(tags = "工作台相关接口")
+@RestController
+@AllArgsConstructor
+@RequestMapping("/api/v1/dashboard")
+public class DashboardController {
+
+ private final DashboardManage dashboardManage;
+
+ @ApiOperation("会议日历")
+ @GetMapping("/meetingCalender")
+ @WebLog(value = "会议日历")
+ public List meetingCalender(@Valid MeetingCalenderReq po) {
+ return dashboardManage.meetingCalender(po);
+ }
+
+ @ApiOperation("待办:专家评价列表")
+ @GetMapping("/todo/expertEvaluation")
+ @WebLog(value = "待办:专家评价列表")
+ public PageVo expertEvaluationToDo(PagePo po) {
+ return dashboardManage.expertEvaluationToDo(po);
+ }
+
+ @ApiOperation("待办:专家待替换列表")
+ @GetMapping("/todo/expertReplace")
+ @WebLog(value = "待办:专家待替换列表")
+ public PageVo expertReplaceToDo(PagePo po) {
+ return dashboardManage.expertReplaceTodoList(po);
+ }
+
+ @ApiOperation("待办:专家待确认列表")
+ @GetMapping("/todo/expertConfirm")
+ @WebLog(value = "待办:专家待确认列表")
+ public PageVo expertConfirmToDo(PagePo po) {
+ return dashboardManage.expertConfirmToDo(po);
+ }
+
+ @ApiOperation("会议数量统计")
+ @GetMapping("/meetingCountSummary")
+ @WebLog(value = "会议数量统计")
+ public MeetingCountSummaryVO meetingCountSummary() {
+ return dashboardManage.meetingCountSummary();
+ }
+
+ @ApiOperation("专家工作台:会议数量统计")
+ @GetMapping("/meetingCountByExpert")
+ @WebLog(value = "专家工作台:会议数量统计")
+ public MeetingCountByExpertVO meetingCountByExpert() {
+ return dashboardManage.meetingCountByExpert();
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingController.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingController.java
new file mode 100644
index 0000000..eb2e25e
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/controller/MeetingController.java
@@ -0,0 +1,173 @@
+package com.ningdatech.pmapi.meeting.controller;
+
+
+import com.ningdatech.basic.model.IdVo;
+import com.ningdatech.basic.model.PageVo;
+import com.ningdatech.log.annotation.WebLog;
+import com.ningdatech.pmapi.meeting.entity.dto.MeetingBasicDTO;
+import com.ningdatech.pmapi.meeting.entity.req.*;
+import com.ningdatech.pmapi.meeting.entity.vo.*;
+import com.ningdatech.pmapi.meeting.manage.MeetingManage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+/**
+ *
+ * 会议 前端控制器
+ *
+ *
+ * @author WendyYang
+ * @since 2022-07-26
+ */
+@Validated
+@RestController
+@AllArgsConstructor
+@Api(tags = "会议管理")
+@RequestMapping("/api/v1/meeting")
+public class MeetingController {
+
+ private final MeetingManage meetingManage;
+
+ @PostMapping("/save")
+ @ApiOperation("新建会议")
+ @WebLog(value = "新建会议")
+ public IdVo meetingCreate(@Valid @RequestBody MeetingBasicDTO po) {
+ return meetingManage.save(po);
+ }
+
+ @PostMapping("/expertInviteByCreate")
+ @ApiOperation("新建会议-专家抽取")
+ @WebLog(value = "新建会议-专家抽取")
+ public void expertInviteByCreate(@Valid @RequestBody ExpertInviteCreateReq po) {
+ meetingManage.expertInviteByCreate(po);
+ }
+
+ @ApiOperation("专家抽取数量校验")
+ @PostMapping("/expertCountOnChange")
+ public ExpertCountOnChangeVO expertCountOnChange(@RequestBody ExpertInviteCreateReq po) {
+ return meetingManage.expertCountOnChange(po);
+ }
+
+ @ApiOperation("专家抽取员事务列表")
+ @GetMapping("/meetingListByManager")
+ @WebLog(value = "专家抽取员事务列表")
+ public PageVo meetingListByManager(MeetingListReq po) {
+ return meetingManage.meetingListByManager(po);
+ }
+
+ @ApiOperation("履职记录 | 专家会议列表")
+ @GetMapping("/meetingListByExpert")
+ @WebLog(value = "履职记录 | 专家会议列表")
+ public PageVo meetingListByExpert(MeetingListReq po) {
+ return meetingManage.meetingListByExpert(po);
+ }
+
+ @ApiOperation("会议详情-基本信息")
+ @GetMapping("detail/{meetingId}/basicInfo")
+ @WebLog(value = "会议详情-基本信息")
+ public MeetingDetailBasicVO meetingBasic(@PathVariable Long meetingId) {
+ return meetingManage.getMeetingBasicInfo(meetingId);
+ }
+
+ @ApiOperation("会议结果上传")
+ @PostMapping("/uploadMeetingResult")
+ @WebLog(value = "会议结果上传")
+ public void uploadMeetingResult(@Valid @RequestBody MeetingResultReq po) {
+ meetingManage.uploadMeetingResult(po);
+
+ }
+
+ @ApiOperation("会议结果详情")
+ @GetMapping("/detail/{meetingId}/meetingResult")
+ @WebLog(value = "会议结果详情况")
+ public MeetingResultVO meetingResultDetail(@PathVariable Long meetingId) {
+ return meetingManage.meetingResultDetail(meetingId);
+ }
+
+ @ApiOperation("邀请情况详情")
+ @GetMapping("/detail/{meetingId}/inviteDetail")
+ @WebLog(value = "邀请情况详请")
+ public ExpertInviteDetailVO inviteDetail(@PathVariable Long meetingId) {
+ return meetingManage.inviteDetail(meetingId);
+ }
+
+ @ApiOperation("会议基础信息修改")
+ @PostMapping("/basicInfo/modify")
+ @WebLog(value = "会议基础信息修改")
+ public void meetingBasicInfoModify(@Valid @RequestBody MeetingBasicInfoModifyReq po) {
+ meetingManage.meetingBasicInfoModify(po);
+ }
+
+ @ApiOperation("会议详情-抽取规则")
+ @GetMapping("/detail/inviteRule/{meetingId}")
+ @WebLog(value = "会议详情-抽取规则")
+ public InviteRuleDetailVO inviteRuleDetail(@PathVariable Long meetingId) {
+ return meetingManage.inviteRuleDetail(meetingId);
+ }
+
+ @ApiOperation("专家移除")
+ @PostMapping("/expertRemove")
+ @WebLog(value = "专家移除")
+ public void expertRemove(@RequestBody ExpertRemoveReq po) {
+ meetingManage.expertRemove(po);
+ }
+
+ @ApiOperation("专家替换")
+ @PostMapping("/expertReplace")
+ @WebLog(value = "专家替换")
+ public void expertReplace(@RequestBody ExpertRemoveReq po) {
+ meetingManage.expertReplace(po);
+
+ }
+
+ @ApiOperation("确认名单(下发会议通知)")
+ @GetMapping("/sendMeetingNotice/{meetingId}")
+ @WebLog(value = "确认名单(下发会议通知")
+ public void sendMeetingNotice(@PathVariable Long meetingId) {
+ meetingManage.sendMeetingNotice(meetingId);
+
+ }
+
+ @ApiOperation("停止抽取")
+ @GetMapping("/stopInvite/{meetingId}")
+ @WebLog(value = "停止抽取")
+ public void stopInvite(@PathVariable Long meetingId) {
+ meetingManage.stopRandomInvite(meetingId);
+
+ }
+
+ @ApiOperation("取消会议")
+ @PostMapping("/cancelMeeting")
+ @WebLog(value = "取消会议")
+ public void cancelMeeting(@Valid @RequestBody MeetingCancelReq po) {
+ meetingManage.cancelMeeting(po);
+ }
+
+ @ApiOperation("邀请函信息")
+ @GetMapping("/expertInvitationDetail")
+ @WebLog(value = "邀请函信息")
+ public ExpertInvitationDetailVO expertInvitationDetail(@RequestParam("meetingId") Long meetingId,
+ @RequestParam(required = false) Long expertId) {
+ return meetingManage.expertInvitationDetail(meetingId, expertId);
+ }
+
+ @ApiOperation("批量补充专家")
+ @PostMapping("batchAppointExperts")
+ @WebLog(value = "批量补充专家")
+ public void batchAppointExperts(@Valid @RequestBody BatchAppointExpertsReq po) {
+ meetingManage.batchAppointExperts(po);
+ }
+
+ @ApiOperation("确认参加")
+ @PostMapping("/confirmAttendByManager")
+ @WebLog(value = "确认参加")
+ public void confirmAttendByManager(@RequestBody ExpertRemoveReq po) {
+ meetingManage.confirmAttendByManager(po);
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/config/WebProperties.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/config/WebProperties.java
new file mode 100644
index 0000000..8729d6e
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/config/WebProperties.java
@@ -0,0 +1,36 @@
+package com.ningdatech.pmapi.meeting.entity.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ *
+ * SystemProperties
+ *
+ *
+ * @author WendyYang
+ * @since 14:39 2022/9/15
+ */
+@Data
+@Component
+public class WebProperties {
+
+ public static String webUrl;
+
+ public static String provincialUrl;
+
+ @Value("${web.url:}")
+ private void setWebUrl(String url) {
+ webUrl = url;
+ }
+
+ /**
+ * 省局项目管理调用跳转地址
+ */
+ @Value("${web.provincial:}")
+ private void setProvincial(String provincial) {
+ provincialUrl = provincial;
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/ExpertInviteAvoidRule.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/ExpertInviteAvoidRule.java
new file mode 100644
index 0000000..dd99ef2
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/ExpertInviteAvoidRule.java
@@ -0,0 +1,56 @@
+package com.ningdatech.pmapi.meeting.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;
+
+/**
+ *
+ * ExpertInviteAvoidRule
+ *
+ *
+ * @author WendyYang
+ * @since 2022-07-26
+ */
+@Data
+@TableName("meeting_expert_invite_avoid_rule")
+@ApiModel(value = "ExpertInviteAvoidRule对象")
+public class ExpertInviteAvoidRule implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty("主键")
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty("事务ID")
+ private Long meetingId;
+
+ @ApiModelProperty("回避专家ID")
+ private String expertIds;
+
+ @ApiModelProperty("回避单位名称")
+ private String companyIds;
+
+ @ApiModelProperty("回避本单位同事")
+ private Boolean avoidMates;
+
+ @ApiModelProperty("创建人ID")
+ private Long createBy;
+
+ @ApiModelProperty("创建时间")
+ private LocalDateTime createOn;
+
+ @ApiModelProperty("修改时间")
+ private LocalDateTime updateOn;
+
+ @ApiModelProperty("修改人ID")
+ private Long updateBy;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/ExpertInviteIgnoreTime.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/ExpertInviteIgnoreTime.java
new file mode 100644
index 0000000..a70a9f2
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/ExpertInviteIgnoreTime.java
@@ -0,0 +1,54 @@
+package com.ningdatech.pmapi.meeting.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;
+import java.time.LocalTime;
+
+/**
+ *
+ * 专家抽取免打扰时间设置
+ *
+ *
+ * @author WendyYang
+ * @since 2022-11-21
+ */
+@Data
+@TableName("expert_invite_ignore_time")
+@ApiModel(value = "ExpertInviteIgnoreTime对象", description = "专家抽取免打扰时间设置")
+public class ExpertInviteIgnoreTime implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty("主键")
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty("是否启用")
+ private Boolean enable;
+
+ @ApiModelProperty("开始时间")
+ private LocalTime startTime;
+
+ @ApiModelProperty("截止时间")
+ private LocalTime endTime;
+
+ @ApiModelProperty("创建人ID")
+ private Long createBy;
+
+ @ApiModelProperty("创建时间")
+ private LocalDateTime createOn;
+
+ @ApiModelProperty("修改人ID")
+ private Long updateBy;
+
+ @ApiModelProperty("修改时间")
+ private LocalDateTime updateOn;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/ExpertInviteRule.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/ExpertInviteRule.java
new file mode 100644
index 0000000..f317cc8
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/ExpertInviteRule.java
@@ -0,0 +1,55 @@
+package com.ningdatech.pmapi.meeting.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;
+
+/**
+ *
+ * ExpertInviteRule
+ *
+ *
+ * @author WendyYang
+ * @since 2022-07-26
+ */
+@Data
+@TableName("meeting_expert_invite_rule")
+@ApiModel(value = "ExpertInviteRule对象")
+public class ExpertInviteRule implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty("主键")
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ private Long meetingId;
+
+ @ApiModelProperty("抽取规则")
+ private String inviteRule;
+
+ @ApiModelProperty("创建人ID")
+ private Long createBy;
+
+ @ApiModelProperty("创建时间")
+ private LocalDateTime createOn;
+
+ @ApiModelProperty("修改时间")
+ private LocalDateTime updateOn;
+
+ @ApiModelProperty("修改人ID")
+ private Long updateBy;
+
+ @ApiModelProperty("抽取类型:1 自定义规则、2 指定邀请")
+ private Integer inviteType;
+
+ @ApiModelProperty("抽取数量")
+ private Integer inviteCount;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/Meeting.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/Meeting.java
new file mode 100644
index 0000000..d09e155
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/Meeting.java
@@ -0,0 +1,116 @@
+package com.ningdatech.pmapi.meeting.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+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-07-26
+ */
+@Data
+@TableName("meeting")
+@ApiModel(value = "Meeting对象", description = "会议")
+public class Meeting implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty("主键")
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty("事务名称")
+ private String name;
+
+ @ApiModelProperty("事务类型")
+ private String type;
+
+ @ApiModelProperty("开始时间")
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("结束时间")
+ private LocalDateTime endTime;
+
+ @ApiModelProperty("地区编码")
+ private String regionCode;
+
+ @ApiModelProperty("地区层级")
+ private Integer regionLevel;
+
+ @ApiModelProperty("地区详情")
+ private String regionDetail;
+
+ @ApiModelProperty("联系人")
+ private String connecter;
+
+ @ApiModelProperty("联系方式")
+ private String contact;
+
+ @ApiModelProperty("事务说明")
+ private String description;
+
+ @ApiModelProperty("附件")
+ private String attachment;
+
+ @ApiModelProperty("备注")
+ private String remark;
+
+ @ApiModelProperty("创建人ID")
+ @TableField(fill = FieldFill.INSERT)
+ private Long createBy;
+
+ @ApiModelProperty("创建时间")
+ @TableField(fill = FieldFill.INSERT)
+ private LocalDateTime createOn;
+
+ @ApiModelProperty("修改人ID")
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ private Long updateBy;
+
+ @ApiModelProperty("修改时间")
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ private LocalDateTime updateOn;
+
+ @ApiModelProperty("创建人")
+ private String author;
+
+ @ApiModelProperty("创建人地区编码")
+ private String authorRegionCode;
+
+ @ApiModelProperty("创建人地区层级")
+ private Integer authorRegionLevel;
+
+ private Integer status;
+
+ private String resultDescription;
+
+ private String resultAttachment;
+
+ @ApiModelProperty("是否下发会议通知")
+ private Boolean sendMeetingNotice;
+
+ @ApiModelProperty("是否停止随机邀请")
+ private Boolean stopRandomInvite;
+
+ @ApiModelProperty("是否进行了专家抽取")
+ private Boolean invited;
+
+ @ApiModelProperty("取消说明")
+ private String cancelRemark;
+
+ @ApiModelProperty("举办单位")
+ private String holdCompany;
+
+ public String getHoldCompanyBracket() {
+ return "(" + this.getHoldCompany() + ")";
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpert.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpert.java
new file mode 100644
index 0000000..ce7f9a1
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpert.java
@@ -0,0 +1,73 @@
+package com.ningdatech.pmapi.meeting.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.Builder;
+import lombok.Data;
+import lombok.experimental.Tolerate;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ * 事务专家表
+ *
+ *
+ * @author WendyYang
+ * @since 2022-07-27
+ */
+@Data
+@Builder
+@TableName("meeting_expert")
+@ApiModel(value = "MeetingExpert对象", description = "事务专家表")
+public class MeetingExpert implements Serializable {
+
+ @Tolerate
+ public MeetingExpert() {
+ }
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty("主键")
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty("事务ID")
+ private Long meetingId;
+
+ @ApiModelProperty("专家ID")
+ private Long expertId;
+
+ @ApiModelProperty("邀请规则ID")
+ private Long ruleId;
+
+ private String mobile;
+
+ @ApiModelProperty("当前状态")
+ private Integer status;
+
+ @ApiModelProperty("前一个状态")
+ private Integer preStatus;
+
+ private Long preId;
+
+ @ApiModelProperty("邀请类型")
+ private Integer inviteType;
+
+ private Long createBy;
+
+ private LocalDateTime createOn;
+
+ private Long updateBy;
+
+ private LocalDateTime updateOn;
+
+ private String submitKey;
+
+ private String expertName;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpertEvaluation.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpertEvaluation.java
new file mode 100644
index 0000000..c8462aa
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/domain/MeetingExpertEvaluation.java
@@ -0,0 +1,66 @@
+package com.ningdatech.pmapi.meeting.entity.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ningdatech.pmapi.sys.model.entity.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ *
+ * 专家评价表
+ *
+ *
+ * @author WendyYang
+ * @since 2022-07-25
+ */
+@Data
+@TableName("meeting_expert_evaluation")
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "MeetingExpertEvaluation对象", description = "专家评价表")
+public class MeetingExpertEvaluation extends BaseEntity {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty("主键")
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ @ApiModelProperty("专家事务关联ID")
+ private Long expertMeetingId;
+
+ @ApiModelProperty("事务ID")
+ private Long meetingId;
+
+ @ApiModelProperty("专家ID")
+ private Long expertId;
+
+ @TableField(value = "is_attended")
+ @ApiModelProperty("是否参加")
+ private Boolean attended;
+
+ @TableField(value = "is_in_time")
+ @ApiModelProperty("是否准时参加")
+ private Boolean inTime;
+
+ @TableField(value = "is_violated")
+ @ApiModelProperty("是否违规")
+ private Boolean violated;
+
+ @ApiModelProperty("参与程度")
+ private Integer initiative;
+
+ @ApiModelProperty("建设性建议")
+ private String advice;
+
+ @ApiModelProperty("评审结果情况")
+ private String evaluateResult;
+
+ @ApiModelProperty("违规情况")
+ private String violation;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/AbstractInviteRule.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/AbstractInviteRule.java
new file mode 100644
index 0000000..bd965b5
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/AbstractInviteRule.java
@@ -0,0 +1,39 @@
+package com.ningdatech.pmapi.meeting.entity.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ *
+ * AbstractExpertExtractRule
+ *
+ *
+ * @author WendyYang
+ * @since 10:10 2022/7/26
+ */
+@Data
+@ApiModel("抽取规则")
+public abstract class AbstractInviteRule {
+
+ @ApiModelProperty("id")
+ private Long id;
+
+ @ApiModelProperty("专家抽取数量")
+ @NotNull(message = "专家抽取数量不能为空", groups = {RuleSave.class})
+ private Integer count;
+
+ @ApiModelProperty("抽取类型:1 随机抽取、2 指定抽取")
+ @NotNull(message = "抽取类型不能为空", groups = {RuleSave.class, CountCheck.class})
+ private Integer inviteType;
+
+ public interface RuleSave {
+ }
+
+ public interface CountCheck {
+ }
+
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/AppointInviteRuleDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/AppointInviteRuleDTO.java
new file mode 100644
index 0000000..f322835
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/AppointInviteRuleDTO.java
@@ -0,0 +1,34 @@
+package com.ningdatech.pmapi.meeting.entity.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ *
+ * AppointExtractRuleDto
+ *
+ *
+ * @author WendyYang
+ * @since 10:19 2022/7/26
+ */
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@ApiModel("指定抽取规则")
+public class AppointInviteRuleDTO extends AbstractInviteRule {
+
+ @NotEmpty(message = "邀请说明不能为空", groups = {RuleSave.class})
+ @ApiModelProperty("邀请说明")
+ private String inviteDesc;
+
+ @NotEmpty(message = "专家ID不能为空", groups = {RuleSave.class, CountCheck.class})
+ @ApiModelProperty("专家ID")
+ private List expertIds;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/AvoidInfoDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/AvoidInfoDTO.java
new file mode 100644
index 0000000..97c4d5e
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/AvoidInfoDTO.java
@@ -0,0 +1,60 @@
+package com.ningdatech.pmapi.meeting.entity.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ *
+ * AvoidInfoDto
+ *
+ *
+ * @author WendyYang
+ * @since 10:22 2022/7/26
+ */
+@Data
+@ApiModel("回避信息")
+public class AvoidInfoDTO {
+
+ @ApiModelProperty("回避单位")
+ @NotEmpty(message = "回避单位不能为空", groups = {AbstractInviteRule.RuleSave.class})
+ private List companyIds;
+
+ @ApiModelProperty("是否回避同单位其他专家")
+ @NotNull(message = "是否回避同单位其他专家不能为空")
+ private Boolean avoidMates;
+
+ @ApiModelProperty("回避专家ID")
+ private List expertIds;
+
+ /**
+ * 返回一个默认值,仅在前端未传值时使用
+ *
+ * @return /
+ */
+ public static AvoidInfoDTO defVal() {
+ AvoidInfoDTO val = new AvoidInfoDTO();
+ val.setAvoidMates(false);
+ val.setCompanyIds(Collections.emptyList());
+ val.setExpertIds(Collections.emptyList());
+ return val;
+ }
+
+ public void initDefVal() {
+ if (this.avoidMates == null) {
+ this.setAvoidMates(false);
+ }
+ if (this.companyIds == null) {
+ this.setCompanyIds(Collections.emptyList());
+ }
+ if (this.expertIds == null) {
+ this.setExpertIds(Collections.emptyList());
+ }
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/CountConfirmByMeetingIdDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/CountConfirmByMeetingIdDTO.java
new file mode 100644
index 0000000..af9ab8a
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/CountConfirmByMeetingIdDTO.java
@@ -0,0 +1,31 @@
+package com.ningdatech.pmapi.meeting.entity.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.experimental.Tolerate;
+
+/**
+ *
+ * CountConfirmByMeetingIdDto
+ *
+ *
+ * @author WendyYang
+ * @since 14:21 2022/8/8
+ */
+@Data
+@Builder
+@AllArgsConstructor
+public class CountConfirmByMeetingIdDTO {
+
+ @Tolerate
+ public CountConfirmByMeetingIdDTO() {
+ }
+
+ private Long meetingId;
+
+ private Integer total;
+
+ private Integer confirmed;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertChooseDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertChooseDTO.java
new file mode 100644
index 0000000..e76145e
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertChooseDTO.java
@@ -0,0 +1,25 @@
+package com.ningdatech.pmapi.meeting.entity.dto;
+
+import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ *
+ * ExpertChooseDto
+ *
+ *
+ * @author WendyYang
+ * @since 00:44 2022/7/27
+ */
+@Data
+@AllArgsConstructor
+public class ExpertChooseDTO {
+
+ private List experts;
+
+ private Integer total;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertDictChooseDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertDictChooseDTO.java
new file mode 100644
index 0000000..053c533
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertDictChooseDTO.java
@@ -0,0 +1,25 @@
+package com.ningdatech.pmapi.meeting.entity.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ *
+ * ExpertDictChooseDTO
+ *
+ *
+ * @author WendyYang
+ * @since 15:49 2022/8/9
+ */
+@Data
+public class ExpertDictChooseDTO {
+
+ @ApiModelProperty("专家字典类型")
+ private String expertDict;
+
+ @ApiModelProperty("字典编码")
+ private List dictCodes;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertTagChooseDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertTagChooseDTO.java
new file mode 100644
index 0000000..6f10cf0
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/ExpertTagChooseDTO.java
@@ -0,0 +1,25 @@
+package com.ningdatech.pmapi.meeting.entity.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ *
+ * ExpertTagChooseDTO
+ *
+ *
+ * @author WendyYang
+ * @since 19:45 2022/7/26
+ */
+@Data
+public class ExpertTagChooseDTO {
+
+ @ApiModelProperty("专家标签")
+ private String expertTag;
+
+ @ApiModelProperty("标签编码")
+ private List tagCodes;
+
+}
\ No newline at end of file
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingAndAttendStatusDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingAndAttendStatusDTO.java
new file mode 100644
index 0000000..9991234
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingAndAttendStatusDTO.java
@@ -0,0 +1,22 @@
+package com.ningdatech.pmapi.meeting.entity.dto;
+
+import lombok.Data;
+
+/**
+ *
+ * MeetingAndAttendStatusDto
+ *
+ *
+ * @author WendyYang
+ * @since 22:48 2022/8/22
+ */
+@Data
+public class MeetingAndAttendStatusDTO {
+
+ private Long meetingId;
+
+ private Integer status;
+
+ private Boolean attended;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingBasicDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingBasicDTO.java
new file mode 100644
index 0000000..8107ea8
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/MeetingBasicDTO.java
@@ -0,0 +1,80 @@
+package com.ningdatech.pmapi.meeting.entity.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ *
+ * MeetingBasicDto
+ *
+ *
+ * @author WendyYang
+ * @since 09:35 2022/7/26
+ */
+@Data
+@ApiModel("会议基本信息")
+public class MeetingBasicDTO {
+
+ @NotEmpty(message = "抽取单位不能为空")
+ @ApiModelProperty("抽取单位")
+ private String inviterCompany;
+
+ @NotEmpty(message = "事务名称不能为空")
+ @ApiModelProperty("事务名称")
+ private String name;
+
+ @NotEmpty(message = "事务类型不能为空")
+ @ApiModelProperty("事务类型")
+ private String type;
+
+ @NotNull(message = "开始时间不能为空")
+ @ApiModelProperty("开始时间")
+ private LocalDateTime startTime;
+
+ @NotNull(message = "结束时间不能为空")
+ @ApiModelProperty("结束时间")
+ private LocalDateTime endTime;
+
+ @NotEmpty(message = "地区编码不能为空")
+ @ApiModelProperty("地区编码")
+ private String regionCode;
+
+ @NotNull(message = "地区编码层级不能为空")
+ @ApiModelProperty("地区编码层级")
+ private Integer regionLevel;
+
+ @NotEmpty(message = "地址详情不能为空")
+ @ApiModelProperty("地址详情")
+ private String regionDetail;
+
+ @NotEmpty(message = "联系人不能为空")
+ @ApiModelProperty("联系人")
+ private String connecter;
+
+ @NotEmpty(message = "联系方式不能为空")
+ @ApiModelProperty("联系方式")
+ private String contact;
+
+ @NotEmpty(message = "事务说明不能为空")
+ @ApiModelProperty("事务说明")
+ private String description;
+
+ @ApiModelProperty("附件ID")
+ private List attachmentIds;
+
+ @ApiModelProperty("备注")
+ private String remark;
+
+ @ApiModelProperty("创建人")
+ private String author;
+
+ @ApiModelProperty("创建时间")
+ private LocalDateTime createOn;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/RandomInviteRuleDTO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/RandomInviteRuleDTO.java
new file mode 100644
index 0000000..a7c1ee5
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/dto/RandomInviteRuleDTO.java
@@ -0,0 +1,46 @@
+package com.ningdatech.pmapi.meeting.entity.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ *
+ * RandomExtractRuleDto
+ *
+ *
+ * @author WendyYang
+ * @since 10:18 2022/7/26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel("随机抽取规则")
+public class RandomInviteRuleDTO extends AbstractInviteRule {
+
+ @ApiModelProperty("专家字典信息")
+ private List expertDicts;
+
+ @ApiModelProperty("履职意向地编码")
+ private String intentionRegionCode;
+
+ @ApiModelProperty("履职意向地层级")
+ private Integer intentionRegionLevel;
+
+ @ApiModelProperty("专家层级编码")
+ private String expertRegionCode;
+
+ @ApiModelProperty("专家层级级别")
+ private Integer expertRegionLevel;
+
+ @ApiModelProperty("专家标签")
+ private List expertTags;
+
+ @ApiModelProperty("专家最长响应时间")
+ @NotNull(message = "专家最长响应时间不能为空", groups = {RuleSave.class})
+ private Integer waitForCallbackMinutes;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertAttendStatus.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertAttendStatus.java
new file mode 100644
index 0000000..095af8c
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertAttendStatus.java
@@ -0,0 +1,45 @@
+package com.ningdatech.pmapi.meeting.entity.enumeration;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ *
+ * ExpertAttendStatus
+ *
+ *
+ * @author WendyYang
+ * @since 09:23 2022/8/9
+ */
+@Getter
+public enum ExpertAttendStatus {
+
+ NOTICING("通知中", 0),
+ NOT_ANSWERED("未应答", 1),
+ REPLACED("已替换", 2),
+ AGREED("同意参加", 3),
+ REFUSED("拒绝参加", 4),
+ CANCELED("已移除", 5),
+ ON_LEAVE("已请假", 6);
+
+ private final Integer code;
+ private final String desc;
+
+ ExpertAttendStatus(String desc, Integer code) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public boolean eq(Integer code) {
+ return this.getCode().equals(code);
+ }
+
+ public static ExpertAttendStatus getByCode(Integer code) {
+ return Arrays.stream(values())
+ .filter(w -> w.eq(code))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException("无效的邀请状态"));
+ }
+
+}
\ No newline at end of file
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertInviteType.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertInviteType.java
new file mode 100644
index 0000000..fde33e9
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/ExpertInviteType.java
@@ -0,0 +1,39 @@
+package com.ningdatech.pmapi.meeting.entity.enumeration;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ *
+ * ExpertExtractRuleType
+ *
+ *
+ * @author WendyYang
+ * @since 10:11 2022/7/26
+ */
+@Getter
+public enum ExpertInviteType {
+
+ /**
+ * 专家抽取类型
+ */
+ RANDOM(1, "随机邀请"),
+ APPOINT(2, "指定邀请");
+
+ private final Integer code;
+ private final String name;
+
+ ExpertInviteType(Integer code, String name) {
+ this.code = code;
+ this.name = name;
+ }
+
+ public static ExpertInviteType 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/meeting/entity/enumeration/MeetingDateTermType.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/MeetingDateTermType.java
new file mode 100644
index 0000000..f846be9
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/MeetingDateTermType.java
@@ -0,0 +1,36 @@
+package com.ningdatech.pmapi.meeting.entity.enumeration;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ *
+ * MeetingDateTermType-会议日期类型
+ *
+ *
+ * @author WendyYang
+ * @since 09:54 2022/8/15
+ */
+@Getter
+public enum MeetingDateTermType {
+
+ ONE_DAY(1, "一天"),
+ MORE_THAN_ONE(2, "两天及以上");
+
+ private final Integer code;
+ private final String name;
+
+ MeetingDateTermType(Integer code, String name) {
+ this.code = code;
+ this.name = name;
+ }
+
+ public static MeetingDateTermType 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/meeting/entity/enumeration/MeetingStatus.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/MeetingStatus.java
new file mode 100644
index 0000000..e90255f
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/MeetingStatus.java
@@ -0,0 +1,73 @@
+package com.ningdatech.pmapi.meeting.entity.enumeration;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ *
+ * MeetingStatus
+ *
+ *
+ * @author WendyYang
+ * @since 11:14 2022/8/8
+ */
+public class MeetingStatus {
+
+ /**
+ * 管理员事务列表:事务状态
+ */
+ @Getter
+ public enum Manager {
+
+ UNCOMPLETED("未完成", 1),
+ COMPLETED("已完成", 2),
+ CANCELED("已取消", 3);
+
+ private final String desc;
+ private final Integer code;
+
+ Manager(String desc, Integer code) {
+ this.desc = desc;
+ this.code = code;
+ }
+
+ public boolean eq(Integer code) {
+ return this.getCode().equals(code);
+ }
+
+ public static Manager getByCode(Integer code) {
+ return Arrays.stream(values())
+ .filter(w -> w.getCode().equals(code))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException("状态编码"));
+ }
+
+ }
+
+ @Getter
+ public enum Expert {
+
+ TO_ATTEND("待参加", 1),
+ ATTENDED("已参加", 2),
+ ON_LEAVE("已请假", 3),
+ UN_ATTEND("缺席", 4);
+
+ private final String desc;
+ private final Integer code;
+
+ Expert(String desc, Integer code) {
+ this.desc = desc;
+ this.code = code;
+ }
+
+ public static Expert 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/meeting/entity/enumeration/MeetingStatusByDashboard.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/MeetingStatusByDashboard.java
new file mode 100644
index 0000000..1aeac9e
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/enumeration/MeetingStatusByDashboard.java
@@ -0,0 +1,30 @@
+package com.ningdatech.pmapi.meeting.entity.enumeration;
+
+/**
+ *
+ * MeetingStatusByDashboard
+ *
+ *
+ * @author WendyYang
+ * @since 14:02 2022/8/30
+ */
+public enum MeetingStatusByDashboard {
+
+ /**
+ * 已完成
+ */
+ COMPLETED,
+ /**
+ * 已取消
+ */
+ CANCELED,
+ /**
+ * 待召开
+ */
+ TO_BE_HELD,
+ /**
+ * 已召开
+ */
+ HELD
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/BatchAppointExpertsReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/BatchAppointExpertsReq.java
new file mode 100644
index 0000000..155c4cb
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/BatchAppointExpertsReq.java
@@ -0,0 +1,31 @@
+package com.ningdatech.pmapi.meeting.entity.req;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ *
+ * BatchAppointExpertsPo
+ *
+ *
+ * @author WendyYang
+ * @since 15:49 2022/8/26
+ */
+@Data
+@ApiModel("补充专家参数实体")
+public class BatchAppointExpertsReq {
+
+ @NotEmpty(message = "专家ID不能为空")
+ @ApiModelProperty("专家ID")
+ private List expertIds;
+
+ @NotNull(message = "会议ID不能为空")
+ @ApiModelProperty("会议ID")
+ private Long meetingId;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertEvaluationReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertEvaluationReq.java
new file mode 100644
index 0000000..c882d33
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertEvaluationReq.java
@@ -0,0 +1,49 @@
+package com.ningdatech.pmapi.meeting.entity.req;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ *
+ * ExpertEvaluationPo
+ *
+ *
+ * @author WendyYang
+ * @since 15:30 2022/7/25
+ */
+@Data
+@ApiModel("专家评价实体")
+public class ExpertEvaluationReq {
+
+ @ApiModelProperty("专家事务关联ID")
+ @NotNull(message = "专家事务关联ID不能为空")
+ private Long expertMeetingId;
+
+ @ApiModelProperty("是否参加")
+ @NotNull(message = "是否参加不能为空")
+ private Boolean attended;
+
+ @ApiModelProperty("是否准时参加")
+ private Boolean inTime;
+
+ @ApiModelProperty("是否违规")
+ @NotNull(message = "是否违规不能为空")
+ private Boolean violated;
+
+ @ApiModelProperty("违规情况")
+ private String violation;
+
+ @ApiModelProperty("参与程度:1 很积极...5 很消极")
+ @NotNull(message = "参与程度不能为空")
+ private Integer initiative;
+
+ @ApiModelProperty("建设性的建议")
+ private String advice;
+
+ @ApiModelProperty("评审结果")
+ private String evaluateResult;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertInviteCreateReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertInviteCreateReq.java
new file mode 100644
index 0000000..220654e
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertInviteCreateReq.java
@@ -0,0 +1,43 @@
+package com.ningdatech.pmapi.meeting.entity.req;
+
+import com.ningdatech.pmapi.meeting.entity.dto.AbstractInviteRule;
+import com.ningdatech.pmapi.meeting.entity.dto.AppointInviteRuleDTO;
+import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO;
+import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ *
+ * MeetingCreatePo
+ *
+ *
+ * @author WendyYang
+ * @since 10:32 2022/7/26
+ */
+@Data
+@ApiModel("专家抽取新家实体")
+public class ExpertInviteCreateReq {
+
+ @NotNull(message = "会议ID不能为空", groups = {AbstractInviteRule.RuleSave.class, AbstractInviteRule.CountCheck.class})
+ @ApiModelProperty("会议ID")
+ private Long meetingId;
+
+ @Valid
+ @ApiModelProperty("回避信息")
+ private AvoidInfoDTO avoidInfo;
+
+ @Valid
+ @ApiModelProperty("随机抽取规则")
+ private List randomRules;
+
+ @Valid
+ @ApiModelProperty("指定抽取规则")
+ private AppointInviteRuleDTO appointRule;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertInviteIgnoreTimeModifyReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertInviteIgnoreTimeModifyReq.java
new file mode 100644
index 0000000..8fa5833
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertInviteIgnoreTimeModifyReq.java
@@ -0,0 +1,36 @@
+package com.ningdatech.pmapi.meeting.entity.req;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalTime;
+
+/**
+ *
+ * 专家抽取免打扰时间设置
+ *
+ *
+ * @author WendyYang
+ * @since 2022-11-21
+ */
+@Data
+@ApiModel("专家抽取免打扰时间设置")
+public class ExpertInviteIgnoreTimeModifyReq {
+
+ @ApiModelProperty("主键")
+ private Long id;
+
+ @ApiModelProperty("是否启用:true 是、false 否")
+ private Boolean enable;
+
+ @ApiModelProperty("开始时间(格式:HH:mm)")
+ @JSONField(format = "HH:mm")
+ private LocalTime startTime;
+
+ @ApiModelProperty("截止时间(格式:HH:mm)")
+ @JSONField(format = "HH:mm")
+ private LocalTime endTime;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertRemoveReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertRemoveReq.java
new file mode 100644
index 0000000..ad08f87
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/ExpertRemoveReq.java
@@ -0,0 +1,28 @@
+package com.ningdatech.pmapi.meeting.entity.req;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ *
+ * ExpertRemovePo
+ *
+ *
+ * @author WendyYang
+ * @since 08:59 2022/8/10
+ */
+@Data
+@ApiModel("专家(移除/替换)实体")
+public class ExpertRemoveReq {
+
+ @ApiModelProperty("会议ID")
+ private Long meetingId;
+
+ @ApiModelProperty("专家ID")
+ private Long expertId;
+
+ @ApiModelProperty("专家会议ID")
+ private Long expertMeetingId;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingBasicInfoModifyReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingBasicInfoModifyReq.java
new file mode 100644
index 0000000..274d3ea
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingBasicInfoModifyReq.java
@@ -0,0 +1,82 @@
+package com.ningdatech.pmapi.meeting.entity.req;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ *
+ * MeetingBasicInfoModifyPo
+ *
+ *
+ * @author WendyYang
+ * @since 11:15 2022/8/17
+ */
+@Data
+public class MeetingBasicInfoModifyReq {
+
+ @NotEmpty(message = "抽取单位不能为空")
+ @ApiModelProperty("抽取单位")
+ private String inviterCompany;
+
+ @ApiModelProperty("会议ID")
+ @NotNull(message = "会议ID不能为空")
+ private Long id;
+
+ @NotEmpty(message = "会议名称不能为空")
+ @ApiModelProperty("会议名称")
+ private String name;
+
+ @NotEmpty(message = "会议类型不能为空")
+ @ApiModelProperty("会议类型")
+ private String type;
+
+ @NotNull(message = "开始时间不能为空")
+ @ApiModelProperty("开始时间")
+ private LocalDateTime startTime;
+
+ @NotNull(message = "结束时间不能为空")
+ @ApiModelProperty("结束时间")
+ private LocalDateTime endTime;
+
+ @NotEmpty(message = "地区编码不能为空")
+ @ApiModelProperty("地区编码")
+ private String regionCode;
+
+ @NotNull(message = "地区编码层级不能为空")
+ @ApiModelProperty("地区编码层级")
+ private Integer regionLevel;
+
+ @NotEmpty(message = "地址详情不能为空")
+ @ApiModelProperty("地址详情")
+ private String regionDetail;
+
+ @NotEmpty(message = "联系人不能为空")
+ @ApiModelProperty("联系人")
+ private String connecter;
+
+ @NotEmpty(message = "联系方式不能为空")
+ @ApiModelProperty("联系方式")
+ private String contact;
+
+ @NotEmpty(message = "会议说明不能为空")
+ @ApiModelProperty("会议说明")
+ private String description;
+
+ @ApiModelProperty("附件ID")
+ private List attachmentIds;
+
+ @ApiModelProperty("备注")
+ private String remark;
+
+ @ApiModelProperty("创建人")
+ private String author;
+
+ @ApiModelProperty("创建时间")
+ private LocalDateTime createOn;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingCalenderReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingCalenderReq.java
new file mode 100644
index 0000000..03e1f68
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingCalenderReq.java
@@ -0,0 +1,28 @@
+package com.ningdatech.pmapi.meeting.entity.req;
+
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDate;
+
+/**
+ *
+ * MeetingCalenderPo
+ *
+ *
+ * @author WendyYang
+ * @since 22:38 2022/8/24
+ */
+@Data
+public class MeetingCalenderReq {
+
+ @NotNull(message = "开始日期不能为空")
+ @DateTimeFormat(pattern = "yyyy-MM-dd")
+ private LocalDate startDate;
+
+ @NotNull(message = "结束日期不能为空")
+ @DateTimeFormat(pattern = "yyyy-MM-dd")
+ private LocalDate endDate;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingCancelReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingCancelReq.java
new file mode 100644
index 0000000..47ebb97
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingCancelReq.java
@@ -0,0 +1,30 @@
+package com.ningdatech.pmapi.meeting.entity.req;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ *
+ * MeetingCancelPo
+ *
+ *
+ * @author WendyYang
+ * @since 10:43 2022/8/26
+ */
+@Data
+@ApiModel("会议取消实体")
+public class MeetingCancelReq {
+
+ @NotNull(message = "会议ID不能为空")
+ @ApiModelProperty("会议ID")
+ private Long meetingId;
+
+ @NotBlank(message = "取消说明不能为空")
+ @ApiModelProperty("取消说明")
+ private String cancelRemark;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingListByExpertReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingListByExpertReq.java
new file mode 100644
index 0000000..ce2003a
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingListByExpertReq.java
@@ -0,0 +1,21 @@
+package com.ningdatech.pmapi.meeting.entity.req;
+
+import com.ningdatech.basic.model.PagePo;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ *
+ * MeetingListByExpertPo
+ *
+ *
+ * @author WendyYang
+ * @since 17:02 2022/8/23
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class MeetingListByExpertReq extends PagePo {
+
+ private Long expertId;
+
+}
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
new file mode 100644
index 0000000..b472592
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingListReq.java
@@ -0,0 +1,49 @@
+package com.ningdatech.pmapi.meeting.entity.req;
+
+import com.ningdatech.basic.model.PagePo;
+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;
+
+/**
+ *
+ * MeetingListByManagerPo
+ *
+ *
+ * @author WendyYang
+ * @since 11:07 2022/8/8
+ */
+@Data
+@ApiModel("专家抽取员事务列表请求参数")
+@EqualsAndHashCode(callSuper = true)
+public class MeetingListReq extends PagePo {
+
+ @ApiModelProperty("事务名称")
+ private String name;
+
+ @ApiModelProperty("事务开始时间")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("事务结束时间")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime endTime;
+
+ @ApiModelProperty("地点")
+ private String address;
+
+ @ApiModelProperty("事务状态:1 未完成、2 已完成、3 已取消\n" +
+ "专家参与状态:1 待参加、2 已参加、3 已请假")
+ private Integer status;
+
+ @ApiModelProperty("事务类型")
+ private String type;
+
+ @ApiModelProperty("专家ID")
+ private Long expertId;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingResultReq.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingResultReq.java
new file mode 100644
index 0000000..ee600c7
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/req/MeetingResultReq.java
@@ -0,0 +1,34 @@
+package com.ningdatech.pmapi.meeting.entity.req;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ *
+ * MeetingResultPo
+ *
+ *
+ * @author WendyYang
+ * @since 21:20 2022/8/8
+ */
+@Data
+@ApiModel("会议结果上传实体")
+public class MeetingResultReq {
+
+ @NotNull(message = "事务ID不能为空")
+ @ApiModelProperty("事务ID")
+ private Long meetingId;
+
+ @NotBlank(message = "会议结果说明不能为空")
+ @ApiModelProperty("会议结果说明")
+ private String resultDescription;
+
+ @ApiModelProperty("附件ID")
+ private List attachments;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertAttendSummaryVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertAttendSummaryVO.java
new file mode 100644
index 0000000..d3323df
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertAttendSummaryVO.java
@@ -0,0 +1,25 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ *
+ * ExpertAttendSummaryVo
+ *
+ *
+ * @author WendyYang
+ * @since 11:18 2022/8/28
+ */
+@Data
+public class ExpertAttendSummaryVO {
+
+ private transient Long expertId;
+
+ @ApiModelProperty("专家姓名")
+ private String expertName;
+
+ @ApiModelProperty("专家出席次数")
+ private Integer attendCount;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertBasicInfoVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertBasicInfoVO.java
new file mode 100644
index 0000000..aecb8e9
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertBasicInfoVO.java
@@ -0,0 +1,48 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import com.ningdatech.pmapi.sys.model.dto.RegionDTO;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Builder;
+import lombok.Data;
+import lombok.experimental.Tolerate;
+
+import java.util.List;
+
+/**
+ *
+ * ExpertBasicInfoVo
+ *
+ *
+ * @author WendyYang
+ * @since 15:58 2022/8/8
+ */
+@Data
+@Builder
+public class ExpertBasicInfoVO {
+
+ @Tolerate
+ public ExpertBasicInfoVO() {
+ }
+
+ @ApiModelProperty("专家ID")
+ private Long expertId;
+
+ @ApiModelProperty("专家姓名")
+ private String name;
+
+ @ApiModelProperty("专家层级")
+ private List regions;
+
+ @ApiModelProperty("职称级别")
+ private String jobLevel;
+
+ @ApiModelProperty("单位属性")
+ private String companyType;
+
+ @ApiModelProperty("工作单位")
+ private String company;
+
+ @ApiModelProperty("联系方式")
+ private String contact;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertCountOnChangeVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertCountOnChangeVO.java
new file mode 100644
index 0000000..6646d75
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertCountOnChangeVO.java
@@ -0,0 +1,38 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ *
+ * ExpertCountOnChangeVo
+ *
+ *
+ * @author WendyYang
+ * @since 10:02 2022/8/8
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ApiModel("专家抽取数量校验实体")
+public class ExpertCountOnChangeVO {
+
+ @ApiModelProperty("每个随机规则对应的可抽取数量")
+ private List countList;
+
+ @ApiModelProperty("参数是否通过校验:true 是、false 否")
+ private Boolean status;
+
+ @ApiModelProperty("错误提醒")
+ private String message;
+
+ public void addCountList(Integer count) {
+ this.countList.add(count);
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertEvaluationListVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertEvaluationListVO.java
new file mode 100644
index 0000000..cf0113c
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertEvaluationListVO.java
@@ -0,0 +1,25 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ *
+ * ExpertEvaluationListVo
+ *
+ *
+ * @author WendyYang
+ * @since 16:03 2022/8/8
+ */
+@Data
+@ApiModel("专家评价列表")
+public class ExpertEvaluationListVO {
+
+ @ApiModelProperty("专家评价ID")
+ private Long evaluationId;
+
+ @ApiModelProperty("专家信息")
+ private ExpertBasicInfoVO expert;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertEvaluationToDoListItemVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertEvaluationToDoListItemVO.java
new file mode 100644
index 0000000..f7e1b48
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertEvaluationToDoListItemVO.java
@@ -0,0 +1,38 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
+
+/**
+ *
+ * ExpertEvaluationToDoListItemVo
+ *
+ *
+ * @author WendyYang
+ * @since 13:58 2022/8/29
+ */
+@Data
+@ApiModel("专家评价待办列表")
+@EqualsAndHashCode(callSuper = true)
+public class ExpertEvaluationToDoListItemVO extends ExpertBasicInfoVO {
+
+ @ApiModelProperty("专家会议ID")
+ private Long expertMeetingId;
+
+ @ApiModelProperty("会议ID")
+ private Long meetingId;
+
+ @ApiModelProperty("会议名称")
+ private String meetingName;
+
+ @ApiModelProperty("会议开始时间")
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("会议结束时间")
+ private LocalDateTime endTime;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertInvitationDetailVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertInvitationDetailVO.java
new file mode 100644
index 0000000..35c6b62
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertInvitationDetailVO.java
@@ -0,0 +1,60 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.ningdatech.pmapi.sys.model.dto.RegionDTO;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Builder;
+import lombok.Data;
+import lombok.experimental.Tolerate;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ *
+ * ExpertInvitationDetailVo
+ *
+ *
+ * @author WendyYang
+ * @since 13:51 2022/8/27
+ */
+@Data
+@Builder
+public class ExpertInvitationDetailVO {
+
+ @Tolerate
+ public ExpertInvitationDetailVO() {
+ }
+
+ @ApiModelProperty("专家确认时间")
+ private LocalDateTime inviteTime;
+
+ @ApiModelProperty("会议举办单位")
+ private String holdCompany;
+
+ @ApiModelProperty("会议开始时间")
+ @JSONField(format = "yyyy-MM-dd HH:mm")
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("会议结束时间")
+ @JSONField(format = "yyyy-MM-dd HH:mm")
+ private LocalDateTime endTime;
+
+ @ApiModelProperty("会议名称")
+ private String meetingName;
+
+ @ApiModelProperty("举办地址详情")
+ private String regionDetail;
+
+ private List regions;
+
+ @ApiModelProperty("联系方式")
+ private String contact;
+
+ @ApiModelProperty("联系人")
+ private String connecter;
+
+ @ApiModelProperty("专家名称")
+ private String expertName;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertInviteDetailVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertInviteDetailVO.java
new file mode 100644
index 0000000..672dfcc
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertInviteDetailVO.java
@@ -0,0 +1,95 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * ExpertInviteDetailVo
+ *
+ *
+ * @author WendyYang
+ * @since 08:58 2022/8/9
+ */
+@Data
+@ApiModel("专家邀请情况实体")
+public class ExpertInviteDetailVO {
+
+ @Data
+ @EqualsAndHashCode(callSuper = true)
+ @ApiModel("最终参与名单实体")
+ public static class ExpertAttendListItemVO extends ExpertBasicInfoVO {
+
+ private Long meetingId;
+
+ private Long expertMeetingId;
+
+ @ApiModelProperty("邀请方式")
+ private String inviteType;
+
+ }
+
+ @Data
+ @EqualsAndHashCode(callSuper = true)
+ @ApiModel("随机邀请名单实体")
+ public static class RandomInviteListItemVO extends ExpertBasicInfoVO {
+
+ @ApiModelProperty("会议ID")
+ private Long meetingId;
+
+ @ApiModelProperty("专家会议ID")
+ private Long expertMeetingId;
+
+ @ApiModelProperty("电话通知状态")
+ private String noticeStatus;
+
+ @ApiModelProperty("邀请结果")
+ private String confirmResult;
+
+ @ApiModelProperty("邀请状态")
+ private Integer status;
+
+ }
+
+ @ApiModelProperty("参与数量总计")
+ private Integer attendTotal = 0;
+
+ @ApiModelProperty("随机邀请参与数量")
+ private Integer randomAttend = 0;
+
+ @ApiModelProperty("指定邀请参与数量")
+ private Integer appointAttend = 0;
+
+ @ApiModelProperty("是否已停止邀请")
+ private Boolean hasStopInvite;
+
+ @ApiModelProperty("是否已下发通知")
+ private Boolean hasSendNotice;
+
+ @ApiModelProperty("最终参与名单")
+ private List attendList = new ArrayList<>();
+
+ @ApiModelProperty("随机邀请名单")
+ private List randomInviteList = new ArrayList<>();
+
+ @ApiModelProperty("指定邀请名单")
+ private List appointInviteList = new ArrayList<>();
+
+ public void addAttendList(ExpertAttendListItemVO attend) {
+ this.attendList.add(attend);
+ }
+
+ public void addRandomInviteList(RandomInviteListItemVO randomInvite) {
+ this.randomInviteList.add(randomInvite);
+ }
+
+ public void addAppointInviteList(RandomInviteListItemVO appointInvite) {
+ this.appointInviteList.add(appointInvite);
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertInviteIgnoreTimeListVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertInviteIgnoreTimeListVO.java
new file mode 100644
index 0000000..606f133
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertInviteIgnoreTimeListVO.java
@@ -0,0 +1,43 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+/**
+ *
+ * 专家抽取免打扰时间设置
+ *
+ *
+ * @author WendyYang
+ * @since 2022-11-21
+ */
+@Data
+@ApiModel("专家抽取免打扰时间设置")
+public class ExpertInviteIgnoreTimeListVO {
+
+ @ApiModelProperty("主键")
+ private Long id;
+
+ @ApiModelProperty("是否启用:true 是、false 否")
+ private Boolean enable;
+
+ @ApiModelProperty("开始时间")
+ @JSONField(format = "HH:mm")
+ private LocalTime startTime;
+
+ @ApiModelProperty("截止时间")
+ @JSONField(format = "HH:mm")
+ private LocalTime endTime;
+
+ @ApiModelProperty("创建时间")
+ private LocalDateTime createOn;
+
+ @ApiModelProperty("修改时间")
+ private LocalDateTime updateOn;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertListItemFoEvaluationVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertListItemFoEvaluationVO.java
new file mode 100644
index 0000000..f2bcfed
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertListItemFoEvaluationVO.java
@@ -0,0 +1,30 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ *
+ * MeetingExpertListItemFoEvaluationVo
+ *
+ *
+ * @author WendyYang
+ * @since 10:06 2022/8/24
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel("专家评价专家列表视图实体")
+public class ExpertListItemFoEvaluationVO extends ExpertBasicInfoVO {
+
+ @ApiModelProperty("是否已评价:true 已评价、false 未评价")
+ private boolean evaluated;
+
+ @ApiModelProperty("评价ID")
+ private Long evaluationId;
+
+ @ApiModelProperty("专家会议ID")
+ private Long expertMeetingId;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertReplaceTodoListItemVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertReplaceTodoListItemVO.java
new file mode 100644
index 0000000..9325bab
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/ExpertReplaceTodoListItemVO.java
@@ -0,0 +1,41 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
+
+/**
+ *
+ * ExpertReplaceTodoListItemVo
+ *
+ *
+ * @author WendyYang
+ * @since 16:46 2022/8/29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ExpertReplaceTodoListItemVO extends ExpertBasicInfoVO {
+
+ @ApiModelProperty("会议ID")
+ private Long meetingId;
+
+ private Long expertMeetingId;
+
+ @ApiModelProperty("会议名称")
+ private String meetingName;
+
+ @ApiModelProperty("邀请结果")
+ private Integer status;
+
+ @ApiModelProperty("邀请方式")
+ private String inviteType;
+
+ @ApiModelProperty("开始时间")
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("结束时间")
+ private LocalDateTime endTime;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/InviteRuleDetailVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/InviteRuleDetailVO.java
new file mode 100644
index 0000000..267127d
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/InviteRuleDetailVO.java
@@ -0,0 +1,72 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ *
+ * InviteRuleDetailVo
+ *
+ *
+ * @author WendyYang
+ * @since 14:58 2022/8/17
+ */
+@Data
+public class InviteRuleDetailVO {
+
+ @ApiModelProperty("是否创建邀请规则")
+ private Boolean invited;
+
+ @ApiModelProperty("随机邀请规则")
+ private List randomRules;
+
+ @ApiModelProperty("是否有指定抽取规则")
+ private Boolean hasAppointRule;
+
+ @ApiModelProperty("指定抽取规则")
+ private AppointRuleVo appointRule;
+
+ @ApiModelProperty("是否有回避规则")
+ private Boolean hasAvoidInfo;
+
+ @ApiModelProperty("回避信息")
+ private AvoidInfoVo avoidInfo;
+
+ @Data
+ public static class AvoidInfoVo {
+
+ private List companyIds;
+
+ private Boolean avoidMates;
+
+ private List experts;
+
+ }
+
+ @Data
+ public static class AppointRuleVo {
+
+ private String inviteDesc;
+
+ private List experts;
+
+ }
+
+ public Boolean setAndGetHasAppointRule(Boolean hasAppointRule) {
+ this.hasAppointRule = hasAppointRule;
+ return this.hasAppointRule;
+ }
+
+ public Boolean setAndGetHasAvoidInfo(Boolean hasAvoidInfo) {
+ this.hasAvoidInfo = hasAvoidInfo;
+ return this.hasAvoidInfo;
+ }
+
+ public Boolean setAndGetInvited(Boolean invited) {
+ this.invited = invited;
+ return this.invited;
+ }
+
+}
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
new file mode 100644
index 0000000..11a2f52
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingByManagerVO.java
@@ -0,0 +1,76 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Builder;
+import lombok.Data;
+import lombok.experimental.Tolerate;
+
+import java.time.LocalDateTime;
+
+/**
+ *
+ * MeetingByManagerVo
+ *
+ *
+ * @author WendyYang
+ * @since 11:43 2022/8/8
+ */
+@Data
+@Builder
+@ApiModel("会议实体(管理员列表)")
+public class MeetingByManagerVO {
+
+ @Tolerate
+ public MeetingByManagerVO() {
+ }
+
+ @ApiModelProperty("事务ID")
+ private Long id;
+
+ @ApiModelProperty("事务状态")
+ private Integer status;
+
+ @ApiModelProperty("会议参加状态:1 待参加、2 已参加、3 已请假")
+ private Integer attendStatus;
+
+ @ApiModelProperty("事务名称")
+ private String name;
+
+ @ApiModelProperty("联系人")
+ private String connecter;
+
+ @ApiModelProperty("联系方式")
+ private String contact;
+
+ @ApiModelProperty("会议地址详情")
+ private String meetingAddress;
+
+ @ApiModelProperty("事务类型编码")
+ private String dateType;
+
+ @ApiModelProperty("事务类型名称")
+ private String dateTypeName;
+
+ @ApiModelProperty("事务开始时间")
+ @JSONField(format = "yyyy-MM-dd HH:mm")
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("事务结束时间")
+ @JSONField(format = "yyyy-MM-dd HH:mm")
+ private LocalDateTime endTime;
+
+ @ApiModelProperty("邀请人数")
+ private Integer inviteCount;
+
+ @ApiModelProperty("确认人数")
+ private Integer confirmCount;
+
+ @ApiModelProperty("是否进行了专家抽取:true 是、false 否")
+ private Boolean invited;
+
+ @ApiModelProperty("抽取单位")
+ private String inviterCompany;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingCalenderItemVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingCalenderItemVO.java
new file mode 100644
index 0000000..76607ea
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingCalenderItemVO.java
@@ -0,0 +1,38 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDate;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ *
+ * MeetingCalenderItemVo
+ *
+ *
+ * @author WendyYang
+ * @since 22:57 2022/8/24
+ */
+@Data
+@ApiModel("会议日历视图实体")
+public class MeetingCalenderItemVO {
+
+ @ApiModelProperty("当前日期")
+ private LocalDate today;
+
+ @ApiModelProperty("是否请假")
+ private Boolean hasLeave;
+
+ @ApiModelProperty("请假ID")
+ private Collection leaveIds;
+
+ @ApiModelProperty("是否有会议")
+ private Boolean hasMeeting;
+
+ @ApiModelProperty("会议信息")
+ private List meetings;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingConfirmToDoListItemVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingConfirmToDoListItemVO.java
new file mode 100644
index 0000000..499d7e1
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingConfirmToDoListItemVO.java
@@ -0,0 +1,51 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import com.ningdatech.pmapi.sys.model.dto.RegionDTO;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ *
+ * MeetingConfirmToDoListItem
+ *
+ *
+ * @author WendyYang
+ * @since 15:20 2022/8/29
+ */
+@Data
+public class MeetingConfirmToDoListItemVO {
+
+ @ApiModelProperty("会议ID")
+ private Long meetingId;
+
+ @ApiModelProperty("会议名称")
+ private String meetingName;
+
+ @ApiModelProperty("会议开始时间")
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("会议结束时间")
+ private LocalDateTime endTime;
+
+ @ApiModelProperty("会议类型")
+ private String type;
+
+ @ApiModelProperty("举办地址详情")
+ private String regionDetail;
+
+ @ApiModelProperty("举办地址")
+ private List regions;
+
+ @ApiModelProperty("状态")
+ private Integer status;
+
+ @ApiModelProperty("邀请总人数")
+ private Integer totalExpert;
+
+ @ApiModelProperty("确认总人数")
+ private Integer confirmedExpert;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingCountByExpertVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingCountByExpertVO.java
new file mode 100644
index 0000000..c36eef6
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingCountByExpertVO.java
@@ -0,0 +1,46 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ *
+ * MeetingCountByExpertVo
+ *
+ *
+ * @author WendyYang
+ * @since 10:23 2022/10/19
+ */
+@Data
+@AllArgsConstructor
+@ApiModel("专家工作台:会议数量统计视图")
+public class MeetingCountByExpertVO {
+
+ @ApiModelProperty("待参加数量")
+ private Integer toBeAttended;
+
+ @ApiModelProperty("已参加数量")
+ private Integer attended;
+
+ @ApiModelProperty("请假数量")
+ private Integer leaved;
+
+ public static MeetingCountByExpertVO init() {
+ return new MeetingCountByExpertVO(0, 0, 0);
+ }
+
+ public void incrToBeAttended() {
+ this.toBeAttended += 1;
+ }
+
+ public void incrAttended() {
+ this.attended += 1;
+ }
+
+ public void incrLeaved() {
+ this.leaved += 1;
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingCountSummaryVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingCountSummaryVO.java
new file mode 100644
index 0000000..5cc643e
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingCountSummaryVO.java
@@ -0,0 +1,33 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ *
+ * MeetingCountSummaryVo
+ *
+ *
+ * @author WendyYang
+ * @since 09:43 2022/8/30
+ */
+@Data
+@Builder
+@ApiModel("会议数量统计视图实体")
+public class MeetingCountSummaryVO {
+
+ @ApiModelProperty("已完成")
+ private Integer completed;
+
+ @ApiModelProperty("已取消")
+ private Integer canceled;
+
+ @ApiModelProperty("待召开")
+ private Integer toBeHeld;
+
+ @ApiModelProperty("已召开")
+ private Integer held;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingDetailBasicVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingDetailBasicVO.java
new file mode 100644
index 0000000..1fe9e37
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingDetailBasicVO.java
@@ -0,0 +1,97 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.ningdatech.file.entity.vo.result.AttachFileVo;
+import com.ningdatech.pmapi.sys.model.dto.RegionDTO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Builder;
+import lombok.Data;
+import lombok.experimental.Tolerate;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ *
+ * MeetingDetailBasicVo
+ *
+ *
+ * @author WendyYang
+ * @since 15:16 2022/8/8
+ */
+@Data
+@Builder
+@ApiModel("会议详情基本信息")
+public class MeetingDetailBasicVO {
+
+ @Tolerate
+ public MeetingDetailBasicVO() {
+ }
+
+ private Long id;
+
+ @ApiModelProperty("会议名称")
+ private String name;
+
+ @ApiModelProperty("会议类型名称")
+ private String typeName;
+
+ @ApiModelProperty("会议类型代码")
+ private String type;
+
+ @ApiModelProperty("开始时间")
+ @JSONField(format = "yyyy-MM-dd HH:mm")
+ private LocalDateTime startTime;
+
+ @ApiModelProperty("结束时间")
+ @JSONField(format = "yyyy-MM-dd HH:mm")
+ private LocalDateTime endTime;
+
+ @ApiModelProperty("联系人")
+ private String connecter;
+
+ @ApiModelProperty("创建人")
+ private String author;
+
+ private List regions;
+
+ @ApiModelProperty("地点")
+ private String address;
+
+ @ApiModelProperty("联系方式")
+ private String contact;
+
+ @ApiModelProperty("创建时间")
+ private LocalDateTime createOn;
+
+ @ApiModelProperty("会议说明")
+ private String description;
+
+ @ApiModelProperty("相关材料")
+ private List attachments;
+
+ @ApiModelProperty("备注")
+ private String remark;
+
+ @ApiModelProperty("会议状态")
+ private Integer status;
+
+ @ApiModelProperty("专家出席状态")
+ private Integer attendStatus;
+
+ @ApiModelProperty("取消说明")
+ private String cancelRemark;
+
+ @ApiModelProperty("创建人")
+ private String createBy;
+
+ private Boolean invited;
+
+ @ApiModelProperty("抽取单位")
+ private String inviterCompany;
+
+ @ApiModelProperty("是否已确认下发会议通知名单")
+ private Boolean sendMeetingNotice;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingResultVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingResultVO.java
new file mode 100644
index 0000000..66be470
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/MeetingResultVO.java
@@ -0,0 +1,29 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import com.ningdatech.file.entity.vo.result.AttachFileVo;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ *
+ * MeetingResultVo
+ *
+ *
+ * @author WendyYang
+ * @since 21:28 2022/8/8
+ */
+@Data
+public class MeetingResultVO {
+
+ @ApiModelProperty("事务ID")
+ private Long meetingId;
+
+ @ApiModelProperty("会议结果说明")
+ private String resultDescription;
+
+ @ApiModelProperty("附件信息")
+ private List attachments;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/RandomInviteRuleVO.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/RandomInviteRuleVO.java
new file mode 100644
index 0000000..7d1f745
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/entity/vo/RandomInviteRuleVO.java
@@ -0,0 +1,31 @@
+package com.ningdatech.pmapi.meeting.entity.vo;
+
+import com.ningdatech.pmapi.meeting.entity.dto.RandomInviteRuleDTO;
+import com.ningdatech.pmapi.sys.model.dto.RegionDTO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+/**
+ *
+ * RandomInviteRuleVo
+ *
+ *
+ * @author WendyYang
+ * @since 09:55 2022/8/26
+ */
+@Data
+@ApiModel("随机抽取规则视图实体")
+@EqualsAndHashCode(callSuper = true)
+public class RandomInviteRuleVO extends RandomInviteRuleDTO {
+
+ @ApiModelProperty("履职意向地(回显使用)")
+ private List intentionRegions;
+
+ @ApiModelProperty("专家层级意向地(回显使用)")
+ private List expertRegions;
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/ExpertInviteHelper.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/ExpertInviteHelper.java
new file mode 100644
index 0000000..997f565
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/ExpertInviteHelper.java
@@ -0,0 +1,80 @@
+package com.ningdatech.pmapi.meeting.helper;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ningdatech.basic.util.CollUtils;
+import com.ningdatech.pmapi.meeting.entity.domain.Meeting;
+import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert;
+import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO;
+import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus;
+import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatus;
+import com.ningdatech.pmapi.meeting.service.IMeetingExpertService;
+import com.ningdatech.pmapi.meeting.service.IMeetingService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.util.*;
+
+/**
+ *
+ * ExpertInviteHelper
+ *
+ *
+ * @author WendyYang
+ * @since 16:35 2022/11/21
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class ExpertInviteHelper {
+
+ private final IMeetingService meetingService;
+ private final IMeetingExpertService meetingExpertService;
+
+ /**
+ * 获取时间段内被抽中的专家(通知中、确认参加)
+ *
+ * @param start 开始时间
+ * @param end 结束时间
+ * @return java.util.List
+ * @author WendyYang
+ **/
+ public List listInvitedExpertByTime(LocalDateTime start, LocalDateTime end) {
+ LambdaQueryWrapper meetingQuery = Wrappers.lambdaQuery(Meeting.class)
+ .select(Meeting::getId)
+ .eq(Meeting::getStatus, MeetingStatus.Manager.UNCOMPLETED.getCode())
+ .and(wrapper -> wrapper.between(Meeting::getStartTime, start, end)
+ .or(wrapper1 -> wrapper1.between(Meeting::getEndTime, start, end)));
+ List meetings = meetingService.list(meetingQuery);
+ if (meetings.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List meetingIds = CollUtils.fieldList(meetings, Meeting::getId);
+ LambdaQueryWrapper meetingExpertQuery = Wrappers.lambdaQuery(MeetingExpert.class)
+ .select(MeetingExpert::getExpertId)
+ .in(MeetingExpert::getStatus, ExpertAttendStatus.AGREED.getCode(), ExpertAttendStatus.NOTICING.getCode())
+ .in(MeetingExpert::getMeetingId, meetingIds);
+ List meetingExperts = meetingExpertService.list(meetingExpertQuery);
+ return CollUtils.fieldList(meetingExperts, MeetingExpert::getExpertId);
+ }
+
+ public Set listExpertLeaveOrInvited(LocalDateTime start, LocalDateTime end) {
+ Set notInUserIds = new HashSet<>();
+ notInUserIds.addAll(listInvitedExpertByTime(start, end));
+ return notInUserIds;
+ }
+
+ public Set getAvoidExpert(List appoints, AvoidInfoDTO avoid, LocalDateTime start, LocalDateTime end) {
+ Set expertIds = new HashSet<>();
+ Optional.ofNullable(appoints).ifPresent(expertIds::addAll);
+ Optional.ofNullable(avoid)
+ .flatMap(w -> Optional.ofNullable(w.getExpertIds()))
+ .ifPresent(expertIds::addAll);
+ // 过滤掉请假专家
+ expertIds.addAll(listInvitedExpertByTime(start, end));
+ return expertIds;
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/MeetingManageHelper.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/MeetingManageHelper.java
new file mode 100644
index 0000000..b221be6
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/MeetingManageHelper.java
@@ -0,0 +1,222 @@
+package com.ningdatech.pmapi.meeting.helper;
+
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ningdatech.basic.exception.BizException;
+import com.ningdatech.basic.util.CollUtils;
+import com.ningdatech.pmapi.common.util.BizUtils;
+import com.ningdatech.pmapi.common.util.StrUtils;
+import com.ningdatech.pmapi.expert.constant.ExpertAccountStatusEnum;
+import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo;
+import com.ningdatech.pmapi.expert.model.dto.ExpertDictionaryDTO;
+import com.ningdatech.pmapi.expert.model.dto.ExpertUserFullInfoDTO;
+import com.ningdatech.pmapi.expert.service.ExpertInfoService;
+import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService;
+import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule;
+import com.ningdatech.pmapi.meeting.entity.domain.Meeting;
+import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert;
+import com.ningdatech.pmapi.meeting.entity.dto.AvoidInfoDTO;
+import com.ningdatech.pmapi.meeting.entity.dto.MeetingAndAttendStatusDTO;
+import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus;
+import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatus;
+import com.ningdatech.pmapi.meeting.entity.req.MeetingListReq;
+import com.ningdatech.pmapi.meeting.entity.vo.ExpertBasicInfoVO;
+import com.ningdatech.pmapi.meeting.entity.vo.MeetingByManagerVO;
+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.meta.constant.DictExpertInfoTypeEnum;
+import com.ningdatech.pmapi.meta.helper.DictionaryCache;
+import com.ningdatech.pmapi.meta.model.dto.DictionaryDTO;
+import lombok.AllArgsConstructor;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+
+/**
+ *
+ * MeetingManageHelper
+ *
+ *
+ * @author WendyYang
+ * @since 17:23 2022/8/23
+ */
+@Component
+@AllArgsConstructor
+public class MeetingManageHelper {
+
+ private final DictionaryCache dictionaryCache;
+ private final ExpertInfoService expertInfoService;
+ private final IExpertUserFullInfoService expertUserFullInfoService;
+ private final IMeetingExpertService meetingExpertService;
+ private final IExpertInviteRuleService inviteRuleService;
+ private final IExpertInviteAvoidRuleService inviteAvoidRuleService;
+
+ /**
+ * 获取专家出席会议的状态
+ *
+ * @param info 会议状态及评价信息
+ * @return java.lang.Integer
+ * @author WendyYang
+ **/
+ public Integer getExpertAttendStatus(MeetingAndAttendStatusDTO info) {
+ if (info.getAttended() == null && info.getStatus().equals(ExpertAttendStatus.AGREED.getCode())) {
+ return MeetingStatus.Expert.TO_ATTEND.getCode();
+ } else if (info.getStatus().equals(ExpertAttendStatus.ON_LEAVE.getCode())) {
+ return MeetingStatus.Expert.ON_LEAVE.getCode();
+ } else if (info.getAttended() != null && info.getAttended()) {
+ return MeetingStatus.Expert.ATTENDED.getCode();
+ } else {
+ return MeetingStatus.Expert.UN_ATTEND.getCode();
+ }
+ }
+
+ public MeetingByManagerVO buildByMeeting(Meeting meeting) {
+ return MeetingByManagerVO.builder()
+ .id(meeting.getId())
+ .dateTypeName(dictionaryCache.getByCode(meeting.getType()).getName())
+ .meetingAddress(meeting.getRegionDetail())
+ .name(meeting.getName())
+ .startTime(meeting.getStartTime())
+ .endTime(meeting.getEndTime())
+ .connecter(meeting.getConnecter())
+ .contact(meeting.getContact())
+ .status(meeting.getStatus())
+ .invited(meeting.getInvited())
+ .inviterCompany(meeting.getHoldCompany())
+ .build();
+ }
+
+ public void buildMeetingQuery(LambdaQueryWrapper query, MeetingListReq po) {
+ if (StrUtil.isNotBlank(po.getName())) {
+ query.like(Meeting::getName, po.getName());
+ }
+ if (StrUtil.isNotBlank(po.getAddress())) {
+ query.like(Meeting::getRegionDetail, po.getAddress());
+ }
+ if (StrUtil.isNotBlank(po.getType())) {
+ query.eq(Meeting::getType, po.getType());
+ }
+ if (po.getStartTime() != null) {
+ query.ge(Meeting::getStartTime, po.getStartTime());
+ }
+ if (po.getEndTime() != null) {
+ query.le(Meeting::getEndTime, po.getEndTime());
+ }
+ }
+
+ /**
+ * 构建用户基本信息
+ *
+ * @param userIds 用户ID
+ * @return java.util.Map
+ * @author WendyYang
+ **/
+ public Map getExpertBasicInfo(List userIds) {
+ /*List expertInfos = expertInfoService.listExpertUserFullInfoAll(userIds);
+ return CollUtils.listToMap(expertInfos, ExpertFullInfoAllDTO::getUserId, w -> {
+ ExpertBasicInfoVO basicInfoVo = new ExpertBasicInfoVO();
+ ExpertUserFullInfoDTO userInfo = w.getExpertUserInfoDTO();
+ basicInfoVo.setName(userInfo.getName());
+ basicInfoVo.setExpertId(w.getUserId());
+ basicInfoVo.setContact(userInfo.getPhoneNo());
+ basicInfoVo.setCompany(userInfo.getCompany());
+ Optional first = w.getExpertDictionaryList().stream()
+ .filter(dict -> dict.getExpertInfoField().equals(DictExpertInfoTypeEnum.TITLE_LEVEL.getKey()))
+ .findFirst();
+ if (first.isPresent()) {
+ DictionaryDTO dictInfo = dictionaryCache.getByCode(first.get().getDictionaryCode());
+ basicInfoVo.setJobLevel(dictInfo.getName());
+ } else {
+ basicInfoVo.setJobLevel("");
+ }
+ basicInfoVo.setCompanyType("");
+ return basicInfoVo;
+ });*/
+ // TODO
+ return null;
+ }
+
+ public AvoidInfoDTO getAvoidInfoDto(Long meetingId) {
+ ExpertInviteAvoidRule avoidRule = inviteAvoidRuleService.getByMeetingId(meetingId);
+ AvoidInfoDTO avoidInfoDto = new AvoidInfoDTO();
+ avoidInfoDto.setAvoidMates(avoidRule.getAvoidMates());
+ avoidInfoDto.setExpertIds(BizUtils.splitToLong(avoidRule.getExpertIds()));
+ avoidInfoDto.setCompanyIds(StrUtils.split(avoidRule.getCompanyIds()));
+ return avoidInfoDto;
+ }
+
+ public void saveAvoidInfo(Long meetingId, List expertIds) {
+ ExpertInviteAvoidRule avoidRule = inviteAvoidRuleService.getByMeetingId(meetingId);
+ avoidRule.setExpertIds(CollUtils.joinByComma(expertIds));
+ inviteAvoidRuleService.saveOrUpdate(avoidRule);
+ }
+
+ /**
+ * 校验是否能够进行指定邀请
+ *
+ * @param meetingId 会议ID
+ * @param expertIds 专家ID
+ * @author WendyYang
+ **/
+ public List appointExpertCheck(Long meetingId, List expertIds) {
+ List experts = expertUserFullInfoService.listByUserId(expertIds);
+ AvoidInfoDTO avoidRule = getAvoidInfoDto(meetingId);
+ Map countMap = new HashMap<>(16);
+ experts.forEach(expert -> {
+ if (avoidRule.getCompanyIds().contains(expert.getCompany())) {
+ throw BizException.wrap("回避单位的专家不可出现在指定邀请名单中");
+ }
+ if (CollectionUtils.isNotEmpty(avoidRule.getExpertIds()) && avoidRule.getExpertIds().contains(expert.getUserId())) {
+ throw BizException.wrap("已回避的专家不可被指定邀请");
+ }
+ if (avoidRule.getAvoidMates()) {
+ Integer oldValue = countMap.put(expert.getCompany(), 1);
+ Assert.isNull(oldValue, "不可选择同单位的多个专家");
+ }
+ // 校验专家状态
+ ExpertAccountStatusEnum accountStatus = ExpertAccountStatusEnum.of(expert.getExpertAccountStatus());
+ if (!accountStatus.equals(ExpertAccountStatusEnum.AVAILABLE)) {
+ throw BizException.wrap("专家%s不可被抽取", expert.getExpertName());
+ }
+ });
+ Map expertMap = CollUtils.listToMap(experts, ExpertUserFullInfo::getUserId);
+ List meetingExperts = meetingExpertService.listByMeetingId(meetingId);
+ if (!meetingExperts.isEmpty()) {
+ Comparator comparator = Comparator.comparing(MeetingExpert::getUpdateOn).reversed();
+ Collection values = BizUtils.groupFirst(meetingExperts, MeetingExpert::getExpertId, comparator);
+ values.forEach(w -> {
+ ExpertUserFullInfo expertInfo = expertMap.get(w.getExpertId());
+ if (expertInfo != null) {
+ String expertName = expertInfo.getExpertName();
+ switch (ExpertAttendStatus.getByCode(w.getStatus())) {
+ case REFUSED:
+ throw BizException.wrap("专家%s已拒绝参加", expertName);
+ case CANCELED:
+ throw BizException.wrap("专家%s已被移除", expertName);
+ case REPLACED:
+ switch (ExpertAttendStatus.getByCode(w.getPreStatus())) {
+ case REFUSED:
+ throw BizException.wrap("专家%s已拒绝参加", expertName);
+ case CANCELED:
+ throw BizException.wrap("专家%s已被移除", expertName);
+ default:
+ break;
+ }
+ break;
+ case AGREED:
+ throw BizException.wrap("专家%s已同意参加", expertName);
+ case NOTICING:
+ throw BizException.wrap("专家%s正在通知中", expertName);
+ default:
+ break;
+ }
+ }
+ });
+ }
+ return experts;
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/YxtCallOrSmsHelper.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/YxtCallOrSmsHelper.java
new file mode 100644
index 0000000..bd713f0
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/helper/YxtCallOrSmsHelper.java
@@ -0,0 +1,50 @@
+package com.ningdatech.pmapi.meeting.helper;
+
+import com.ningdatech.pmapi.meeting.entity.domain.Meeting;
+import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ *
+ * YxtCallOrSmsHelper
+ *
+ *
+ * @author WendyYang
+ * @since 23:59 2022/8/31
+ */
+@Component
+@AllArgsConstructor
+public class YxtCallOrSmsHelper {
+
+ // private final YinXinTongClient yinXinTongClient;
+
+ public void callByMeetingExperts(Meeting meeting, List experts) {
+ /*String callContent = String.format(YxtCallTemplateConst.OFFLINE_TEMPLATE,
+ meeting.getHoldCompany(), meeting.getName(),
+ meeting.getStartTime().format(DateUtil.DTF_YMD_HM), meeting.getRegionDetail());
+ List callContexts = CollUtils.convert(experts, w -> {
+ SubmitTaskCallContext context = new SubmitTaskCallContext();
+ context.setContent(callContent);
+ context.setReceiveNumber(w.getMobile());
+ return context;
+ });
+ SubmitTaskCallResponse callResponse = yinXinTongClient.submitTaskCall(SubmitTaskCallCmd.of(callContexts));
+ experts.forEach(w -> w.setSubmitKey(callResponse.getSubmitKey()));*/
+ }
+
+ /*public void sendSms(List smsList) {
+ yinXinTongClient.submitSmsTask(new SendSmsCmd() {{
+ setContextList(smsList);
+ setSmsSignEnum(YxtSmsSignEnum.ZJS_ELECTRONIC_EXPERT_LIB);
+ }});
+ }
+
+ public void sendSms(SendSmsContext sms) {
+ sendSms(Collections.singletonList(sms));
+ }*/
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/DashboardManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/DashboardManage.java
new file mode 100644
index 0000000..0d1a634
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/DashboardManage.java
@@ -0,0 +1,241 @@
+package com.ningdatech.pmapi.meeting.manage;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ningdatech.basic.exception.BizException;
+import com.ningdatech.basic.model.PagePo;
+import com.ningdatech.basic.model.PageVo;
+import com.ningdatech.basic.util.CollUtils;
+import com.ningdatech.pmapi.meeting.entity.domain.Meeting;
+import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert;
+import com.ningdatech.pmapi.meeting.entity.dto.CountConfirmByMeetingIdDTO;
+import com.ningdatech.pmapi.meeting.entity.dto.MeetingAndAttendStatusDTO;
+import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus;
+import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteType;
+import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatus;
+import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatusByDashboard;
+import com.ningdatech.pmapi.meeting.entity.req.MeetingCalenderReq;
+import com.ningdatech.pmapi.meeting.entity.req.MeetingListReq;
+import com.ningdatech.pmapi.meeting.entity.vo.*;
+import com.ningdatech.pmapi.meeting.helper.MeetingManageHelper;
+import com.ningdatech.pmapi.meeting.service.IMeetingExpertEvaluationService;
+import com.ningdatech.pmapi.meeting.service.IMeetingExpertService;
+import com.ningdatech.pmapi.meeting.service.IMeetingService;
+import com.ningdatech.pmapi.meta.helper.DictionaryCache;
+import com.ningdatech.pmapi.user.util.LoginUserUtil;
+import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.tuple.Pair;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * DashboardManage
+ *
+ *
+ * @author WendyYang
+ * @since 23:04 2022/8/24
+ */
+@Component
+@AllArgsConstructor
+public class DashboardManage {
+
+ private final MeetingManage meetingManage;
+ private final IMeetingService meetingService;
+ private final IMeetingExpertService meetingExpertService;
+ private final MeetingManageHelper meetingManageHelper;
+ private final IMeetingExpertEvaluationService meetingExpertEvaluationService;
+ private final DictionaryCache dictionaryCache;
+
+ public static final int MEETING_CALENDER_MONTHS = 2;
+
+ public List meetingCalender(MeetingCalenderReq po) {
+ if (po.getStartDate().plusMonths(MEETING_CALENDER_MONTHS).isBefore(po.getEndDate())) {
+ throw new BizException("最多可查询两个月数据");
+ }
+ MeetingListReq meetingListPo = new MeetingListReq();
+ meetingListPo.setPageSize(500);
+ meetingListPo.setStartTime(po.getStartDate().atStartOfDay());
+ meetingListPo.setEndTime(po.getEndDate().atTime(LocalTime.MAX));
+ PageVo meetingPage = meetingManage.meetingListByExpert(meetingListPo);
+ Map> meetingByDate = meetingPage.getRecords().stream().map(w -> {
+ List> pairs = new ArrayList<>();
+ LocalDateTime tempTime = w.getStartTime();
+ while (tempTime.isBefore(w.getEndTime())) {
+ pairs.add(Pair.of(tempTime.toLocalDate(), w));
+ tempTime = tempTime.plusDays(1);
+ }
+ return pairs;
+ }).flatMap(Collection::stream)
+ .collect(Collectors.groupingBy(Pair::getLeft,
+ Collectors.collectingAndThen(Collectors.mapping(Pair::getRight, Collectors.toList()),
+ w -> {
+ w.sort(Comparator.comparing(MeetingByManagerVO::getStartTime));
+ return w;
+ })));
+ LocalDate tempDate = po.getStartDate();
+ List result = new ArrayList<>();
+ while (!tempDate.isAfter(po.getEndDate())) {
+ MeetingCalenderItemVO item = new MeetingCalenderItemVO();
+ List meetings = meetingByDate.get(tempDate);
+ item.setHasMeeting(meetings != null);
+ if (item.getHasMeeting()) {
+ item.setMeetings(meetings);
+ }
+ item.setToday(tempDate);
+ result.add(item);
+ tempDate = tempDate.plusDays(1);
+ }
+ return result;
+ }
+
+ public PageVo expertEvaluationToDo(PagePo po) {
+ PageVo result = PageVo.of(new ArrayList<>(), 0L);
+ // 查询所有未完成的项目
+ LambdaQueryWrapper query = Wrappers.lambdaQuery(Meeting.class)
+ .select(Meeting::getId)
+ .ne(Meeting::getStatus, MeetingStatus.Manager.CANCELED.getCode())
+ .eq(Meeting::getCreateBy, LoginUserUtil.getUserId());
+ List meetings = meetingService.list(query);
+ if (meetings.isEmpty()) {
+ return PageVo.empty();
+ }
+ List meetingIds = CollUtils.fieldList(meetings, Meeting::getId);
+ Page page = meetingExpertEvaluationService.pageExpertEvaluationTodo(meetingIds, po);
+ if (page.getTotal() > 0) {
+ List expertIds = new ArrayList<>(), meetingIdsByPage = new ArrayList<>();
+ page.getRecords().forEach(w -> {
+ meetingIdsByPage.add(w.getMeetingId());
+ expertIds.add(w.getExpertId());
+ });
+ Map meetingMap = CollUtils.listToMap(meetingService.listByIds(meetingIdsByPage), Meeting::getId);
+ Map basicInfoVoMap = meetingManageHelper.getExpertBasicInfo(expertIds);
+ page.getRecords().forEach(w -> {
+ ExpertBasicInfoVO expertInfo = basicInfoVoMap.get(w.getExpertId());
+ Meeting meeting = meetingMap.get(w.getMeetingId());
+ ExpertEvaluationToDoListItemVO item = BeanUtil.copyProperties(expertInfo, ExpertEvaluationToDoListItemVO.class);
+ item.setMeetingName(meeting.getName());
+ item.setMeetingId(w.getMeetingId());
+ item.setExpertMeetingId(w.getId());
+ item.setStartTime(meeting.getStartTime());
+ item.setEndTime(meeting.getEndTime());
+ result.getRecords().add(item);
+ });
+ result.setTotal(page.getTotal());
+ }
+ return result;
+ }
+
+ public PageVo expertConfirmToDo(PagePo po) {
+ // 查询所有未完成的项目
+ LambdaQueryWrapper query = Wrappers.lambdaQuery(Meeting.class)
+ .eq(Meeting::getStatus, MeetingStatus.Manager.UNCOMPLETED.getCode())
+ .eq(Meeting::getCreateBy, LoginUserUtil.getUserId())
+ .orderByDesc(Meeting::getStartTime);
+ List meetings = meetingService.list(query);
+ if (meetings.isEmpty()) {
+ return PageVo.empty();
+ }
+ List meetingIds = CollUtils.fieldList(meetings, Meeting::getId);
+ Map confirmedMap = meetingExpertService.countConfirmedByMeetingIds(meetingIds);
+ confirmedMap.entrySet().removeIf(w -> {
+ CountConfirmByMeetingIdDTO confirm = w.getValue();
+ return confirm.getConfirmed().equals(confirm.getTotal());
+ });
+ if (confirmedMap.size() == 0) {
+ return PageVo.empty();
+ }
+ meetings.removeIf(w -> !confirmedMap.containsKey(w.getId()));
+ List dataList = meetings.stream()
+ .skip((long) (po.getPageNumber() - 1) * po.getPageSize())
+ .limit(po.getPageSize()).map(w -> {
+ MeetingConfirmToDoListItemVO item = new MeetingConfirmToDoListItemVO();
+ CountConfirmByMeetingIdDTO confirm = confirmedMap.get(w.getId());
+ if (confirm == null) {
+ item.setTotalExpert(0);
+ item.setConfirmedExpert(0);
+ } else {
+ item.setTotalExpert(confirm.getTotal());
+ item.setConfirmedExpert(confirm.getConfirmed());
+ }
+ item.setMeetingId(w.getId());
+ item.setEndTime(w.getEndTime());
+ item.setStartTime(w.getStartTime());
+ item.setStatus(w.getStatus());
+ item.setRegionDetail(w.getRegionDetail());
+ item.setType(dictionaryCache.getByCode(w.getType()).getName());
+ item.setMeetingName(w.getName());
+ return item;
+ }).collect(Collectors.toList());
+ return PageVo.of(dataList, meetings.size());
+ }
+
+ public PageVo expertReplaceTodoList(PagePo po) {
+ // 查询所有未完成的项目
+ LambdaQueryWrapper query = Wrappers.lambdaQuery(Meeting.class)
+ .eq(Meeting::getStatus, MeetingStatus.Manager.UNCOMPLETED.getCode())
+ .eq(Meeting::getCreateBy, LoginUserUtil.getUserId())
+ .orderByDesc(Meeting::getStartTime);
+ List meetings = meetingService.list(query);
+ if (meetings.isEmpty()) {
+ return PageVo.empty();
+ }
+ List meetingIds = CollUtils.fieldList(meetings, Meeting::getId);
+ Page page = meetingExpertService.pageExpertByStatusAndMeetingIds(new Page<>(po.getPageNumber(), po.getPageSize()),
+ meetingIds, ExpertAttendStatus.ON_LEAVE);
+ if (page.getTotal() == 0) {
+ return PageVo.empty();
+ }
+ Map meetingMap = CollUtils.listToMap(meetings, Meeting::getId);
+ List expertIds = CollUtils.fieldList(page.getRecords(), MeetingExpert::getExpertId);
+ Map basicInfoVoMap = meetingManageHelper.getExpertBasicInfo(expertIds);
+ List dataList = page.getRecords().stream().map(w -> {
+ ExpertBasicInfoVO basicInfoVo = basicInfoVoMap.get(w.getExpertId());
+ ExpertReplaceTodoListItemVO item = BeanUtil.copyProperties(basicInfoVo, ExpertReplaceTodoListItemVO.class);
+ item.setMeetingId(w.getMeetingId());
+ item.setExpertMeetingId(w.getId());
+ Meeting meeting = meetingMap.get(w.getMeetingId());
+ item.setMeetingName(meeting.getName());
+ item.setInviteType(ExpertInviteType.getByCode(w.getInviteType()).getName());
+ item.setStatus(w.getStatus());
+ item.setStartTime(meeting.getStartTime());
+ item.setEndTime(meeting.getEndTime());
+ return item;
+ }).collect(Collectors.toList());
+ return PageVo.of(dataList, page.getTotal());
+ }
+
+ public MeetingCountSummaryVO meetingCountSummary() {
+ Map meetingCountSummary = meetingService.meetingCountSummary(LoginUserUtil.getUserId());
+ return MeetingCountSummaryVO.builder()
+ .canceled(meetingCountSummary.getOrDefault(MeetingStatusByDashboard.CANCELED, 0))
+ .completed(meetingCountSummary.getOrDefault(MeetingStatusByDashboard.COMPLETED, 0))
+ .toBeHeld(meetingCountSummary.getOrDefault(MeetingStatusByDashboard.TO_BE_HELD, 0))
+ .held(meetingCountSummary.getOrDefault(MeetingStatusByDashboard.HELD, 0))
+ .build();
+ }
+
+ public MeetingCountByExpertVO meetingCountByExpert() {
+ List attendStatusList = meetingExpertService.listByExpertIdAndStatus(LoginUserUtil.getUserId(), null, null);
+ MeetingCountByExpertVO result = MeetingCountByExpertVO.init();
+ attendStatusList.forEach(w -> {
+ if (w.getStatus().equals(ExpertAttendStatus.ON_LEAVE.getCode())) {
+ result.incrLeaved();
+ } else if (w.getAttended() != null && w.getAttended()) {
+ result.incrAttended();
+ } else {
+ result.incrToBeAttended();
+ }
+ });
+ return result;
+ }
+
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertInviteManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertInviteManage.java
new file mode 100644
index 0000000..546b676
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/ExpertInviteManage.java
@@ -0,0 +1,672 @@
+package com.ningdatech.pmapi.meeting.manage;
+
+import cn.hutool.core.collection.CollUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ningdatech.basic.util.CollUtils;
+import com.ningdatech.pmapi.common.util.BizUtils;
+import com.ningdatech.pmapi.expert.constant.ExpertAccountStatusEnum;
+import com.ningdatech.pmapi.expert.entity.ExpertAvoidCompany;
+import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo;
+import com.ningdatech.pmapi.expert.service.IExpertAvoidCompanyService;
+import com.ningdatech.pmapi.expert.service.IExpertIntentionWorkRegionService;
+import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService;
+import com.ningdatech.pmapi.meeting.builder.ExpertInviteBuilder;
+import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteRule;
+import com.ningdatech.pmapi.meeting.entity.domain.Meeting;
+import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert;
+import com.ningdatech.pmapi.meeting.entity.dto.*;
+import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus;
+import com.ningdatech.pmapi.meeting.helper.ExpertInviteHelper;
+import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper;
+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.meta.helper.TagCache;
+import com.ningdatech.pmapi.meta.model.entity.ExpertDictionary;
+import com.ningdatech.pmapi.meta.model.entity.ExpertTag;
+import com.ningdatech.pmapi.meta.service.IExpertDictionaryService;
+import com.ningdatech.pmapi.meta.service.IExpertTagService;
+import lombok.AllArgsConstructor;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.RandomUtils;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ *
+ * 专家邀请管理
+ *
+ *
+ * @author WendyYang
+ * @since 18:05 2022/8/8
+ */
+@Component
+@AllArgsConstructor
+public class ExpertInviteManage {
+
+ private final IExpertDictionaryService expertDictionaryService;
+ private final TagCache tagCache;
+ private final IExpertTagService expertTagService;
+ private final IExpertIntentionWorkRegionService workRegionService;
+ private final IExpertInviteRuleService inviteRuleService;
+ private final IMeetingExpertService meetingExpertService;
+ private final ExpertInviteHelper expertInviteHelper;
+ private final IExpertUserFullInfoService expertUserFullInfoService;
+ private final IMeetingService meetingService;
+ private final IExpertAvoidCompanyService iExpertAvoidCompanyService;
+ private final YxtCallOrSmsHelper yxtCallOrSmsHelper;
+
+ private static final Predicate> COLL_EMPTY = (coll) -> coll != null && coll.isEmpty();
+
+ private LambdaQueryWrapper buildBaseExpertQuery() {
+ return Wrappers.lambdaQuery(ExpertUserFullInfo.class)
+ .select(ExpertUserFullInfo::getUserId,
+ ExpertUserFullInfo::getId,
+ ExpertUserFullInfo::getCompany,
+ ExpertUserFullInfo::getPhoneNo)
+ .eq(ExpertUserFullInfo::getExpertAccountStatus, ExpertAccountStatusEnum.AVAILABLE.getKey());
+ }
+
+ /**
+ * 增加专家层级限制
+ *
+ * @param query 查询
+ * @param rule 随机邀请规则
+ */
+ private static void addRegionLimit(LambdaQueryWrapper query, RandomInviteRuleDTO rule) {
+ if (ObjectUtils.allNotNull(rule.getExpertRegionCode(), rule.getExpertRegionLevel())) {
+ query.eq(ExpertUserFullInfo::getRegionCode, rule.getExpertRegionCode());
+ query.eq(ExpertUserFullInfo::getRegionLevel, rule.getExpertRegionLevel());
+ }
+ }
+
+ /**
+ * 获取满足履职意向地的专家ID
+ * null -> 表示无需过滤
+ *
+ * @param rule 抽取规则
+ * @return java.util.List
+ * @author WendyYang
+ **/
+ private List expertIdsByRegion(RandomInviteRuleDTO rule) {
+ if (rule.getIntentionRegionCode() == null || rule.getIntentionRegionLevel() == null) {
+ return null;
+ }
+ return workRegionService.userIdsMatchIntentionRegion(rule.getIntentionRegionCode(), rule.getIntentionRegionLevel());
+ }
+
+
+ /**
+ * 如果抽取回避单位和专家回避单位一致,同样需要回避该专家
+ *
+ * @param companyNames /
+ * @return /
+ */
+ private List avoidCompanyExpertIds(List companyNames) {
+ if (CollUtil.isEmpty(companyNames)) {
+ return new ArrayList<>();
+ }
+ List dealCompanyNames = new ArrayList<>();
+ for (String companyName : companyNames) {
+ if (companyName.contains(",")) {
+ String[] splitCompanyNames = companyName.split(",");
+ for (String splitCompanyName : splitCompanyNames) {
+ dealCompanyNames.add(splitCompanyName);
+ }
+ } else {
+ dealCompanyNames.add(companyName);
+ }
+ }
+ List expertAvoidCompanyList = iExpertAvoidCompanyService.list(Wrappers.lambdaQuery(ExpertAvoidCompany.class)
+ .in(ExpertAvoidCompany::getCompanyName, dealCompanyNames));
+ return expertAvoidCompanyList.stream().map(ExpertAvoidCompany::getUserId).distinct().collect(Collectors.toList());
+ }
+
+ private List mergeExpertIdsByCondition(RandomInviteRuleDTO rule, AvoidInfoDTO avoidInfo) {
+ // 处理履职意向地
+ List expertIdsByIntentionRegion = expertIdsByRegion(rule);
+ if (COLL_EMPTY.evaluate(expertIdsByIntentionRegion)) {
+ return null;
+ }
+ // 处理专家标签
+ List expertIdsByTag = expertIdsByTag(rule);
+ if (COLL_EMPTY.evaluate(expertIdsByTag)) {
+ return null;
+ }
+ // 处理专家字典
+ List expertIdsByDict = expertIdsByDict(rule);
+ if (COLL_EMPTY.evaluate(expertIdsByDict)) {
+ return null;
+ }
+ // 处理专家回避单位 与 抽取回避单位是否相同
+ List avoidCompanyExpertIds = avoidCompanyExpertIds(avoidInfo.getCompanyIds());
+
+ // 聚合用户ID
+ List expertIdsIn = new ArrayList<>();
+ if (ObjectUtils.anyNotNull(expertIdsByDict, expertIdsByTag, expertIdsByIntentionRegion)) {
+ Optional.ofNullable(expertIdsByDict).ifPresent(expertIdsIn::addAll);
+ Optional.ofNullable(expertIdsByTag).ifPresent(item -> {
+ if (expertIdsIn.isEmpty()) {
+ expertIdsIn.addAll(expertIdsByTag);
+ } else {
+ expertIdsIn.removeIf(w -> !expertIdsByTag.contains(w));
+ }
+ });
+ Optional.ofNullable(expertIdsByIntentionRegion).ifPresent(item -> {
+ if (expertIdsIn.isEmpty()) {
+ expertIdsIn.addAll(expertIdsByIntentionRegion);
+ } else {
+ expertIdsIn.removeIf(w -> !expertIdsByIntentionRegion.contains(w));
+ }
+ });
+ if (expertIdsIn.isEmpty()) {
+ return null;
+ }
+ }
+
+ if (CollUtil.isNotEmpty(avoidCompanyExpertIds)) {
+ for (Long avoidCompanyExpertId : avoidCompanyExpertIds) {
+ expertIdsIn.remove(avoidCompanyExpertId);
+ }
+ }
+ return expertIdsIn;
+ }
+
+ /**
+ * 根据专家标签获取满足的专家ID
+ *
+ * @param rule 抽取规则
+ * @return java.util.List
+ * @author WendyYang
+ **/
+ private List expertIdsByTag(RandomInviteRuleDTO rule) {
+ if (CollectionUtils.isEmpty(rule.getExpertTags())) {
+ return null;
+ }
+ LambdaQueryWrapper query = Wrappers.lambdaQuery(ExpertTag.class)
+ .select(ExpertTag::getUserId, ExpertTag::getExpertInfoField);
+ rule.getExpertTags().forEach(tag -> {
+ List codes = tag.getTagCodes().stream()
+ .map(tagCache::listChildrenCodes)
+ .flatMap(Collection::stream)
+ .collect(Collectors.toList());
+ query.or(wrapper -> wrapper.eq(ExpertTag::getExpertInfoField, tag.getExpertTag())
+ .in(ExpertTag::getTagCode, codes));
+ });
+ List expertTagList = expertTagService.list(query);
+ return expertTagList.stream()
+ .collect(Collectors.groupingBy(ExpertTag::getUserId, Collectors.collectingAndThen(Collectors.toList(),
+ tags -> CollUtils.fieldList(tags, ExpertTag::getExpertInfoField).size())))
+ .entrySet().stream().filter(w -> w.getValue() == rule.getExpertTags().size())
+ .map(Map.Entry::getKey).collect(Collectors.toList());
+ }
+
+ /**
+ * 根据专家字典获取满足的专家ID
+ * null -> 表示无需过虑
+ * 空集合 -> 未查到
+ *
+ * @param rule 抽取规则
+ * @return java.util.List
+ * @author WendyYang
+ **/
+ private List expertIdsByDict(RandomInviteRuleDTO rule) {
+ if (CollectionUtils.isEmpty(rule.getExpertDicts())) {
+ return null;
+ }
+ LambdaQueryWrapper query = Wrappers.lambdaQuery(ExpertDictionary.class)
+ .select(ExpertDictionary::getUserId, ExpertDictionary::getExpertInfoField);
+ for (ExpertDictChooseDTO dict : rule.getExpertDicts()) {
+ query.or(wrapper -> wrapper.eq(ExpertDictionary::getExpertInfoField, dict.getExpertDict())
+ .in(ExpertDictionary::getDictionaryCode, dict.getDictCodes()));
+ }
+ List expertDictionaryList = expertDictionaryService.list(query);
+ return expertDictionaryList.stream()
+ .collect(Collectors.groupingBy(ExpertDictionary::getUserId,
+ Collectors.collectingAndThen(Collectors.toList(),
+ dicts -> CollUtils.fieldList(dicts, ExpertDictionary::getExpertInfoField).size())))
+ .entrySet().stream().filter(w -> w.getValue() == rule.getExpertDicts().size())
+ .map(Map.Entry::getKey).collect(Collectors.toList());
+ }
+
+
+ /**
+ * 专家抽取(随机)
+ *
+ * @param avoidInfo 回避信息
+ * @param randomRule 抽取规则
+ * @param appointExpertIds 指定抽取专家ID
+ * @return 满足抽取条件的专家
+ * @author WendyYang
+ **/
+ public ExpertChooseDTO expertInviteByRandomRule(AvoidInfoDTO avoidInfo,
+ RandomInviteRuleDTO randomRule,
+ List appointExpertIds,
+ LocalDateTime start,
+ LocalDateTime end) {
+ ExpertChooseDTO result = new ExpertChooseDTO(new ArrayList<>(), 0);
+ List expertIdsIn = mergeExpertIdsByCondition(randomRule, avoidInfo);
+ if (expertIdsIn == null) {
+ return result;
+ }
+ boolean avoid = avoidInfo != null;
+ boolean avoidExpert = avoid && CollUtil.isNotEmpty(avoidInfo.getExpertIds());
+ boolean avoidCompany = avoid && CollUtil.isNotEmpty(avoidInfo.getCompanyIds());
+ Set tmpAvoidCompany = new HashSet<>();
+ if (avoidCompany) {
+ List companyIds = avoidInfo.getCompanyIds();
+ for (String companyId : companyIds) {
+ if (companyId.contains(",")) {
+ String[] splitCompanyIds = companyId.split(",");
+ for (String splitCompanyId : splitCompanyIds) {
+ tmpAvoidCompany.add(splitCompanyId);
+ }
+ } else {
+ tmpAvoidCompany.add(companyId);
+ }
+ }
+ }
+ // 回避信息
+ if (CollUtil.isNotEmpty(appointExpertIds) && avoid && avoidInfo.getAvoidMates()) {
+ // 如果设置了回避本单位同事且手动指定了专家,则对应的单位需要排除
+ List appointUsers = expertUserFullInfoService.listByUserId(appointExpertIds);
+ tmpAvoidCompany.addAll(CollUtils.fieldList(appointUsers, ExpertUserFullInfo::getCompany));
+ }
+ LambdaQueryWrapper query = buildBaseExpertQuery();
+ query.notIn(!tmpAvoidCompany.isEmpty(), ExpertUserFullInfo::getCompany, tmpAvoidCompany);
+ if (avoidCompany) {
+ query.notExists("select 1 from expert_avoid_company eac where eac.user_id = expert_user_full_info.user_id" +
+ " and company_name in ({0})", CollUtils.joinByComma(avoidInfo.getCompanyIds()));
+ }
+ // 处理专家层级
+ addRegionLimit(query, randomRule);
+
+ if (!expertIdsIn.isEmpty()) {
+ if (avoidExpert) {
+ expertIdsIn.removeIf(w -> avoidInfo.getExpertIds().contains(w));
+ if (expertIdsIn.isEmpty()) {
+ // 字典、标签、履职意向地筛选出的专家ID移除需要回避的专家ID
+ // 如果为空则说明没有符合条件的
+ return result;
+ }
+ }
+ if (CollUtil.isNotEmpty(appointExpertIds)) {
+ expertIdsIn.removeIf(appointExpertIds::contains);
+ if (expertIdsIn.isEmpty()) {
+ return result;
+ }
+ }
+ // 过滤掉已参加会议的专家
+ List expertIdsLockByMeeting = expertInviteHelper.listInvitedExpertByTime(start, end);
+ expertIdsIn.removeIf(expertIdsLockByMeeting::contains);
+ if (expertIdsIn.isEmpty()) {
+ return result;
+ }
+ query.in(ExpertUserFullInfo::getUserId, expertIdsIn);
+ } else if (avoidExpert || CollUtil.isNotEmpty(appointExpertIds)) {
+ Set tempExperts = expertInviteHelper.getAvoidExpert(appointExpertIds, avoidInfo, start, end);
+ query.notIn(ExpertUserFullInfo::getUserId, tempExperts);
+ } else {
+ Set notInUserIds = expertInviteHelper.listExpertLeaveOrInvited(start, end);
+ if (!notInUserIds.isEmpty()) {
+ query.notIn(ExpertUserFullInfo::getUserId, notInUserIds);
+ }
+ }
+ List userFullInfos = expertUserFullInfoService.list(query);
+ if (userFullInfos.isEmpty()) {
+ return result;
+ }
+ if (avoid && avoidInfo.getAvoidMates()) {
+ // 回避同单位其他专家
+ Map> userFullInfoMap = CollUtils.group(userFullInfos, ExpertUserFullInfo::getCompany);
+ result.setTotal(userFullInfoMap.size());
+ if (randomRule.getCount() == null || userFullInfoMap.size() >= randomRule.getCount()) {
+ List userFullInfoList = inviteGroupByCompany(userFullInfoMap, randomRule.getCount());
+ result.setExperts(userFullInfoList);
+ }
+ } else {
+ result.setTotal(userFullInfos.size());
+ // count为空表示数量校验
+ if (randomRule.getCount() == null || result.getTotal() >= randomRule.getCount()) {
+ List userFullInfoList = inviteWithoutCompany(userFullInfos, randomRule.getCount());
+ result.setExperts(userFullInfoList);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * 专家替换、补充
+ *
+ * @param avoidInfo 回避信息
+ * @param randomRule 随机抽取
+ * @param meetingExperts 已抽取人员
+ * @param count 抽取数量
+ * @return com.ningdatech.emapi.meeting.entity.dto.ExpertChooseDto
+ * @author WendyYang
+ **/
+ public ExpertChooseDTO expertReplaceByRandomRule(AvoidInfoDTO avoidInfo,
+ RandomInviteRuleDTO randomRule,
+ Collection meetingExperts,
+ Integer count,
+ LocalDateTime start,
+ LocalDateTime end,
+ Long replacedExpertId) {
+ ExpertChooseDTO result = new ExpertChooseDTO(new ArrayList<>(), 0);
+ // 合并标签、字典
+ List expertIdsIn = mergeExpertIdsByCondition(randomRule, avoidInfo);
+ if (expertIdsIn == null) {
+ return result;
+ }
+ LambdaQueryWrapper query = buildBaseExpertQuery();
+ query.notIn(ExpertUserFullInfo::getCompany, avoidInfo.getCompanyIds());
+ query.notExists("select 1 from expert_avoid_company eac where eac.user_id = expert_user_full_info.user_id" +
+ " and company_name in ({0})", CollUtils.joinByComma(avoidInfo.getCompanyIds()));
+
+ // 处理专家层级
+ if (ObjectUtils.allNotNull(randomRule.getExpertRegionCode(), randomRule.getExpertRegionLevel())) {
+ query.eq(ExpertUserFullInfo::getRegionCode, randomRule.getExpertRegionCode());
+ query.eq(ExpertUserFullInfo::getRegionLevel, randomRule.getExpertRegionLevel());
+ }
+ if (expertIdsIn.size() > 0) {
+ if (CollectionUtils.isNotEmpty(avoidInfo.getExpertIds())) {
+ expertIdsIn.removeIf(w -> avoidInfo.getExpertIds().contains(w));
+ if (expertIdsIn.isEmpty()) {
+ // 字典、标签、履职意向地筛选出的专家ID移除需要回避的专家ID
+ // 如果为空则说明没有符合条件的
+ return result;
+ }
+ }
+ List lockExpertIds = expertInviteHelper.listInvitedExpertByTime(start, end);
+ expertIdsIn.removeIf(lockExpertIds::contains);
+ if (expertIdsIn.isEmpty()) {
+ return result;
+ }
+ query.in(ExpertUserFullInfo::getUserId, expertIdsIn);
+ } else if (CollectionUtils.isNotEmpty(avoidInfo.getExpertIds())) {
+ Set notInExpertIds = expertInviteHelper.getAvoidExpert(avoidInfo.getExpertIds(), null, start, end);
+ query.notIn(ExpertUserFullInfo::getUserId, notInExpertIds);
+ } else {
+ Set notInUserIds = expertInviteHelper.listExpertLeaveOrInvited(start, end);
+ if (notInUserIds.size() > 0) {
+ query.notIn(ExpertUserFullInfo::getUserId, notInUserIds);
+ }
+ }
+ List userFullInfos = expertUserFullInfoService.list(query);
+ if (userFullInfos.size() == 0) {
+ return result;
+ }
+ Comparator sort = Comparator.comparing(MeetingExpert::getUpdateOn).reversed();
+ Map tempExpertIdsMap = BizUtils.groupFirstMap(meetingExperts, MeetingExpert::getExpertId, sort);
+ Map> expertIdGroupByStatus = tempExpertIdsMap.values().stream()
+ .collect(Collectors.groupingBy(w -> ExpertAttendStatus.getByCode(w.getStatus())));
+ // 回避同单位其他专家
+ List removeExpertByCompany = new ArrayList<>();
+ BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatus.AGREED), removeExpertByCompany::addAll);
+ BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatus.NOTICING), removeExpertByCompany::addAll);
+ List removeExpertIds = new ArrayList<>();
+ // 拒绝参加的不可以被再次抽中
+ BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatus.REFUSED), w -> {
+ List tempRefused = CollUtils.fieldList(w, MeetingExpert::getExpertId);
+ removeExpertIds.addAll(tempRefused);
+ });
+ // 被取消的也不可以被再次抽中
+ BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatus.CANCELED), w -> {
+ List tempCanceled = CollUtils.fieldList(w, MeetingExpert::getExpertId);
+ removeExpertIds.addAll(tempCanceled);
+ });
+ // 被替换之前是上述两种状态的不可被再次抽中
+ BizUtils.notEmpty(expertIdGroupByStatus.get(ExpertAttendStatus.REPLACED), w -> {
+ for (MeetingExpert me : w) {
+ BizUtils.notNull(me.getPreStatus(), preStatus -> {
+ if (ExpertAttendStatus.REFUSED.eq(preStatus) || ExpertAttendStatus.CANCELED.eq(preStatus)) {
+ removeExpertIds.add(me.getExpertId());
+ }
+ });
+ }
+ });
+ // 不为空时表示单个专家替换否则为专家补抽
+ if (replacedExpertId != null) {
+ removeExpertIds.add(replacedExpertId);
+ }
+ List tempExpertIds = CollUtils.fieldList(removeExpertByCompany, MeetingExpert::getExpertId);
+ if (avoidInfo.getAvoidMates()) {
+ if (!tempExpertIds.isEmpty()) {
+ Set confirmedCompany = userFullInfos.stream()
+ .filter(w -> tempExpertIds.contains(w.getUserId()))
+ .map(ExpertUserFullInfo::getCompany).collect(Collectors.toSet());
+ userFullInfos.removeIf(w -> confirmedCompany.contains(w.getCompany()));
+ }
+ userFullInfos.removeIf(w -> removeExpertIds.contains(w.getUserId()));
+ Map> groupByCompany = CollUtils.group(userFullInfos, ExpertUserFullInfo::getCompany);
+ result.setTotal(groupByCompany.size());
+ result.setExperts(inviteGroupByCompany(groupByCompany, count));
+ } else {
+ // 移除确认参加、通知中的、拒绝参加、已取消
+ userFullInfos.removeIf(w -> tempExpertIds.contains(w.getUserId()) || removeExpertIds.contains(w.getUserId()));
+ result.setTotal(userFullInfos.size());
+ result.setExperts(inviteWithoutCompany(userFullInfos, count));
+ }
+ return result;
+ }
+
+ private List> selectMeetingExpertByCount() {
+ LambdaQueryWrapper query = Wrappers.lambdaQuery(Meeting.class)
+ .select(Meeting::getId)
+ .orderByDesc(Meeting::getCreateOn)
+ .last("limit " + 5);
+ List meetingIds = CollUtils.fieldList(meetingService.list(query), Meeting::getId);
+ if (meetingIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+ Map> groupByMeetingId = meetingExpertService.listByMeetingIds(meetingIds)
+ .stream().collect(Collectors.groupingBy(MeetingExpert::getMeetingId));
+ return groupByMeetingId.entrySet().stream()
+ .sorted(Map.Entry.comparingByKey(Comparator.reverseOrder()))
+ .map(Map.Entry::getValue)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * 每个单位只抽取一人
+ *
+ * @param expertGroupByCompany 需要抽取的人
+ * @param count 抽取数量
+ * @return java.util.List
+ * @author WendyYang
+ **/
+ private List inviteGroupByCompany(Map> expertGroupByCompany, Integer count) {
+ if (MapUtils.isEmpty(expertGroupByCompany)) {
+ return Collections.emptyList();
+ }
+ List> meetingExperts = selectMeetingExpertByCount();
+ if (meetingExperts.isEmpty()) {
+ return expertGroupByCompany.values().stream()
+ .map(expertUsers -> expertUsers.get(RandomUtils.nextInt(0, expertUsers.size())))
+ .limit(count).collect(Collectors.toList());
+ } else {
+ List result = new ArrayList<>();
+ List keySet = new ArrayList<>(expertGroupByCompany.keySet());
+ for (int i = 0; i < count; i++) {
+ String key = keySet.get(RandomUtils.nextInt(0, keySet.size()));
+ List expertUserFullInfos = expertGroupByCompany.get(key);
+ for (List expertList : meetingExperts) {
+ List tempList = expertUserFullInfos.stream()
+ .filter(w -> expertList.stream().noneMatch(expert -> expert.getExpertId().equals(w.getUserId())))
+ .collect(Collectors.toList());
+ if (!tempList.isEmpty()) {
+ result.add(tempList.get(RandomUtils.nextInt(0, tempList.size())));
+ break;
+ } else if (meetingExperts.indexOf(expertList) == (meetingExperts.size() - 1)) {
+ result.add(expertUserFullInfos.get(RandomUtils.nextInt(0, expertUserFullInfos.size())));
+ }
+ }
+ if (result.size() < count) {
+ keySet.remove(key);
+ if (keySet.isEmpty()) {
+ break;
+ }
+ }
+ }
+ return result;
+ }
+ }
+
+ private List inviteWithoutCompany(List userFullInfos, Integer count) {
+ List result = new ArrayList<>();
+ List> meetingExpertList = selectMeetingExpertByCount();
+ if (meetingExpertList.isEmpty()) {
+ for (int i = 0; i < count; i++) {
+ int randomIndex = RandomUtils.nextInt(0, userFullInfos.size());
+ result.add(userFullInfos.remove(randomIndex));
+ if (userFullInfos.size() == 0) {
+ break;
+ }
+ }
+ } else {
+ for (List meetingExperts : meetingExpertList) {
+ List unSelectedUsers = userFullInfos.stream()
+ .filter(w -> meetingExperts.stream().noneMatch(expert -> expert.getExpertId().equals(w.getUserId())))
+ .collect(Collectors.toList());
+ if (!unSelectedUsers.isEmpty()) {
+ result.addAll(unSelectedUsers);
+ if (result.size() >= count) {
+ return result.subList(0, count);
+ }
+ userFullInfos.removeAll(unSelectedUsers);
+ }
+ }
+ if (userFullInfos.size() == 0) {
+ return result;
+ }
+ int restCount = Math.min(count - result.size(), userFullInfos.size());
+ int groupCount = userFullInfos.size() / restCount;
+ if (userFullInfos.size() > restCount) {
+ Stream.iterate(0, t -> t + 1).limit(restCount)
+ .forEach(t -> {
+ int start = t * groupCount;
+ int end = start + groupCount;
+ if (end >= groupCount * restCount) {
+ end = userFullInfos.size();
+ }
+ result.add(userFullInfos.get(RandomUtils.nextInt(start, end)));
+ });
+ } else {
+ result.addAll(userFullInfos);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * 构建邀请规则
+ *
+ * @param inviteRule 邀请规则
+ * @param meetingId 会议ID
+ * @return {@link ExpertInviteRule}
+ * @author WendyYang
+ **/
+ private static ExpertInviteRule getExpertInviteRule(AbstractInviteRule inviteRule, Long meetingId) {
+ ExpertInviteRule rule = new ExpertInviteRule();
+ rule.setInviteRule(JSONObject.toJSONString(inviteRule));
+ rule.setInviteCount(inviteRule.getCount());
+ rule.setInviteType(inviteRule.getInviteType());
+ rule.setMeetingId(meetingId);
+ return rule;
+ }
+
+ public Map checkAppointExpertConflictWithAvoidRule(AppointInviteRuleDTO appointRule, AvoidInfoDTO avoidRule) {
+ if (appointRule == null) {
+ return Collections.emptyMap();
+ }
+ List expertInfos = expertUserFullInfoService.listByUserId(appointRule.getExpertIds());
+ Map infoMap = CollUtils.listToMap(expertInfos, ExpertUserFullInfo::getUserId);
+ if (avoidRule == null) {
+ return infoMap;
+ }
+ Map countMap = new HashMap<>(16);
+ infoMap.forEach((key, userFullInfo) -> {
+ if (CollectionUtils.isNotEmpty(avoidRule.getExpertIds())) {
+ boolean contains = avoidRule.getExpertIds().contains(key);
+ Assert.isTrue(!contains, "已回避的专家不可被指定邀请");
+ }
+ if (CollectionUtils.isNotEmpty(avoidRule.getCompanyIds())) {
+ boolean contains = avoidRule.getCompanyIds().contains(userFullInfo.getCompany());
+ Assert.isTrue(!contains, "回避单位的专家不可出现在指定邀请名单中");
+ }
+ if (avoidRule.getAvoidMates()) {
+ Integer oldValue = countMap.put(userFullInfo.getCompany(), 1);
+ Assert.isNull(oldValue, "不可选择同单位的多个专家");
+ }
+ });
+ return infoMap;
+ }
+
+
+ /**
+ * 专家抽取(会议创建时抽取)
+ *
+ * @param randomRules 随机抽取规则
+ * @param appointRule 指定抽取规则
+ * @param avoid 回避信息
+ * @author WendyYang
+ **/
+ public void expertInviteByMeetingCreate(Meeting meeting,
+ List randomRules,
+ AppointInviteRuleDTO appointRule,
+ AvoidInfoDTO avoid) {
+ Map appointUser = checkAppointExpertConflictWithAvoidRule(appointRule, avoid);
+ List expertInserts = new ArrayList<>();
+ boolean appointed = appointRule != null;
+ // 处理随机抽取规则
+ if (CollectionUtils.isNotEmpty(randomRules)) {
+ List randoms = new ArrayList<>();
+ List expertsByRandom = new ArrayList<>();
+ List tempExpertIdSelected = new ArrayList<>();
+ if (appointed) {
+ tempExpertIdSelected.addAll(appointRule.getExpertIds());
+ }
+ LocalDateTime startTime = meeting.getStartTime(), endTime = meeting.getEndTime();
+ randomRules.forEach(rule -> {
+ ExpertChooseDTO tempExperts = expertInviteByRandomRule(avoid, rule, tempExpertIdSelected, startTime, endTime);
+ expertsByRandom.add(tempExperts);
+ tempExpertIdSelected.addAll(CollUtils.fieldList(tempExperts.getExperts(), ExpertUserFullInfo::getUserId));
+ randoms.add(getExpertInviteRule(rule, meeting.getId()));
+ });
+ inviteRuleService.saveBatch(randoms);
+ for (int i = 0; i < expertsByRandom.size(); i++) {
+ Long ruleId = randoms.get(i).getId();
+ expertsByRandom.get(i).getExperts().forEach(w -> {
+ MeetingExpert expert = ExpertInviteBuilder.getExpertByRandom(meeting.getId(), w, ruleId);
+ expert.setStatus(ExpertAttendStatus.NOTICING.getCode());
+ expertInserts.add(expert);
+ });
+ }
+ yxtCallOrSmsHelper.callByMeetingExperts(meeting, expertInserts);
+ }
+ if (appointed) {
+ // 处理指定抽取规则
+ ExpertInviteRule appoint = getExpertInviteRule(appointRule, meeting.getId());
+ inviteRuleService.save(appoint);
+ Long ruleId = appoint.getId();
+ appointRule.getExpertIds().forEach(w -> {
+ ExpertUserFullInfo info = appointUser.get(w);
+ MeetingExpert expert = ExpertInviteBuilder.getExpertByAppoint(meeting.getId(), info, ruleId);
+ expert.setStatus(ExpertAttendStatus.NOTICING.getCode());
+ expertInserts.add(expert);
+ });
+ }
+ meetingExpertService.saveBatch(expertInserts);
+ }
+
+}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingExpertManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingExpertManage.java
new file mode 100644
index 0000000..b297101
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingExpertManage.java
@@ -0,0 +1,25 @@
+package com.ningdatech.pmapi.meeting.manage;
+
+import com.ningdatech.pmapi.meeting.helper.MeetingManageHelper;
+import com.ningdatech.pmapi.meeting.service.IMeetingExpertEvaluationService;
+import com.ningdatech.pmapi.meeting.service.IMeetingExpertService;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Component;
+
+/**
+ *
+ * MeetingExpertManage
+ *
+ *
+ * @author WendyYang
+ * @since 10:04 2022/8/24
+ */
+@Component
+@AllArgsConstructor
+public class MeetingExpertManage {
+
+ private final IMeetingExpertService meetingExpertService;
+ private final IMeetingExpertEvaluationService meetingExpertEvaluationService;
+ private final MeetingManageHelper meetingManageHelper;
+
+}
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
new file mode 100644
index 0000000..b7df186
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/meeting/manage/MeetingManage.java
@@ -0,0 +1,708 @@
+package com.ningdatech.pmapi.meeting.manage;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.SecureUtil;
+import com.alibaba.fastjson.JSON;
+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.PageVo;
+import com.ningdatech.basic.util.CollUtils;
+import com.ningdatech.basic.util.ValidUtil;
+import com.ningdatech.cache.lock.DistributedLock;
+import com.ningdatech.file.entity.vo.result.AttachFileVo;
+import com.ningdatech.file.service.FileService;
+import com.ningdatech.pmapi.common.util.BizUtils;
+import com.ningdatech.pmapi.common.util.StrUtils;
+import com.ningdatech.pmapi.expert.entity.ExpertUserFullInfo;
+import com.ningdatech.pmapi.expert.helper.PermissionCheckHelper;
+import com.ningdatech.pmapi.expert.service.IExpertUserFullInfoService;
+import com.ningdatech.pmapi.meeting.builder.ExpertInviteBuilder;
+import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteAvoidRule;
+import com.ningdatech.pmapi.meeting.entity.domain.ExpertInviteRule;
+import com.ningdatech.pmapi.meeting.entity.domain.Meeting;
+import com.ningdatech.pmapi.meeting.entity.domain.MeetingExpert;
+import com.ningdatech.pmapi.meeting.entity.dto.*;
+import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertAttendStatus;
+import com.ningdatech.pmapi.meeting.entity.enumeration.ExpertInviteType;
+import com.ningdatech.pmapi.meeting.entity.enumeration.MeetingStatus.Manager;
+import com.ningdatech.pmapi.meeting.entity.req.*;
+import com.ningdatech.pmapi.meeting.entity.vo.*;
+import com.ningdatech.pmapi.meeting.entity.vo.ExpertInviteDetailVO.ExpertAttendListItemVO;
+import com.ningdatech.pmapi.meeting.entity.vo.ExpertInviteDetailVO.RandomInviteListItemVO;
+import com.ningdatech.pmapi.meeting.helper.ExpertInviteHelper;
+import com.ningdatech.pmapi.meeting.helper.MeetingManageHelper;
+import com.ningdatech.pmapi.meeting.helper.YxtCallOrSmsHelper;
+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.meeting.task.ExpertInviteTask;
+import com.ningdatech.pmapi.meta.helper.DictionaryCache;
+import com.ningdatech.pmapi.meta.helper.TagCache;
+import com.ningdatech.pmapi.user.entity.UserInfo;
+import com.ningdatech.pmapi.user.service.IUserInfoService;
+import com.ningdatech.pmapi.user.util.LoginUserUtil;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
+
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.function.Function;
+
+/**
+ *
+ * MeetingManage
+ *
+ *
+ * @author WendyYang
+ * @since 13:35 2022/7/26
+ */
+@Component
+@RequiredArgsConstructor
+public class MeetingManage {
+
+ private final IMeetingService meetingService;
+ private final IExpertInviteAvoidRuleService inviteAvoidRuleService;
+ private final IExpertInviteRuleService inviteRuleService;
+ private final IExpertUserFullInfoService expertUserFullInfoService;
+ private final FileService fileService;
+ private final TagCache tagCache;
+ private final DictionaryCache dictionaryCache;
+ private final IMeetingExpertService meetingExpertService;
+ private final ExpertInviteManage expertInviteManage;
+ private final ExpertInviteTask expertInviteTask;
+ private final MeetingManageHelper meetingManageHelper;
+ private final YxtCallOrSmsHelper yxtCallOrSmsHelper;
+ private final DistributedLock distributedLock;
+ private final PermissionCheckHelper permissionCheckHelper;
+ private final IUserInfoService userInfoService;
+
+ private final ExpertInviteHelper expertInviteHelper;
+ private static final String INVITED_RULE_CREATE = "INVITED_RULE_CREATE:";
+
+ private static final String MEETING_CREATE_KEY = "MEETING_CREATE:";
+
+ /**
+ * 锁定时间10 * 60秒
+ */
+ public static final int RETRY_TIMES = 3;
+
+ public IdVo save(MeetingBasicDTO po) {
+ String md5ByParam = SecureUtil.md5(po.toString());
+ String key = MEETING_CREATE_KEY + md5ByParam;
+ if (!distributedLock.lock(key, RETRY_TIMES)) {
+ throw BizException.wrap("会议正在创建中");
+ }
+ try {
+ Meeting meeting = BeanUtil.copyProperties(po, Meeting.class);
+ meeting.setStatus(Manager.UNCOMPLETED.getCode());
+ if (CollectionUtils.isNotEmpty(po.getAttachmentIds())) {
+ meeting.setAttachment(CollUtils.joinByComma(po.getAttachmentIds()));
+ }
+ Long userId = LoginUserUtil.getUserId();
+ UserInfo userInfo = userInfoService.getById(userId);
+ meeting.setHoldCompany(po.getInviterCompany());
+ meeting.setAuthor(userInfo.getUsername());
+ meeting.setInvited(Boolean.FALSE);
+ meeting.setStopRandomInvite(true);
+ meeting.setSendMeetingNotice(false);
+ meetingService.save(meeting);
+ return IdVo.of(meeting.getId());
+ } finally {
+ distributedLock.releaseLock(key);
+ }
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ public void expertInviteByCreate(ExpertInviteCreateReq req) {
+ // 未传递指定邀请专家直接忽略
+ if (req.getAppointRule() != null && CollectionUtils.isEmpty(req.getAppointRule().getExpertIds())) {
+ Assert.isTrue(CollectionUtils.isNotEmpty(req.getRandomRules()), "未指定抽取规则");
+ req.setAppointRule(null);
+ }
+ String key = INVITED_RULE_CREATE + req.getMeetingId();
+ if (!distributedLock.lock(key, RETRY_TIMES)) {
+ throw BizException.wrap("不可重复进行专家抽取");
+ }
+ try {
+ Meeting meeting = meetingService.getById(req.getMeetingId());
+ Assert.isTrue(!meeting.getInvited(), "不可重复进行专家抽取");
+ ExpertCountOnChangeVO countOnChange = expertCountOnChange(req);
+ for (int i = 0; i < req.getRandomRules().size(); i++) {
+ Integer checkCount = countOnChange.getCountList().get(i);
+ Integer inviteCount = req.getRandomRules().get(i).getCount();
+ Assert.isTrue(checkCount >= inviteCount, "可供抽取的专家数量不足");
+ }
+ AvoidInfoDTO avoidInfo = req.getAvoidInfo();
+ expertInviteManage.expertInviteByMeetingCreate(meeting, req.getRandomRules(), req.getAppointRule(), avoidInfo);
+ LambdaUpdateWrapper updater = Wrappers.lambdaUpdate(Meeting.class)
+ .set(Meeting::getInvited, Boolean.TRUE)
+ .eq(Meeting::getId, req.getMeetingId());
+ if (CollectionUtils.isNotEmpty(req.getRandomRules())) {
+ expertInviteTask.addInviteExpertTaskByMeetingCreate(meeting.getId(), 5);
+ updater.set(Meeting::getStopRandomInvite, false);
+ }
+ meetingService.update(updater);
+ // 回避规则
+ if (avoidInfo != null) {
+ ExpertInviteAvoidRule avoidRule = new ExpertInviteAvoidRule();
+ avoidRule.setMeetingId(meeting.getId());
+ avoidRule.setAvoidMates(avoidInfo.getAvoidMates());
+ avoidRule.setCompanyIds(CollUtils.joinByComma(avoidInfo.getCompanyIds()));
+ if (CollectionUtils.isNotEmpty(avoidInfo.getExpertIds())) {
+ avoidRule.setExpertIds(CollUtils.joinByComma(avoidInfo.getExpertIds()));
+ }
+ inviteAvoidRuleService.save(avoidRule);
+ }
+ } finally {
+ distributedLock.releaseLock(key);
+ }
+ }
+
+ /**
+ * 抽取数量校验
+ *
+ * @param po 抽取参数
+ * @return {@link ExpertCountOnChangeVO}
+ * @author WendyYang
+ **/
+ public ExpertCountOnChangeVO expertCountOnChange(ExpertInviteCreateReq po) {
+ // 未传递指定邀请专家直接忽略
+ if (po.getAppointRule() != null && CollUtil.isEmpty(po.getAppointRule().getExpertIds())) {
+ Assert.isTrue(CollUtil.isNotEmpty(po.getRandomRules()), "未指定抽取规则");
+ po.setAppointRule(null);
+ }
+ boolean appointed = po.getAppointRule() != null;
+ expertInviteManage.checkAppointExpertConflictWithAvoidRule(po.getAppointRule(), po.getAvoidInfo());
+ Meeting meeting = meetingService.getById(po.getMeetingId());
+ ExpertCountOnChangeVO resultCount = new ExpertCountOnChangeVO();
+ resultCount.setStatus(true);
+ resultCount.setCountList(new ArrayList<>());
+ // 参数校验
+ String errMsg = ValidUtil.validFast(po, AbstractInviteRule.CountCheck.class);
+ if (errMsg != null) {
+ resultCount.setStatus(false);
+ resultCount.setMessage(errMsg);
+ return resultCount;
+ }
+ List expertIdsChoose = new ArrayList<>();
+ if (appointed) {
+ expertIdsChoose.addAll(po.getAppointRule().getExpertIds());
+ }
+ for (RandomInviteRuleDTO randomRule : po.getRandomRules()) {
+ ExpertChooseDTO chooseExpert = expertInviteManage.expertInviteByRandomRule(po.getAvoidInfo(),
+ randomRule, expertIdsChoose, meeting.getStartTime(), meeting.getEndTime());
+ resultCount.addCountList(chooseExpert.getTotal());
+ }
+ return resultCount;
+ }
+
+ /**
+ * 专家会议列表
+ *
+ * @param req 查询参数
+ * @return 会议列表
+ * @author WendyYang
+ **/
+ 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()) {
+ return PageVo.empty();
+ }
+ Map mapByMeetingId = new HashMap<>(16);
+ expertDtoList.forEach(w -> mapByMeetingId.put(w.getMeetingId(), w));
+ LambdaQueryWrapper query = new LambdaQueryWrapper()
+ .orderByDesc(Meeting::getCreateOn)
+ .in(Meeting::getId, mapByMeetingId.keySet())
+ .ne(Meeting::getStatus, Manager.CANCELED.getCode());
+ if (req.getExpertId() == null) {
+ meetingManageHelper.buildMeetingQuery(query, req);
+ }
+ Page page = meetingService.page(req.page(), query);
+ if (page.getTotal() == 0) {
+ return PageVo.empty();
+ }
+ PageVo result = new PageVo<>(new ArrayList<>(), page.getTotal());
+ page.getRecords().forEach(meeting -> {
+ MeetingByManagerVO item = meetingManageHelper.buildByMeeting(meeting);
+ MeetingAndAttendStatusDTO info = mapByMeetingId.get(meeting.getId());
+ item.setAttendStatus(meetingManageHelper.getExpertAttendStatus(info));
+ result.getRecords().add(item);
+ });
+ return result;
+ }
+
+ /**
+ * 管理员会议列表
+ *
+ * @param po 查询参数
+ * @return 会议列表
+ * @author WendyYang
+ */
+ public PageVo meetingListByManager(MeetingListReq po) {
+ LambdaQueryWrapper query = new LambdaQueryWrapper()
+ .orderByDesc(Meeting::getCreateOn);
+ // 补充逻辑 如果拥有超级管理员权限可以看到所有事务
+ if (!permissionCheckHelper.isSuperAdmin()) {
+ query.eq(Meeting::getCreateBy, LoginUserUtil.getUserId());
+ }
+ query.eq(po.getStatus() != null, Meeting::getStatus, po.getStatus());
+ meetingManageHelper.buildMeetingQuery(query, po);
+ Page page = meetingService.page(po.page(), query);
+ if (page.getTotal() == 0) {
+ return PageVo.empty();
+ }
+ PageVo result = new PageVo<>(new ArrayList<>(), page.getTotal());
+ Map countConfirmMap = new HashMap<>(16);
+ List meetingIds = CollUtils.fieldList(page.getRecords(), Meeting::getId);
+ countConfirmMap.putAll(meetingExpertService.countConfirmedByMeetingIds(meetingIds));
+ page.getRecords().forEach(meeting -> {
+ MeetingByManagerVO item = meetingManageHelper.buildByMeeting(meeting);
+ CountConfirmByMeetingIdDTO confirm = countConfirmMap.get(meeting.getId());
+ if (confirm == null) {
+ item.setInviteCount(0);
+ item.setConfirmCount(0);
+ } else {
+ item.setInviteCount(confirm.getTotal());
+ item.setConfirmCount(confirm.getConfirmed());
+ }
+ result.getRecords().add(item);
+ });
+ return result;
+ }
+
+ public MeetingDetailBasicVO getMeetingBasicInfo(Long meetingId) {
+ Meeting meeting = meetingService.getById(meetingId);
+ if (Objects.isNull(meeting)) {
+ throw new BizException("该会议信息不存在");
+ }
+ String attachment = meeting.getAttachment();
+ List attachments = new ArrayList<>();
+ if (StrUtils.isNotBlank(attachment)) {
+ attachments.addAll(fileService.getByIds(BizUtils.splitToLong(attachment)));
+ }
+ Integer attendStatus = null;
+ if (LoginUserUtil.isExpert()) {
+ List meIds = Collections.singletonList(meetingId);
+ List status = meetingExpertService.listByExpertIdAndStatus(LoginUserUtil.getUserId(), null, meIds);
+ if (status.isEmpty()) {
+ throw BizException.wrap("您未被邀请参加次会议");
+ }
+ attendStatus = meetingManageHelper.getExpertAttendStatus(status.get(0));
+ }
+ return MeetingDetailBasicVO.builder()
+ .id(meeting.getId())
+ .name(meeting.getName())
+ .type(meeting.getType())
+ .typeName(dictionaryCache.getByCode(meeting.getType()).getName())
+ .author(meeting.getAuthor())
+ .startTime(meeting.getStartTime())
+ .endTime(meeting.getEndTime())
+ .createOn(meeting.getCreateOn())
+ .contact(meeting.getContact())
+ .connecter(meeting.getConnecter())
+ .description(meeting.getDescription())
+ .remark(meeting.getRemark())
+ .address(meeting.getRegionDetail())
+ .attachments(attachments)
+ .status(meeting.getStatus())
+ .attendStatus(attendStatus)
+ .cancelRemark(meeting.getCancelRemark())
+ .createBy(meeting.getAuthor())
+ .inviterCompany(meeting.getHoldCompany())
+ .invited(meeting.getInvited())
+ .sendMeetingNotice(meeting.getSendMeetingNotice())
+ .build();
+ }
+
+ public void uploadMeetingResult(MeetingResultReq po) {
+ LambdaUpdateWrapper updater = Wrappers.lambdaUpdate(Meeting.class)
+ .eq(Meeting::getId, po.getMeetingId())
+ .set(Meeting::getResultDescription, po.getResultDescription())
+ .set(Meeting::getStatus, Manager.COMPLETED.getCode());
+ if (CollectionUtils.isNotEmpty(po.getAttachments())) {
+ updater.set(Meeting::getResultAttachment, CollUtils.joinByComma(po.getAttachments()));
+ }
+ meetingService.update(updater);
+ }
+
+ public MeetingResultVO meetingResultDetail(Long meetingId) {
+ LambdaQueryWrapper query = Wrappers.lambdaQuery(Meeting.class)
+ .select(Meeting::getResultAttachment, Meeting::getResultDescription)
+ .eq(Meeting::getId, meetingId);
+ Meeting meeting = meetingService.getOne(query);
+ MeetingResultVO result = new MeetingResultVO();
+ result.setMeetingId(meetingId);
+ result.setResultDescription(meeting.getResultDescription());
+ result.setAttachments(new ArrayList<>());
+ if (StrUtils.isNotBlank(meeting.getResultAttachment())) {
+ List fileIds = BizUtils.splitToLong(meeting.getResultAttachment());
+ result.getAttachments().addAll(fileService.getByIds(fileIds));
+ }
+ return result;
+ }
+
+
+ public ExpertInviteDetailVO inviteDetail(Long meetingId) {
+ ExpertInviteDetailVO result = new ExpertInviteDetailVO();
+ Meeting meeting = meetingService.getById(meetingId);
+ if (Objects.isNull(meeting)) {
+ throw new BizException("该会议信息不存在");
+ }
+ result.setHasStopInvite(meeting.getStopRandomInvite());
+ result.setHasSendNotice(meeting.getSendMeetingNotice());
+ List experts = meetingExpertService.listByMeetingId(meetingId);
+ if (experts.isEmpty()) {
+ return result;
+ }
+ List randomList = new ArrayList<>();
+ List