Explorar o código

Merge remote-tracking branch 'origin/master'

Zimo hai 3 días
pai
achega
a1bf8a8b70
Modificáronse 19 ficheiros con 961 adicións e 7 borrados
  1. 1 0
      yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstant.java
  2. 9 1
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeeting/IotOperationMeetingController.java
  3. 13 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeeting/vo/IotOperationMeetingRespVO.java
  4. 5 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeeting/vo/IotOperationMeetingSaveReqVO.java
  5. 93 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeetingattrs/IotOperationMeetingAttrsController.java
  6. 84 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeetingattrs/vo/IotOperationMeetingAttrsPageReqVO.java
  7. 104 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeetingattrs/vo/IotOperationMeetingAttrsRespVO.java
  8. 76 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeetingattrs/vo/IotOperationMeetingAttrsSaveReqVO.java
  9. 6 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeetingdetail/vo/IotOperationMeetingDetailRespVO.java
  10. 5 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeetingdetail/vo/IotOperationMeetingDetailSaveReqVO.java
  11. 9 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotoperationmeeting/IotOperationMeetingDO.java
  12. 114 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotoperationmeetingattrs/IotOperationMeetingAttrsDO.java
  13. 10 1
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotoperationmeetingdetail/IotOperationMeetingDetailDO.java
  14. 44 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotoperationmeetingattrs/IotOperationMeetingAttrsMapper.java
  15. 8 1
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotoperationmeeting/IotOperationMeetingService.java
  16. 253 3
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotoperationmeeting/IotOperationMeetingServiceImpl.java
  17. 55 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotoperationmeetingattrs/IotOperationMeetingAttrsService.java
  18. 71 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotoperationmeetingattrs/IotOperationMeetingAttrsServiceImpl.java
  19. 1 1
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotrhdailyreport/IotRhDailyReportServiceImpl.java

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

@@ -107,4 +107,5 @@ public interface ErrorCodeConstant{
     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, "生产运营会明细不存在");
+    ErrorCode IOT_OPERATION_MEETING_ATTRS_NOT_EXISTS = new ErrorCode(284, "专业公司工作量扩展属性不存在");
 }

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

@@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingdetail.vo
 import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingdetail.vo.IotOperationMeetingDetailRespVO;
 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.iotprojecttaskattrs.IotTaskAttrModelProperty;
 import cn.iocoder.yudao.module.pms.service.iotoperationmeeting.IotOperationMeetingService;
 import cn.iocoder.yudao.module.pms.service.iotoperationmeetingdetail.IotOperationMeetingDetailService;
 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
