Преглед на файлове

Merge remote-tracking branch 'origin/master'

Zimo преди 9 часа
родител
ревизия
26e4481b90

+ 1 - 0
yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstant.java

@@ -104,5 +104,6 @@ public interface ErrorCodeConstant{
     ErrorCode IOT_RY_DAILY_REPORT_DETAIL_NOT_EXISTS = new ErrorCode(279, "瑞鹰日报明细(生产动态拆分)不存在");
     ErrorCode IOT_RD_NO_WORK_DAILY_REPORT_EXISTS = new ErrorCode(280, "无工作量日报已经存在");
     ErrorCode IOT_OPERATION_MEETING_NOT_EXISTS = new ErrorCode(281, "生产运营会不存在");
+    ErrorCode IOT_OPERATION_MEETING_EXISTS = new ErrorCode(281, "当期生产运营会已经存在");
     ErrorCode IOT_OPERATION_MEETING_DETAIL_NOT_EXISTS = new ErrorCode(282, "生产运营会明细不存在");
 }

+ 2 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/config/PmsDataPermissionConfiguration.java

@@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.pms.dal.dataobject.inspect.IotInspectPlanDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotlockstock.IotLockStockDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeeting.IotOperationMeetingDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeetingdetail.IotOperationMeetingDetailDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotrddailyreport.IotRdDailyReportDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotrhdailyreport.IotRhDailyReportDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotsapstock.IotSapStockDO;
@@ -67,6 +68,7 @@ public class PmsDataPermissionConfiguration {
             rule.addDeptColumn(IotAccidentReportDO.class, "dept_id");
             rule.addDeptColumn(IotHazardDO.class, "dept_id");
             rule.addDeptColumn(IotOperationMeetingDO.class, "dept_id");
+            rule.addDeptColumn(IotOperationMeetingDetailDO.class, "dept_id");
             // user
 //            rule.addUserColumn(SupplierDO.class);
             rule.addUserColumn(AdminUserDO.class, "id");

+ 18 - 6
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeeting/IotOperationMeetingController.java

@@ -32,10 +32,7 @@ import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
 import java.math.BigDecimal;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -93,7 +90,14 @@ public class IotOperationMeetingController {
     public CommonResult<IotOperationMeetingRespVO> getIotOperationMeeting(@RequestParam("id") Long id) {
         IotOperationMeetingDO iotOperationMeeting = iotOperationMeetingService.getIotOperationMeeting(id);
         return success(buildMeetingResp(iotOperationMeeting));
-        // return success(BeanUtils.toBean(iotOperationMeeting, IotOperationMeetingRespVO.class));
+    }
+
+    @GetMapping("/previousWorkPlan")
+    @Operation(summary = "填报运营会议明细时查询上期填写的工作计划")
+    @PreAuthorize("@ss.hasPermission('pms:iot-operation-meeting:query')")
+    public CommonResult<IotOperationMeetingDetailRespVO> previousWorkPlan(@Valid IotOperationMeetingDetailPageReqVO pageReqVO) {
+        IotOperationMeetingDetailRespVO result = iotOperationMeetingService.previousWorkPlan(pageReqVO);
+        return success(result);
     }
 
     /**
@@ -132,7 +136,15 @@ public class IotOperationMeetingController {
     public CommonResult<PageResult<IotOperationMeetingRespVO>> getIotOperationMeetingPage(@Valid IotOperationMeetingPageReqVO pageReqVO) {
         PageResult<IotOperationMeetingDO> pageResult = iotOperationMeetingService.getIotOperationMeetingPage(pageReqVO);
         return success(new PageResult<>(buildMeetingDetails(pageResult.getList()), pageResult.getTotal()));
-        // return success(BeanUtils.toBean(pageResult, IotOperationMeetingRespVO.class));
+    }
+
+    @GetMapping("/cachedProjects")
+    @Operation(summary = "查询当前公司填写过的项目名称 缓存项目名称")
+    @PreAuthorize("@ss.hasPermission('pms:iot-operation-meeting:query')")
+    public CommonResult<Set<String>> cachedProjects() {
+        // 将当前公司填写过的项目名称作为下拉列表返回 提高填写效率
+        Set<String> cachedProjects = iotOperationMeetingService.cachedProjects();
+        return success(cachedProjects);
     }
 
     /**

+ 6 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeetingdetail/vo/IotOperationMeetingDetailPageReqVO.java

@@ -16,6 +16,9 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
 @ToString(callSuper = true)
 public class IotOperationMeetingDetailPageReqVO extends PageParam {
 
+    @Schema(description = "运营会明细id", example = "25792")
+    private Long Id;
+
     @Schema(description = "运营会id", example = "25792")
     private Long meetingId;
 
@@ -29,6 +32,9 @@ public class IotOperationMeetingDetailPageReqVO extends PageParam {
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] meetingDate;
 
+    @Schema(description = "项目名称")
+    private String projectName;
+
     @Schema(description = "会议期次")
     private String meetingSeries;
 

+ 22 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotoperationmeeting/IotOperationMeetingMapper.java

@@ -7,6 +7,9 @@ import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeeting.IotOperati
 import org.apache.ibatis.annotations.Mapper;
 import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo.*;
 
+import java.time.LocalDateTime;
+import java.util.List;
+
 /**
  * 生产运营会 Mapper
  *
@@ -42,4 +45,23 @@ public interface IotOperationMeetingMapper extends BaseMapperX<IotOperationMeeti
                 .orderByDesc(IotOperationMeetingDO::getId));
     }
 
+    /**
+     * 查询:校验当前公司 当前日期所属年 当前期次是否有重复的记录
+     */
+    default List<IotOperationMeetingDO> selectExistMeetingByYearAndSort(IotOperationMeetingPageReqVO reqVO) {
+        LocalDateTime[] createTimeArr = reqVO.getCreateTime();
+        if (createTimeArr == null || createTimeArr.length == 0) {
+            return null;
+        }
+        // 取年份(用数组第一个时间即可)
+        int year = createTimeArr[0].getYear();
+
+        return selectList(new LambdaQueryWrapperX<IotOperationMeetingDO>()
+                // 1. 匹配 createTime 所在年份
+                .apply("YEAR(create_time) = {0}", year)
+                // 2. sort 查询
+                .eq(IotOperationMeetingDO::getSort, reqVO.getSort())
+        );
+    }
+
 }

+ 27 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotoperationmeetingdetail/IotOperationMeetingDetailMapper.java

@@ -1,11 +1,14 @@
 package cn.iocoder.yudao.module.pms.dal.mysql.iotoperationmeetingdetail;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingdetail.vo.IotOperationMeetingDetailPageReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeetingdetail.IotOperationMeetingDetailDO;
 import org.apache.ibatis.annotations.Mapper;
-import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingdetail.vo.*;
+
+import java.time.LocalDateTime;
+import java.util.List;
 
 /**
  * 生产运营会明细 Mapper
@@ -21,6 +24,7 @@ public interface IotOperationMeetingDetailMapper extends BaseMapperX<IotOperatio
                 .inIfPresent(IotOperationMeetingDetailDO::getMeetingId, reqVO.getMeetingIds())
                 .eqIfPresent(IotOperationMeetingDetailDO::getCompanyId, reqVO.getCompanyId())
                 .eqIfPresent(IotOperationMeetingDetailDO::getDeptId, reqVO.getDeptId())
+                .likeIfPresent(IotOperationMeetingDetailDO::getProjectName, reqVO.getProjectName())
                 .betweenIfPresent(IotOperationMeetingDetailDO::getMeetingDate, reqVO.getMeetingDate())
                 .eqIfPresent(IotOperationMeetingDetailDO::getMeetingSeries, reqVO.getMeetingSeries())
                 .eqIfPresent(IotOperationMeetingDetailDO::getCurrentRevenue, reqVO.getCurrentRevenue())
@@ -44,4 +48,25 @@ public interface IotOperationMeetingDetailMapper extends BaseMapperX<IotOperatio
                 .orderByDesc(IotOperationMeetingDetailDO::getId));
     }
 
+    /**
+     * 查询:createTime 所在年份 + projectName 模糊匹配 + sort 最大的记录
+     */
+    default List<IotOperationMeetingDetailDO> selectMaxSortByYearAndProject(IotOperationMeetingDetailPageReqVO reqVO) {
+        LocalDateTime[] createTimeArr = reqVO.getCreateTime();
+        if (createTimeArr == null || createTimeArr.length == 0) {
+            return null;
+        }
+        // 取年份(用数组第一个时间即可)
+        int year = createTimeArr[0].getYear();
+
+        return selectList(new LambdaQueryWrapperX<IotOperationMeetingDetailDO>()
+                // 1. 匹配 createTime 所在年份
+                .apply("YEAR(create_time) = {0}", year)
+                // 2. projectName 模糊查询
+                .eq(IotOperationMeetingDetailDO::getProjectName, reqVO.getProjectName())
+                // 3. 按 sort 倒序 → 取第一条就是最大值
+                .orderByDesc(IotOperationMeetingDetailDO::getSort)
+        );
+    }
+
 }