@@ -95,13 +96,20 @@ public class IotOperationMeetingController {
 
     @GetMapping("/mandatoryOrNot")
     @Operation(summary = "查询当前登录人所在公司是否需要设置 设备利用率 必填")
-    @Parameter(name = "id", description = "编号", required = true, example = "1024")
     @PreAuthorize("@ss.hasPermission('pms:iot-operation-meeting:query')")
     public CommonResult<IotOperationMeetingRespVO> mandatoryOrNot() {
         IotOperationMeetingRespVO iotOperationMeeting = iotOperationMeetingService.mandatoryOrNot();
         return success(iotOperationMeeting);
     }
 
+    @GetMapping("/currentCompanyExtProperties")
+    @Operation(summary = "查询当前登录人所在公司相关的扩展属性")
+    @PreAuthorize("@ss.hasPermission('pms:iot-operation-meeting:query')")
+    public CommonResult<List<IotTaskAttrModelProperty>> currentCompanyExtProperties() {
+        List<IotTaskAttrModelProperty> workloadAttrs = iotOperationMeetingService.currentCompanyExtProperties();
+        return success(workloadAttrs);
+    }
+
     @GetMapping("/previousWorkPlan")
     @Operation(summary = "填报运营会议明细时查询上期填写的工作计划")
     @PreAuthorize("@ss.hasPermission('pms:iot-operation-meeting:query')")

+ 13 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeeting/vo/IotOperationMeetingRespVO.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo;
 
 import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingdetail.vo.IotOperationMeetingDetailRespVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import java.math.BigDecimal;
@@ -96,6 +97,9 @@ public class IotOperationMeetingRespVO {
     @ExcelProperty("需集团协调支持的事项")
     private String support;
 
+    @Schema(description = "不同专业公司的扩展属性值")
+    private List<IotTaskAttrModelProperty> extProperty;
+
     @Schema(description = "排序值")
     @ExcelProperty("排序值")
     private Integer sort;
@@ -123,4 +127,13 @@ public class IotOperationMeetingRespVO {
 
     @Schema(description = "是否累计财务数据", example = "true累计 false不累计")
     private boolean cumulative;
+
+    @Schema(description = "本期收入环比", example = "0.45")
+    private BigDecimal revenuePeriodOnPeriod;
+
+    @Schema(description = "本期挂账环比", example = "0.45")
+    private BigDecimal onAccountPeriodOnPeriod;
+
+    @Schema(description = "本期回款环比", example = "0.45")
+    private BigDecimal paymentPeriodOnPeriod;
 }

+ 5 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeeting/vo/IotOperationMeetingSaveReqVO.java

@@ -1,9 +1,11 @@
 package cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo;
 
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.List;
 
 @Schema(description = "管理后台 - 生产运营会新增/修改 Request VO")
 @Data
@@ -69,6 +71,9 @@ public class IotOperationMeetingSaveReqVO {
     @Schema(description = "需集团协调支持的事项")
     private String support;
 
+    @Schema(description = "不同专业公司的扩展属性")
+    private List<IotTaskAttrModelProperty> extProperty;
+
     @Schema(description = "排序值")
     private Integer sort;
 

+ 93 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeetingattrs/IotOperationMeetingAttrsController.java

@@ -0,0 +1,93 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingattrs;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+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.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingattrs.vo.IotOperationMeetingAttrsPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingattrs.vo.IotOperationMeetingAttrsRespVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingattrs.vo.IotOperationMeetingAttrsSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeetingattrs.IotOperationMeetingAttrsDO;
+import cn.iocoder.yudao.module.pms.service.iotoperationmeetingattrs.IotOperationMeetingAttrsService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 专业公司工作量扩展属性")
+@RestController
+@RequestMapping("/pms/iot-operation-meeting-attrs")
+@Validated
+public class IotOperationMeetingAttrsController {
+
+    @Resource
+    private IotOperationMeetingAttrsService iotOperationMeetingAttrsService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建专业公司工作量扩展属性")
+    @PreAuthorize("@ss.hasPermission('pms:iot-operation-meeting-attrs:create')")
+    public CommonResult<Long> createIotOperationMeetingAttrs(@Valid @RequestBody IotOperationMeetingAttrsSaveReqVO createReqVO) {
+        return success(iotOperationMeetingAttrsService.createIotOperationMeetingAttrs(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新专业公司工作量扩展属性")
+    @PreAuthorize("@ss.hasPermission('pms:iot-operation-meeting-attrs:update')")
+    public CommonResult<Boolean> updateIotOperationMeetingAttrs(@Valid @RequestBody IotOperationMeetingAttrsSaveReqVO updateReqVO) {
+        iotOperationMeetingAttrsService.updateIotOperationMeetingAttrs(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除专业公司工作量扩展属性")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('pms:iot-operation-meeting-attrs:delete')")
+    public CommonResult<Boolean> deleteIotOperationMeetingAttrs(@RequestParam("id") Long id) {
+        iotOperationMeetingAttrsService.deleteIotOperationMeetingAttrs(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得专业公司工作量扩展属性")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('pms:iot-operation-meeting-attrs:query')")
+    public CommonResult<IotOperationMeetingAttrsRespVO> getIotOperationMeetingAttrs(@RequestParam("id") Long id) {
+        IotOperationMeetingAttrsDO iotOperationMeetingAttrs = iotOperationMeetingAttrsService.getIotOperationMeetingAttrs(id);
+        return success(BeanUtils.toBean(iotOperationMeetingAttrs, IotOperationMeetingAttrsRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得专业公司工作量扩展属性分页")
+    @PreAuthorize("@ss.hasPermission('pms:iot-operation-meeting-attrs:query')")
+    public CommonResult<PageResult<IotOperationMeetingAttrsRespVO>> getIotOperationMeetingAttrsPage(@Valid IotOperationMeetingAttrsPageReqVO pageReqVO) {
+        PageResult<IotOperationMeetingAttrsDO> pageResult = iotOperationMeetingAttrsService.getIotOperationMeetingAttrsPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, IotOperationMeetingAttrsRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出专业公司工作量扩展属性 Excel")
+    @PreAuthorize("@ss.hasPermission('pms:iot-operation-meeting-attrs:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportIotOperationMeetingAttrsExcel(@Valid IotOperationMeetingAttrsPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<IotOperationMeetingAttrsDO> list = iotOperationMeetingAttrsService.getIotOperationMeetingAttrsPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "专业公司工作量扩展属性.xls", "数据", IotOperationMeetingAttrsRespVO.class,
+                        BeanUtils.toBean(list, IotOperationMeetingAttrsRespVO.class));
+    }
+
+}

+ 84 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeetingattrs/vo/IotOperationMeetingAttrsPageReqVO.java

@@ -0,0 +1,84 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingattrs.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 专业公司工作量扩展属性分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class IotOperationMeetingAttrsPageReqVO extends PageParam {
+
+    @Schema(description = "日报扩展模板id", example = "30140")
+    private Long templateId;
+
+    @Schema(description = "公司id", example = "15842")
+    private Long deptId;
+
+    @Schema(description = "项目id", example = "3286")
+    private Long projectId;
+
+    @Schema(description = "项目类别(钻井 修井 注氮 酸化压裂 ...)")
+    private String projectClassification;
+
+    @Schema(description = "井型", example = "2")
+    private String wellType;
+
+    @Schema(description = "井别")
+    private String wellCategory;
+
+    @Schema(description = "施工工艺")
+    private String technique;
+
+    @Schema(description = "属性名称", example = "芋艿")
+    private String name;
+
+    @Schema(description = "属性标识符")
+    private String identifier;
+
+    @Schema(description = "数据类型(double text textarea date dropdown)", example = "2")
+    private String dataType;
+
+    @Schema(description = "是否必填(0非必填 1必填)")
+    private Integer required;
+
+    @Schema(description = "单位(MPa)")
+    private String unit;
+
+    @Schema(description = "访问模式(r读  w写)")
+    private String accessMode;
+
+    @Schema(description = "默认值")
+    private String defaultValue;
+
+    @Schema(description = "最大值")
+    private String maxValue;
+
+    @Schema(description = "最小值")
+    private String minValue;
+
+    @Schema(description = "不同专业公司的扩展属性")
+    private String extProperty;
+
+    @Schema(description = "排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "你说的对")
+    private String remark;
+
+    @Schema(description = "状态(0启用 1禁用)", example = "2")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 104 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeetingattrs/vo/IotOperationMeetingAttrsRespVO.java

@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingattrs.vo;
+
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 专业公司工作量扩展属性 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotOperationMeetingAttrsRespVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "22098")
+    @ExcelProperty("主键id")
+    private Long id;
+
+    @Schema(description = "日报扩展模板id", example = "30140")
+    @ExcelProperty("日报扩展模板id")
+    private Long templateId;
+
+    @Schema(description = "公司id", example = "15842")
+    @ExcelProperty("公司id")
+    private Long deptId;
+
+    @Schema(description = "项目id", example = "3286")
+    @ExcelProperty("项目id")
+    private Long projectId;
+
+    @Schema(description = "项目类别(钻井 修井 注氮 酸化压裂 ...)")
+    @ExcelProperty("项目类别(钻井 修井 注氮 酸化压裂 ...)")
+    private String projectClassification;
+
+    @Schema(description = "井型", example = "2")
+    @ExcelProperty("井型")
+    private String wellType;
+
+    @Schema(description = "井别")
+    @ExcelProperty("井别")
+    private String wellCategory;
+
+    @Schema(description = "施工工艺")
+    @ExcelProperty("施工工艺")
+    private String technique;
+
+    @Schema(description = "属性名称", example = "芋艿")
+    @ExcelProperty("属性名称")
+    private String name;
+
+    @Schema(description = "属性标识符")
+    @ExcelProperty("属性标识符")
+    private String identifier;
+
+    @Schema(description = "数据类型(double text textarea date dropdown)", example = "2")
+    @ExcelProperty("数据类型(double text textarea date dropdown)")
+    private String dataType;
+
+    @Schema(description = "是否必填(0非必填 1必填)")
+    @ExcelProperty("是否必填(0非必填 1必填)")
+    private Integer required;
+
+    @Schema(description = "单位(MPa)")
+    @ExcelProperty("单位(MPa)")
+    private String unit;
+
+    @Schema(description = "访问模式(r读  w写)")
+    @ExcelProperty("访问模式(r读  w写)")
+    private String accessMode;
+
+    @Schema(description = "默认值")
+    @ExcelProperty("默认值")
+    private String defaultValue;
+
+    @Schema(description = "最大值")
+    @ExcelProperty("最大值")
+    private String maxValue;
+
+    @Schema(description = "最小值")
+    @ExcelProperty("最小值")
+    private String minValue;
+
+    @Schema(description = "不同专业公司的扩展属性")
+    @ExcelProperty("不同专业公司的扩展属性")
+    private IotTaskAttrModelProperty extProperty;
+
+    @Schema(description = "排序值")
+    @ExcelProperty("排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "你说的对")
+    @ExcelProperty("备注")
+    private String remark;
+
+    @Schema(description = "状态(0启用 1禁用)", example = "2")
+    @ExcelProperty("状态(0启用 1禁用)")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 76 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotoperationmeetingattrs/vo/IotOperationMeetingAttrsSaveReqVO.java

@@ -0,0 +1,76 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingattrs.vo;
+
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+
+@Schema(description = "管理后台 - 专业公司工作量扩展属性新增/修改 Request VO")
+@Data
+public class IotOperationMeetingAttrsSaveReqVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "22098")
+    private Long id;
+
+    @Schema(description = "日报扩展模板id", example = "30140")
+    private Long templateId;
+
+    @Schema(description = "公司id", example = "15842")
+    private Long deptId;
+
+    @Schema(description = "项目id", example = "3286")
+    private Long projectId;
+
+    @Schema(description = "项目类别(钻井 修井 注氮 酸化压裂 ...)")
+    private String projectClassification;
+
+    @Schema(description = "井型", example = "2")
+    private String wellType;
+
+    @Schema(description = "井别")
+    private String wellCategory;
+
+    @Schema(description = "施工工艺")
+    private String technique;
+
+    @Schema(description = "属性名称", example = "芋艿")
+    private String name;
+
+    @Schema(description = "属性标识符")
+    private String identifier;
+
+    @Schema(description = "数据类型(double text textarea date dropdown)", example = "2")
+    private String dataType;
+
+    @Schema(description = "是否必填(0非必填 1必填)")
+    private Integer required;
+
+    @Schema(description = "单位(MPa)")
+    private String unit;
+
+    @Schema(description = "访问模式(r读  w写)")
+    private String accessMode;
+
+    @Schema(description = "默认值")
+    private String defaultValue;
+
+    @Schema(description = "最大值")
+    private String maxValue;
+
+    @Schema(description = "最小值")
+    private String minValue;
+
+    @Schema(description = "不同专业公司的扩展属性")
+    private IotTaskAttrModelProperty extProperty;
+
+    @Schema(description = "排序值")
+    private Integer sort;
+
+    @Schema(description = "备注", example = "你说的对")
+    private String remark;
+
+    @Schema(description = "状态(0启用 1禁用)", example = "2")
+    private Integer status;
+
+}

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

@@ -1,9 +1,12 @@
 package cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingdetail.vo;
 
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.List;
+
 import com.alibaba.excel.annotation.*;
 
 @Schema(description = "管理后台 - 生产运营会明细 Response VO")
@@ -98,6 +101,9 @@ public class IotOperationMeetingDetailRespVO {
     @ExcelProperty("需集团协调支持的事项")
     private String support;
 
+    @Schema(description = "不同专业公司的扩展属性值")
+    private List<IotTaskAttrModelProperty> extProperty;
+
     @Schema(description = "排序值")
     @ExcelProperty("排序值")
     private Integer sort;

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

@@ -1,9 +1,11 @@
 package cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingdetail.vo;
 
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.List;
 
 @Schema(description = "管理后台 - 生产运营会明细新增/修改 Request VO")
 @Data
@@ -72,6 +74,9 @@ public class IotOperationMeetingDetailSaveReqVO {
     @Schema(description = "需集团协调支持的事项")
     private String support;
 
+    @Schema(description = "不同专业公司的扩展属性")
+    private List<IotTaskAttrModelProperty> extProperty;
+
     @Schema(description = "排序值")
     private Integer sort;
 

+ 9 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotoperationmeeting/IotOperationMeetingDO.java

@@ -1,8 +1,12 @@
 package cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeeting;
 
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
 import lombok.*;
 import java.time.LocalDateTime;
 import java.math.BigDecimal;
+import java.util.List;
+
 import com.baomidou.mybatisplus.annotation.*;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 
@@ -102,6 +106,11 @@ public class IotOperationMeetingDO extends BaseDO {
      * 需集团协调支持的事项
      */
     private String support;
+    /**
+     * 专业公司工作量细化扩展属性
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private List<IotTaskAttrModelProperty> extProperty;
     /**
      * 排序值
      */

+ 114 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotoperationmeetingattrs/IotOperationMeetingAttrsDO.java

@@ -0,0 +1,114 @@
+package cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeetingattrs;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import lombok.*;
+
+/**
+ * 专业公司工作量扩展属性 DO
+ *
+ * @author ruiqi
+ */
+@TableName(value = "rq_iot_operation_meeting_attrs", autoResultMap = true)
+@KeySequence("rq_iot_operation_meeting_attrs_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class IotOperationMeetingAttrsDO extends BaseDO {
+
+    /**
+     * 主键id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 日报扩展模板id
+     */
+    private Long templateId;
+    /**
+     * 公司id
+     */
+    private Long deptId;
+    /**
+     * 项目id
+     */
+    private Long projectId;
+    /**
+     * 项目类别(钻井 修井 注氮 酸化压裂 ...)
+     */
+    private String projectClassification;
+    /**
+     * 井型
+     */
+    private String wellType;
+    /**
+     * 井别
+     */
+    private String wellCategory;
+    /**
+     * 施工工艺
+     */
+    private String technique;
+    /**
+     * 属性名称
+     */
+    private String name;
+    /**
+     * 属性标识符
+     */
+    private String identifier;
+    /**
+     * 数据类型(double text textarea date dropdown)
+     */
+    private String dataType;
+    /**
+     * 是否必填(0非必填 1必填)
+     */
+    private Integer required;
+    /**
+     * 单位(MPa)
+     */
+    private String unit;
+    /**
+     * 访问模式(r读  w写)
+     */
+    private String accessMode;
+    /**
+     * 默认值
+     */
+    private String defaultValue;
+    /**
+     * 最大值
+     */
+    private String maxValue;
+    /**
+     * 最小值
+     */
+    private String minValue;
+    /**
+     * 不同专业公司的细化工作量扩展属性
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private IotTaskAttrModelProperty extProperty;
+    /**
+     * 排序值
+     */
+    private Integer sort;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 状态(0启用 1禁用)
+     */
+    private Integer status;
+
+}

+ 10 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotoperationmeetingdetail/IotOperationMeetingDetailDO.java

@@ -1,8 +1,12 @@
 package cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeetingdetail;
 
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
 import lombok.*;
 import java.time.LocalDateTime;
 import java.math.BigDecimal;
+import java.util.List;
+
 import com.baomidou.mybatisplus.annotation.*;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 
@@ -11,7 +15,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  *
  * @author ruiqi
  */
-@TableName("rq_iot_operation_meeting_detail")
+@TableName(value = "rq_iot_operation_meeting_detail", autoResultMap = true)
 @KeySequence("rq_iot_operation_meeting_detail_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -106,6 +110,11 @@ public class IotOperationMeetingDetailDO extends BaseDO {
      * 需集团协调支持的事项
      */
     private String support;
+    /**
+     * 专业公司工作量细化扩展属性
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private List<IotTaskAttrModelProperty> extProperty;
     /**
      * 排序值
      */

+ 44 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotoperationmeetingattrs/IotOperationMeetingAttrsMapper.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.pms.dal.mysql.iotoperationmeetingattrs;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+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.iotoperationmeetingattrs.vo.IotOperationMeetingAttrsPageReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeetingattrs.IotOperationMeetingAttrsDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 专业公司工作量扩展属性 Mapper
+ *
+ * @author ruiqi
+ */
+@Mapper
+public interface IotOperationMeetingAttrsMapper extends BaseMapperX<IotOperationMeetingAttrsDO> {
+
+    default PageResult<IotOperationMeetingAttrsDO> selectPage(IotOperationMeetingAttrsPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<IotOperationMeetingAttrsDO>()
+                .eqIfPresent(IotOperationMeetingAttrsDO::getTemplateId, reqVO.getTemplateId())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getDeptId, reqVO.getDeptId())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getProjectId, reqVO.getProjectId())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getProjectClassification, reqVO.getProjectClassification())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getWellType, reqVO.getWellType())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getWellCategory, reqVO.getWellCategory())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getTechnique, reqVO.getTechnique())
+                .likeIfPresent(IotOperationMeetingAttrsDO::getName, reqVO.getName())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getIdentifier, reqVO.getIdentifier())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getDataType, reqVO.getDataType())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getRequired, reqVO.getRequired())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getUnit, reqVO.getUnit())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getAccessMode, reqVO.getAccessMode())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getDefaultValue, reqVO.getDefaultValue())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getMaxValue, reqVO.getMaxValue())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getMinValue, reqVO.getMinValue())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getExtProperty, reqVO.getExtProperty())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getSort, reqVO.getSort())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getRemark, reqVO.getRemark())
+                .eqIfPresent(IotOperationMeetingAttrsDO::getStatus, reqVO.getStatus())
+                .betweenIfPresent(IotOperationMeetingAttrsDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(IotOperationMeetingAttrsDO::getId));
+    }
+
+}

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