+ 19 - 3
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotoperationmeeting/IotOperationMeetingService.java

@@ -1,9 +1,15 @@
 package cn.iocoder.yudao.module.pms.service.iotoperationmeeting;
 
-import javax.validation.*;
-import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo.*;
-import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeeting.IotOperationMeetingDO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo.IotOperationMeetingPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo.IotOperationMeetingSaveBatchVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo.IotOperationMeetingSaveReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingdetail.vo.IotOperationMeetingDetailPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingdetail.vo.IotOperationMeetingDetailRespVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeeting.IotOperationMeetingDO;
+
+import javax.validation.Valid;
+import java.util.Set;
 
 /**
  * 生产运营会 Service 接口
@@ -57,4 +63,14 @@ public interface IotOperationMeetingService {
      * @return 保存记录数
      */
     Long saveBatch(IotOperationMeetingSaveBatchVO saveBatchVO);
+
+    /**
+     * 将当前公司填写过的项目名称作为下拉列表返回 提高填写效率
+     */
+    Set<String> cachedProjects();
+
+    /**
+     * 填报运营会议明细时查询上期填写的工作计划
+     */
+    IotOperationMeetingDetailRespVO previousWorkPlan(IotOperationMeetingDetailPageReqVO pageReqVO);
 }

+ 97 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotoperationmeeting/IotOperationMeetingServiceImpl.java

@@ -1,12 +1,17 @@
 package cn.iocoder.yudao.module.pms.service.iotoperationmeeting;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
 import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo.IotOperationMeetingPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo.IotOperationMeetingSaveBatchVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo.IotOperationMeetingSaveReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingdetail.vo.IotOperationMeetingDetailPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingdetail.vo.IotOperationMeetingDetailRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingdetail.vo.IotOperationMeetingDetailSaveReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeeting.IotOperationMeetingDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeetingdetail.IotOperationMeetingDetailDO;
@@ -20,10 +25,11 @@ import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.List;
+import java.time.LocalDateTime;
+import java.util.*;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_OPERATION_MEETING_EXISTS;
 import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_OPERATION_MEETING_NOT_EXISTS;
 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.DEPT_NOT_FOUND;
 
@@ -123,10 +129,31 @@ public class IotOperationMeetingServiceImpl implements IotOperationMeetingServic
         }
         List<Long> meetingIds = new ArrayList<>();
         long resultId = 0l;
+        // 根据 期次 '第8期' 赋值 sort = 8
+        Optional.ofNullable(meeting.getMeetingSeries())
+                .map(s -> s.replaceAll("\\D", "")) // 提取所有数字
+                .filter(StrUtil::isNumeric)    // 确保是数字
+                .map(Integer::valueOf)
+                .ifPresent(meeting::setSort);
+        // 校验当前公司 当前日期所属年 当前期次是否有重复的记录
+        IotOperationMeetingPageReqVO reqVO = new IotOperationMeetingPageReqVO();
+        reqVO.setSort(meeting.getSort());
+        LocalDateTime [] times = {LocalDateTime.now(), LocalDateTime.now()};
+        reqVO.setCreateTime(times);
+        List<IotOperationMeetingDO> meetings = iotOperationMeetingMapper.selectExistMeetingByYearAndSort(reqVO);
+
         if (ObjUtil.isNotEmpty(meeting.getId())) {
             // 更新
             // 校验存在
             validateIotOperationMeetingExists(meeting.getId());
+            // 校验当期运营会议是否有重复
+            if (CollUtil.isNotEmpty(meetings)) {
+                meetings.forEach(mtg -> {
+                    if (!mtg.getId().equals(meeting.getId())) {
+                        throw exception(IOT_OPERATION_MEETING_EXISTS);
+                    }
+                });
+            }
             IotOperationMeetingDO updateObj = BeanUtils.toBean(meeting, IotOperationMeetingDO.class);
             int id = iotOperationMeetingMapper.updateById(updateObj);
             resultId = id;
@@ -137,6 +164,9 @@ public class IotOperationMeetingServiceImpl implements IotOperationMeetingServic
             meetingIds.add(updateObj.getId());
         } else {
             // 新增
+            if (CollUtil.isNotEmpty(meetings)) {
+                throw exception(IOT_OPERATION_MEETING_EXISTS);
+            }
             IotOperationMeetingDO iotOperationMeeting = BeanUtils.toBean(meeting, IotOperationMeetingDO.class);
             int id = iotOperationMeetingMapper.insert(iotOperationMeeting);
             resultId = id;
@@ -151,6 +181,7 @@ public class IotOperationMeetingServiceImpl implements IotOperationMeetingServic
                 detailDO.setId(null);
                 detailDO.setMeetingId(meetingIds.get(0));
                 detailDO.setDeptId(meeting.getDeptId());
+                detailDO.setSort(meeting.getSort());        // 期次索引
                 meetingDetails.add(detailDO);
             });
             iotOperationMeetingDetailMapper.insertBatch(meetingDetails);