@@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo.IotOp
 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 cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeetingdetail.IotOperationMeetingDetailDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
 
 import javax.validation.Valid;
 import java.util.List;
@@ -104,4 +104,11 @@ public interface IotOperationMeetingService {
      * @return
      */
     Set<String> availableQueryPeriods();
+
+    /**
+     * 查询当前登录人所在公司相关的 工作量 扩展属性
+     * @param
+     * @return
+     */
+    List<IotTaskAttrModelProperty> currentCompanyExtProperties();
 }

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

@@ -11,12 +11,16 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo.IotOp
 import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeeting.vo.IotOperationMeetingRespVO;
 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.iotoperationmeetingattrs.vo.IotOperationMeetingAttrsPageReqVO;
 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.iotoperationmeetingattrs.IotOperationMeetingAttrsDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeetingdetail.IotOperationMeetingDetailDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotoperationmeeting.IotOperationMeetingMapper;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotoperationmeetingattrs.IotOperationMeetingAttrsMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotoperationmeetingdetail.IotOperationMeetingDetailMapper;
 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
 import cn.iocoder.yudao.module.system.service.dept.DeptService;
@@ -26,13 +30,14 @@ import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.stream.Collectors;
 
 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.pms.enums.ErrorCodeConstant.*;
 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.DEPT_NOT_FOUND;
 
 /**
@@ -50,6 +55,9 @@ public class IotOperationMeetingServiceImpl implements IotOperationMeetingServic
     private IotOperationMeetingDetailMapper iotOperationMeetingDetailMapper;
     @Resource
     private DeptService deptservice;
+    @Resource
+    private IotOperationMeetingAttrsMapper iotOperationMeetingAttrsMapper;
+
 
     @Override
     public Long createIotOperationMeeting(IotOperationMeetingSaveReqVO createReqVO) {
@@ -174,15 +182,176 @@ public class IotOperationMeetingServiceImpl implements IotOperationMeetingServic
             resultId = id;
             meetingIds.add(iotOperationMeeting.getId());
         }
+
+        // 查询当年上一期次的会议内容 公司所属项目工作量细化数据 计算环比使用 设备利用率...
+        IotOperationMeetingDetailPageReqVO beforeReqVO = new IotOperationMeetingDetailPageReqVO();
+        // 当前日期所属年
+        LocalDateTime currentDate = LocalDateTime.now();
+        beforeReqVO.setYear(currentDate.getYear());
+        beforeReqVO.setSort(meeting.getSort() - 1);
+        List<IotOperationMeetingDetailDO> beforeSummarizedDetails = iotOperationMeetingDetailMapper.summarizedProjectDetails(beforeReqVO);
+        // key项目名称  value项目设备利用率
+        Map<String, BigDecimal> projectUtilizationPair = new HashMap<>();
+        if (CollUtil.isNotEmpty(beforeSummarizedDetails)) {
+            // 查询每个项目的设备利用率
+            beforeSummarizedDetails.forEach(detail -> {
+                // 每个项目的工作量扩展属性列表
+                List<IotTaskAttrModelProperty> properties = detail.getExtProperty();
+                if (CollUtil.isNotEmpty(properties)) {
+                    // 瑞恒设备利用率
+                    BigDecimal utilizationRate = getActualValue(properties, "utilizationRate");
+                    projectUtilizationPair.put(detail.getProjectName(), utilizationRate);
+                }
+            });
+        }
+
         // 编辑时先删除明细 再新增明细
         if (ObjUtil.isNotEmpty(saveBatchVO.getDetails())) {
             List<IotOperationMeetingDetailSaveReqVO> details = saveBatchVO.getDetails();
             List<IotOperationMeetingDetailDO> meetingDetails = new ArrayList<>();
             details.forEach(detail -> {
+                // 保存项目明细时 计算工作量 汇总数据 完成比 设备利用率 ...
+                List<IotTaskAttrModelProperty> properties = detail.getExtProperty();
+                if (CollUtil.isNotEmpty(properties)) {
+                    // 找到每个项目的 拆分后的工作量字段值
+                    // 157 瑞恒 注气完成比 gasCompletionRatio = 实际注气量/计划注气量
+                    if (Long.valueOf(157).equals(meeting.getDeptId())) {
+                        BigDecimal planGasInjection = getActualValue(properties, "planGasInjection");
+                        BigDecimal actualGasInjection = getActualValue(properties, "actualGasInjection");
+                        if (planGasInjection.compareTo(BigDecimal.ZERO) > 0) {
+                            // 注气完成比 gasCompletionRatio = 实际注气量/计划注气量 23.85%
+                            BigDecimal gasCompletionRatio =  actualGasInjection.divide(planGasInjection, 4, RoundingMode.HALF_UP);
+                            // 将 完成比 作为单独的1个元素添加到 extProperty
+                            IotTaskAttrModelProperty completionRatioProperty = new IotTaskAttrModelProperty();
+                            completionRatioProperty.setName("注气完成比");
+                            completionRatioProperty.setAccessMode("r");
+                            completionRatioProperty.setRequired(0);
+                            completionRatioProperty.setSort(3);
+                            completionRatioProperty.setUnit("%");
+                            completionRatioProperty.setDataType("double");
+                            completionRatioProperty.setIdentifier("gasCompletionRatio");
+                            completionRatioProperty.setActualValue(gasCompletionRatio.toString());
+                            completionRatioProperty.setMaxValue(StrUtil.EMPTY);
+                            completionRatioProperty.setMinValue(StrUtil.EMPTY);
+                            completionRatioProperty.setDefaultValue(StrUtil.EMPTY);
+                            properties.add(completionRatioProperty);
+                        }
+                    }
+
+                    // 瑞鹰 进尺完成比 井次完成比
+                    if (Long.valueOf(158).equals(meeting.getDeptId())) {
+                        // 计划进尺
+                        BigDecimal planFootage = getActualValue(properties, "planFootage");
+                        // 实际进尺
+                        BigDecimal actualFootage = getActualValue(properties, "actualFootage");
+                        if (planFootage.compareTo(BigDecimal.ZERO) > 0) {
+                            // 进尺完成比 footageCompletionRatio = 实际进尺/计划进尺 23.85%
+                            BigDecimal footageCompletionRatio =  actualFootage.divide(planFootage, 4, RoundingMode.HALF_UP);
+                            // 将 完成比 作为单独的1个元素添加到 extProperty
+                            IotTaskAttrModelProperty footageCompletionRatioProperty = new IotTaskAttrModelProperty();
+                            footageCompletionRatioProperty.setName("进尺完成比");
+                            footageCompletionRatioProperty.setAccessMode("r");
+                            footageCompletionRatioProperty.setRequired(0);
+                            footageCompletionRatioProperty.setSort(3);
+                            footageCompletionRatioProperty.setUnit("%");
+                            footageCompletionRatioProperty.setDataType("double");
+                            footageCompletionRatioProperty.setIdentifier("footageCompletionRatio");
+                            footageCompletionRatioProperty.setActualValue(footageCompletionRatio.toString());
+                            footageCompletionRatioProperty.setMaxValue(StrUtil.EMPTY);
+                            footageCompletionRatioProperty.setMinValue(StrUtil.EMPTY);
+                            footageCompletionRatioProperty.setDefaultValue(StrUtil.EMPTY);
+                            properties.add(footageCompletionRatioProperty);
+                        }
+                    }
+
+                    // 瑞都(层数完成比 井次完成比)   5#公司 层数完成比
+                    if (Long.valueOf(163).equals(meeting.getDeptId()) || Long.valueOf(388).equals(meeting.getDeptId())) {
+                        // 计划层数
+                        BigDecimal planLayers = getActualValue(properties, "planLayers");
+                        // 实际层数
+                        BigDecimal actualLayers = getActualValue(properties, "actualLayers");
+                        if (planLayers.compareTo(BigDecimal.ZERO) > 0) {
+                            // 层数完成比 layersCompletionRatio = 实际层数/计划层数 23.85%
+                            BigDecimal layersCompletionRatio =  actualLayers.divide(planLayers, 4, RoundingMode.HALF_UP);
+                            // 将 完成比 作为单独的1个元素添加到 extProperty
+                            IotTaskAttrModelProperty layersCompletionRatioProperty = new IotTaskAttrModelProperty();
+                            layersCompletionRatioProperty.setName("层数完成比");
+                            layersCompletionRatioProperty.setAccessMode("r");
+                            layersCompletionRatioProperty.setRequired(0);
+                            layersCompletionRatioProperty.setSort(3);
+                            layersCompletionRatioProperty.setUnit("%");
+                            layersCompletionRatioProperty.setDataType("double");
+                            layersCompletionRatioProperty.setIdentifier("layersCompletionRatio");
+                            layersCompletionRatioProperty.setActualValue(layersCompletionRatio.toString());
+                            layersCompletionRatioProperty.setMaxValue(StrUtil.EMPTY);
+                            layersCompletionRatioProperty.setMinValue(StrUtil.EMPTY);
+                            layersCompletionRatioProperty.setDefaultValue(StrUtil.EMPTY);
+                            properties.add(layersCompletionRatioProperty);
+                        }
+                    }
+
+                    // 瑞鹰 瑞都 同时 具备 井次 工作量
+                    if (Long.valueOf(163).equals(meeting.getDeptId()) || Long.valueOf(158).equals(meeting.getDeptId())) {
+                        // 计划井次
+                        BigDecimal planWellTrips = getActualValue(properties, "planWellTrips");
+                        // 实际井次
+                        BigDecimal actualWellTrips = getActualValue(properties, "actualWellTrips");
+                        if (planWellTrips.compareTo(BigDecimal.ZERO) > 0) {
+                            // 井次完成比 wellTripsCompletionRatio = 实际井次/计划井次 23.85%
+                            BigDecimal wellTripsCompletionRatio =  actualWellTrips.divide(planWellTrips, 4, RoundingMode.HALF_UP);
+                            // 将 完成比 作为单独的1个元素添加到 extProperty
+                            IotTaskAttrModelProperty wellTripsCompletionRatioProperty = new IotTaskAttrModelProperty();
+                            wellTripsCompletionRatioProperty.setName("井次完成比");
+                            wellTripsCompletionRatioProperty.setAccessMode("r");
+                            wellTripsCompletionRatioProperty.setRequired(0);
+                            wellTripsCompletionRatioProperty.setSort(7);
+                            wellTripsCompletionRatioProperty.setUnit("%");
+                            wellTripsCompletionRatioProperty.setDataType("double");
+                            wellTripsCompletionRatioProperty.setIdentifier("wellTripsCompletionRatio");
+                            wellTripsCompletionRatioProperty.setActualValue(wellTripsCompletionRatio.toString());
+                            wellTripsCompletionRatioProperty.setMaxValue(StrUtil.EMPTY);
+                            wellTripsCompletionRatioProperty.setMinValue(StrUtil.EMPTY);
+                            wellTripsCompletionRatioProperty.setDefaultValue(StrUtil.EMPTY);
+                            properties.add(wellTripsCompletionRatioProperty);
+                        }
+                    }
+
+                    // 每个专业公司设备利用率计算逻辑相同 utilizationRate
+                    // 设备利用率 环比 (当前期利用率 - 上一期利用率) / 上一期利用率
+                    // 计算当前期次会议 当前项目的设备利用率 施工设备数量/投运设备数量 已经通过前端 计算赋值
+                    BigDecimal utilizationRate = getActualValue(properties, "utilizationRate");
+
+                    String projectName = detail.getProjectName();
+                    BigDecimal beforeUtilizationRate = BigDecimal.ZERO;
+                    if (StrUtil.isNotBlank(projectName) && projectUtilizationPair.containsKey(projectName)) {
+                        // 上一期次的设备利用率
+                        beforeUtilizationRate = projectUtilizationPair.get(projectName);
+                    }
+                    if (beforeUtilizationRate.compareTo(BigDecimal.ZERO) > 0) {
+                        BigDecimal periodOnPeriod = utilizationRate.subtract(beforeUtilizationRate)
+                                .divide(beforeUtilizationRate, 4, RoundingMode.HALF_UP);
+                        // 将 设备利用率 环比 作为单独的1个元素添加到 extProperty
+                        IotTaskAttrModelProperty periodOnPeriodProperty = new IotTaskAttrModelProperty();
+                        periodOnPeriodProperty.setName("环比");
+                        periodOnPeriodProperty.setAccessMode("r");
+                        periodOnPeriodProperty.setRequired(0);
+                        periodOnPeriodProperty.setSort(8);
+                        periodOnPeriodProperty.setUnit("%");
+                        periodOnPeriodProperty.setDataType("double");
+                        periodOnPeriodProperty.setIdentifier("periodOnPeriod");
+                        periodOnPeriodProperty.setActualValue(periodOnPeriod.toString());
+                        periodOnPeriodProperty.setMaxValue(StrUtil.EMPTY);
+                        periodOnPeriodProperty.setMinValue(StrUtil.EMPTY);
+                        periodOnPeriodProperty.setDefaultValue(StrUtil.EMPTY);
+                        properties.add(periodOnPeriodProperty);
+                    }
+
+                    detail.setExtProperty(properties);
+                }
                 IotOperationMeetingDetailDO detailDO = BeanUtils.toBean(detail, IotOperationMeetingDetailDO.class);
                 detailDO.setId(null);
                 detailDO.setMeetingId(meetingIds.get(0));
-                detailDO.setDeptId(meeting.getDeptId());
+                detailDO.setDeptId(meeting.getDeptId());    // 所属公司
                 detailDO.setSort(meeting.getSort());        // 期次索引
                 meetingDetails.add(detailDO);
             });
@@ -191,6 +360,29 @@ public class IotOperationMeetingServiceImpl implements IotOperationMeetingServic
         return resultId;
     }
 
+    /**
+     * 从工作量扩展属性中获取 指定名称的值
+     */
+    private BigDecimal getActualValue(List<IotTaskAttrModelProperty> properties, String identifier) {
+        // 空值直接返回 0
+        if (CollUtil.isEmpty(properties)) {
+            return BigDecimal.ZERO;
+        }
+
+        // Java 8 流式优雅查找目标属性
+        return properties.stream()
+                // 过滤标识符 = planGasInjection
+                .filter(property -> identifier.equals(property.getIdentifier()))
+                // 提取值
+                .map(IotTaskAttrModelProperty::getActualValue)
+                .filter(StrUtil::isNotBlank)
+                // 只取第一个匹配的
+                .findFirst()
+                // 转成 BigDecimal,无值则返回 0
+                .map(BigDecimal::new)
+                .orElse(BigDecimal.ZERO);
+    }
+
     @Override
     public Set<String> cachedProjects() {
         Set<String> projectNames = new HashSet<>();
@@ -378,6 +570,24 @@ public class IotOperationMeetingServiceImpl implements IotOperationMeetingServic
         if (CollUtil.isEmpty(meetings)) {
             return resultMeetings;
         }
+
+        // 查询 当年 上一期次的会议财务数据 汇总后计算 收入 挂账 回款 环比
+        Set<Long> beforeCompanyIds = new HashSet<>();
+        IotOperationMeetingDetailPageReqVO beforeReqVO = new IotOperationMeetingDetailPageReqVO();
+        beforeReqVO.setYear(year);
+        beforeReqVO.setSort(reqVO.getSort() - 1);
+        List<IotOperationMeetingDetailDO> beforeSummarizedDetails = iotOperationMeetingDetailMapper.summarizedProjectDetails(beforeReqVO);
+        if (CollUtil.isNotEmpty(beforeSummarizedDetails)) {
+            // 如果上期次存在数据 才比较 财务数据 环比
+            beforeSummarizedDetails.forEach(detail -> {
+                beforeCompanyIds.add(detail.getDeptId());
+            });
+        }
+        // 组装每个专业公司各项目的累加财务数据 本期 收入 挂账 回款 并计算 环比
+        Map<Long, BigDecimal> revenuePair = new HashMap<>();
+
+
+
         // 组装每个会议的需要集团支持的事项
         Map<Long, IotOperationMeetingDO> supportPair = new HashMap<>();
         meetings.forEach(meeting -> {
@@ -439,4 +649,44 @@ public class IotOperationMeetingServiceImpl implements IotOperationMeetingServic
         return Collections.emptySet();
     }
 
+    @Override
+    public List<IotTaskAttrModelProperty> currentCompanyExtProperties() {
+        List<IotTaskAttrModelProperty> workloadProperties = new ArrayList<>();
+        // 当前登录人所属公司的deptId 关联表 rq_iot_operation_meeting_attrs
+        Long loginUserDeptId = SecurityFrameworkUtils.getLoginUserDeptId();
+        DeptDO dept = deptservice.getDept(loginUserDeptId);
+        if (ObjUtil.isEmpty(dept)) {
+            throw exception(DEPT_NOT_FOUND);
+        }
+        IotOperationMeetingAttrsPageReqVO reqVO = new IotOperationMeetingAttrsPageReqVO();
+        reqVO.setDeptId(dept.getId());
+        reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        PageResult<IotOperationMeetingAttrsDO> pageAttrs = iotOperationMeetingAttrsMapper.selectPage(reqVO);
+        if (ObjUtil.isEmpty(pageAttrs)) {
+            throw exception(IOT_OPERATION_MEETING_ATTRS_NOT_EXISTS);
+        }
+        List<IotOperationMeetingAttrsDO> attrs = pageAttrs.getList();
+        if (CollUtil.isEmpty(attrs)) {
+            throw exception(IOT_OPERATION_MEETING_ATTRS_NOT_EXISTS);
+        }
+        attrs.forEach(attr -> {
+            // 下期工作计划 标识 defaultValue = next
+            // 可见性 标识 required = 1
+            // 只读 标识 accessMode = r
+            // 可读可写 标识 accessMode = rw
+            IotTaskAttrModelProperty property = attr.getExtProperty();
+            if (ObjUtil.isNotEmpty(property) && ObjUtil.isNotEmpty(property.getRequired()) && 1 == property.getRequired()) {
+                workloadProperties.add(attr.getExtProperty());
+            }
+        });
+        // 按照 sort 值 升序 排序
+        if (CollUtil.isNotEmpty(workloadProperties)) {
+            workloadProperties.sort(Comparator.comparing(
+                    IotTaskAttrModelProperty::getSort,
+                    Comparator.nullsLast(Comparator.naturalOrder())
+            ));
+        }
+        return workloadProperties;
+    }
+
 }

+ 55 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotoperationmeetingattrs/IotOperationMeetingAttrsService.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.pms.service.iotoperationmeetingattrs;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingattrs.vo.IotOperationMeetingAttrsPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingattrs.vo.IotOperationMeetingAttrsSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeetingattrs.IotOperationMeetingAttrsDO;
+
+import javax.validation.Valid;
+
+/**
+ * 专业公司工作量扩展属性 Service 接口
+ *
+ * @author ruiqi
+ */
+public interface IotOperationMeetingAttrsService {
+
+    /**
+     * 创建专业公司工作量扩展属性
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createIotOperationMeetingAttrs(@Valid IotOperationMeetingAttrsSaveReqVO createReqVO);
+
+    /**
+     * 更新专业公司工作量扩展属性
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateIotOperationMeetingAttrs(@Valid IotOperationMeetingAttrsSaveReqVO updateReqVO);
+
+    /**
+     * 删除专业公司工作量扩展属性
+     *
+     * @param id 编号
+     */
+    void deleteIotOperationMeetingAttrs(Long id);
+
+    /**
+     * 获得专业公司工作量扩展属性
+     *
+     * @param id 编号
+     * @return 专业公司工作量扩展属性
+     */
+    IotOperationMeetingAttrsDO getIotOperationMeetingAttrs(Long id);
+
+    /**
+     * 获得专业公司工作量扩展属性分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 专业公司工作量扩展属性分页
+     */
+    PageResult<IotOperationMeetingAttrsDO> getIotOperationMeetingAttrsPage(IotOperationMeetingAttrsPageReqVO pageReqVO);
+
+}

+ 71 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotoperationmeetingattrs/IotOperationMeetingAttrsServiceImpl.java

@@ -0,0 +1,71 @@
+package cn.iocoder.yudao.module.pms.service.iotoperationmeetingattrs;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingattrs.vo.IotOperationMeetingAttrsPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotoperationmeetingattrs.vo.IotOperationMeetingAttrsSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotoperationmeetingattrs.IotOperationMeetingAttrsDO;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotoperationmeetingattrs.IotOperationMeetingAttrsMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_OPERATION_MEETING_ATTRS_NOT_EXISTS;
+
+/**
+ * 专业公司工作量扩展属性 Service 实现类
+ *
+ * @author ruiqi
+ */
+@Service
+@Validated
+public class IotOperationMeetingAttrsServiceImpl implements IotOperationMeetingAttrsService {
+
+    @Resource
+    private IotOperationMeetingAttrsMapper iotOperationMeetingAttrsMapper;
+
+    @Override
+    public Long createIotOperationMeetingAttrs(IotOperationMeetingAttrsSaveReqVO createReqVO) {
+        // 插入
+        IotOperationMeetingAttrsDO iotOperationMeetingAttrs = BeanUtils.toBean(createReqVO, IotOperationMeetingAttrsDO.class);
+        iotOperationMeetingAttrsMapper.insert(iotOperationMeetingAttrs);
+        // 返回
+        return iotOperationMeetingAttrs.getId();
+    }
+
+    @Override
+    public void updateIotOperationMeetingAttrs(IotOperationMeetingAttrsSaveReqVO updateReqVO) {
+        // 校验存在
+        validateIotOperationMeetingAttrsExists(updateReqVO.getId());
+        // 更新
+        IotOperationMeetingAttrsDO updateObj = BeanUtils.toBean(updateReqVO, IotOperationMeetingAttrsDO.class);
+        iotOperationMeetingAttrsMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteIotOperationMeetingAttrs(Long id) {
+        // 校验存在
+        validateIotOperationMeetingAttrsExists(id);
+        // 删除
+        iotOperationMeetingAttrsMapper.deleteById(id);
+    }
+
+    private void validateIotOperationMeetingAttrsExists(Long id) {
+        if (iotOperationMeetingAttrsMapper.selectById(id) == null) {
+            throw exception(IOT_OPERATION_MEETING_ATTRS_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public IotOperationMeetingAttrsDO getIotOperationMeetingAttrs(Long id) {
+        return iotOperationMeetingAttrsMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<IotOperationMeetingAttrsDO> getIotOperationMeetingAttrsPage(IotOperationMeetingAttrsPageReqVO pageReqVO) {
+        return iotOperationMeetingAttrsMapper.selectPage(pageReqVO);
+    }
+
+}

+ 1 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotrhdailyreport/IotRhDailyReportServiceImpl.java

@@ -1130,7 +1130,7 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
             if (projectDeptIds.contains(parentId)) {
                 // 获得当前部门的上级项目部
                 projectDeptIds.forEach(projectDeptId -> {
-                    if (projectDeptId.equals(parentId) && haveDeviceDeptIds.contains(deptId)) {
+                    if (projectDeptId.equals(parentId) && haveDeviceDeptIds.contains(deptId) && teamIds.contains(deptId)) {
                         if (projectTeamPair.containsKey(projectDeptId)) {
                             Set<Long> tempTeamIds = projectTeamPair.get(projectDeptId);
                             tempTeamIds.add(deptId);