@@ -158,4 +189,68 @@ public class IotOperationMeetingServiceImpl implements IotOperationMeetingServic
         return resultId;
     }
 
+    @Override
+    public Set<String> cachedProjects() {
+        Set<String> projectNames = new HashSet<>();
+        // 查询当前登录人所属公司下 填写过的 项目名称
+        IotOperationMeetingDetailPageReqVO reqVO = new IotOperationMeetingDetailPageReqVO();
+        reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        PageResult<IotOperationMeetingDetailDO> meetingPage = iotOperationMeetingDetailMapper.selectPage(reqVO);
+        if (ObjUtil.isNotEmpty(meetingPage)) {
+            List<IotOperationMeetingDetailDO> meetingDetails = meetingPage.getList();
+            if (CollUtil.isNotEmpty(meetingDetails)) {
+                meetingDetails.forEach(detail -> {
+                    projectNames.add(detail.getProjectName());
+                });
+            }
+        }
+        return projectNames;
+    }
+
+    @Override
+    public IotOperationMeetingDetailRespVO previousWorkPlan(IotOperationMeetingDetailPageReqVO pageReqVO) {
+        // 填报运营会议明细时查询上期填写的工作计划
+        String projectName = pageReqVO.getProjectName();
+        Long meetingId = pageReqVO.getMeetingId();   // 会议id
+        Long meetingDetailId = pageReqVO.getId();    // 会议明细id
+        // 如果传了 明细Id 说明是编辑状态 此时 不需要查询上一期次的工作计划
+        // 如果没传 明细Id 说明是新增项目状态 此时需要查询当前公司上一期次相同项目名称的会议明细 下期工作计划
+        // 会议期次 根据 项目名称 期次 查询 当前公司 上一期次(sort-1) 相同项目名称的 ‘下期工作计划-计划工作量’ ‘下期工作计划-重点工作事项’
+        // 没传 明细Id 有2种情况:新建会议 or 编辑会议新增项目
+        // 新建会议(会议id为null) sort 最大的记录即为上一期次的会议
+        // 编辑会议新增项目(会议id不为null) sort 倒序排列 取第2位次的会议即为上一期次的会议
+        if (ObjUtil.isNotEmpty(meetingDetailId) || StrUtil.isBlank(projectName)) {
+            return null;
+        }
+
+        IotOperationMeetingDetailPageReqVO reqVO = new IotOperationMeetingDetailPageReqVO();
+        reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        reqVO.setProjectName(projectName);
+        LocalDateTime [] times = {LocalDateTime.now(), LocalDateTime.now()};
+        reqVO.setCreateTime(times);
+        List<IotOperationMeetingDetailDO> meetingDetails = iotOperationMeetingDetailMapper.selectMaxSortByYearAndProject(reqVO);
+        if (CollUtil.isEmpty(meetingDetails)) {
+            return null;
+        }
+        if (ObjUtil.isEmpty(meetingId)) {
+            // 新建会议
+            // 查询当前用户所属公司最新的会议明细 当前日期所属年
+            // 只取第1条记录
+            return BeanUtils.toBean(meetingDetails.get(0), IotOperationMeetingDetailRespVO.class);
+        }
+        // 编辑会议新增项目
+        // 查询当前的会议的 sort-1 即为上一期会议
+        IotOperationMeetingDO meeting = iotOperationMeetingMapper.selectById(meetingId);
+        if (ObjUtil.isEmpty(meeting)) {
+            return null;
+        }
+
+        Integer lastMeetingSort = meeting.getSort() - 1;
+        return meetingDetails.stream()
+                .filter(detail -> Objects.equals(detail.getSort(), lastMeetingSort))
+                .findFirst()
+                .map(detail -> BeanUtils.toBean(detail, IotOperationMeetingDetailRespVO.class))
+                .orElse(null);
+    }
+
 }