Browse Source

解决冲突

james 1 month ago
parent
commit
523b36108b
63 changed files with 4574 additions and 335 deletions
  1. 3 0
      pom.xml
  2. 1 1
      service-alarm/service-alarm-biz/src/main/java/com/usky/alarm/service/mqtt/alarm/Alarm.java
  3. 44 25
      service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/DmpDeviceInfoController.java
  4. 68 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/PmTimeConfController.java
  5. 1 1
      service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/PmWorkContentController.java
  6. 4 2
      service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/PmWorkReportController.java
  7. 87 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/domain/PmTimeConf.java
  8. 16 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/mapper/PmTimeConfMapper.java
  9. 21 2
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/DmpDeviceInfoService.java
  10. 34 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/PmTimeConfService.java
  11. 2 1
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/PmWorkReportService.java
  12. 34 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/enums/TopicInfo.java
  13. 446 214
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/DmpDeviceInfoServiceImpl.java
  14. 317 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/PmTimeConfServiceImpl.java
  15. 0 2
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/PmWorkContentServiceImpl.java
  16. 36 15
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/PmWorkReportServiceImpl.java
  17. 23 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/vo/DmpHttpAlarmResponseVO.java
  18. 79 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/vo/DmpTopicRequestVO.java
  19. 57 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/vo/DmpTopicResponseVO.java
  20. 65 0
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/vo/PmSubmitCountResponseVO.java
  21. 19 0
      service-iot/service-iot-biz/src/main/resources/mapper/iot/PmTimeConfMapper.xml
  22. 18 69
      service-oa/service-oa-biz/pom.xml
  23. 0 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/MybatisGeneratorUtils.java
  24. 0 2
      service-oa/service-oa-biz/src/main/java/com/usky/oa/ServiceOaApplication.java
  25. 108 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/controller/MybatisGeneratorUtils.java
  26. 85 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/controller/web/OaApprovalController.java
  27. 99 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/controller/web/OaDocumentController.java
  28. 95 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/controller/web/OaFormDefinitionController.java
  29. 44 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/controller/web/OaJbdDocumentController.java
  30. 49 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/controller/web/OaQjdDocumentController.java
  31. 105 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/domain/OaApproval.java
  32. 86 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/domain/OaDocument.java
  33. 135 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/domain/OaFormDefinition.java
  34. 118 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/domain/OaJbdDocument.java
  35. 120 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/domain/OaQjdDocument.java
  36. 18 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/mapper/OaApprovalMapper.java
  37. 34 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/mapper/OaDocumentMapper.java
  38. 18 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/mapper/OaFormDefinitionMapper.java
  39. 18 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/mapper/OaJbdDocumentMapper.java
  40. 18 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/mapper/OaQjdDocumentMapper.java
  41. 15 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/mapper/SysUserMapper.java
  42. 50 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/OaApprovalService.java
  43. 80 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/OaDocumentService.java
  44. 72 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/OaFormDefinitionService.java
  45. 46 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/OaJbdDocumentService.java
  46. 45 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/OaQjdDocumentService.java
  47. 49 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/enums/OaBuiltInDocument.java
  48. 236 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/impl/OaApprovalServiceImpl.java
  49. 236 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/impl/OaDocumentServiceImpl.java
  50. 331 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/impl/OaFormDefinitionServiceImpl.java
  51. 215 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/impl/OaJbdDocumentServiceImpl.java
  52. 231 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/impl/OaQjdDocumentServiceImpl.java
  53. 33 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/utils/OaDefinitionDocumentInfo.java
  54. 53 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/utils/OaProcessAnalysis.java
  55. 93 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/utils/OaSendMessageCenter.java
  56. 54 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/vo/OaApprovalCountVO.java
  57. 23 0
      service-oa/service-oa-biz/src/main/java/com/usky/oa/service/vo/OaFormNameResponseVO.java
  58. 1 1
      service-oa/service-oa-biz/src/main/resources/bootstrap.yml
  59. 24 0
      service-oa/service-oa-biz/src/main/resources/mapper/oa/OaApprovalMapper.xml
  60. 81 0
      service-oa/service-oa-biz/src/main/resources/mapper/oa/OaDocumentMapper.xml
  61. 30 0
      service-oa/service-oa-biz/src/main/resources/mapper/oa/OaFormDefinitionMapper.xml
  62. 26 0
      service-oa/service-oa-biz/src/main/resources/mapper/oa/OaJbdDocumentMapper.xml
  63. 25 0
      service-oa/service-oa-biz/src/main/resources/mapper/oa/OaQjdDocumentMapper.xml

+ 3 - 0
pom.xml

@@ -87,6 +87,9 @@
 
     <module>service-eg</module>
 
+
+    <module>service-oa</module>
+
   </modules>
           
   

+ 1 - 1
service-alarm/service-alarm-biz/src/main/java/com/usky/alarm/service/mqtt/alarm/Alarm.java

@@ -70,7 +70,7 @@ public class Alarm implements MqttStrategy {
             baseAlarm.setAlarmAddress(alarams.get(0).get("deviceName").toString());
         }else if (alarams.get(0).get("deviceType").equals("3")||alarams.get(0).get("deviceType").equals("137")){
             baseAlarm.setAlarmContent(dp.get(0).get("property").toString());
-            baseAlarm.setAlarmGrade(2);
+            baseAlarm.setAlarmGrade(1);
             baseAlarm.setAlarmAddress(alarams.get(0).get("deviceName").toString());
             LambdaQueryWrapper<DmpDeviceLinkage> queryWrapper5 = Wrappers.lambdaQuery();
             queryWrapper5.eq(DmpDeviceLinkage::getDeviceId,map.get("devId").toString());

+ 44 - 25
service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/DmpDeviceInfoController.java

@@ -1,14 +1,14 @@
 package com.usky.iot.controller.web;
 
-
 import com.usky.backend.domain.*;
 import com.usky.common.core.bean.ApiResult;
 import com.usky.common.core.bean.CommonPage;
 import com.usky.common.core.utils.poi.ExcelUtil;
+<<<<<<< HEAD
 import com.usky.demo.domain.LastInnerQueryVO;
 import com.usky.iot.domain.DmpDeviceInfo;
 import com.usky.iot.service.DmpDeviceInfoService;
-import com.usky.iot.service.vo.DmpDeviceInfoRequest;
+import com.usky.iot.service.vo.*;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
@@ -38,7 +38,7 @@ public class DmpDeviceInfoController {
      * @return
      */
     @PostMapping
-    public ApiResult<Void> add(@RequestBody DmpDeviceInfo dmpDeviceInfo){
+    public ApiResult<Void> add(@RequestBody DmpDeviceInfo dmpDeviceInfo) {
         dmpDeviceInfoService.add(dmpDeviceInfo);
         return ApiResult.success();
     }
@@ -49,7 +49,7 @@ public class DmpDeviceInfoController {
      * @return
      */
     @PutMapping
-    public ApiResult<Void> edit(@RequestBody DmpDeviceInfo dmpDeviceInfo){
+    public ApiResult<Void> edit(@RequestBody DmpDeviceInfo dmpDeviceInfo) {
         dmpDeviceInfoService.update(dmpDeviceInfo);
         return ApiResult.success();
     }
@@ -71,8 +71,7 @@ public class DmpDeviceInfoController {
      * @return
      */
     @PostMapping("/page")
-    public ApiResult<CommonPage<DmpDeviceInfo>> page(@RequestBody DmpDeviceInfoRequest dmpDeviceInfoRequest)
-    {
+    public ApiResult<CommonPage<DmpDeviceInfo>> page(@RequestBody DmpDeviceInfoRequest dmpDeviceInfoRequest) {
         return ApiResult.success(dmpDeviceInfoService.page(dmpDeviceInfoRequest));
     }
 
@@ -83,8 +82,7 @@ public class DmpDeviceInfoController {
      * @return
      */
     @PostMapping("/pageWhite")
-    public ApiResult<CommonPage<DmpDeviceInfo>> pageWhite(@RequestBody DmpDeviceInfoRequest dmpDeviceInfoRequest)
-    {
+    public ApiResult<CommonPage<DmpDeviceInfo>> pageWhite(@RequestBody DmpDeviceInfoRequest dmpDeviceInfoRequest) {
         return ApiResult.success(dmpDeviceInfoService.pageWhite(dmpDeviceInfoRequest));
     }
 
@@ -92,8 +90,7 @@ public class DmpDeviceInfoController {
      * 删除记录
      */
     @DeleteMapping("/{id}")
-    public ApiResult<Void> remove(@PathVariable("id") Integer id)
-    {
+    public ApiResult<Void> remove(@PathVariable("id") Integer id) {
         dmpDeviceInfoService.remove(id);
         return ApiResult.success();
     }
@@ -104,7 +101,7 @@ public class DmpDeviceInfoController {
      * @return
      */
     @PostMapping("/addByFile")
-    public ApiResult<Void> addByFile(@RequestParam(value = "file") MultipartFile multipartFiles){
+    public ApiResult<Void> addByFile(@RequestParam(value = "file") MultipartFile multipartFiles) {
         dmpDeviceInfoService.addByFile(multipartFiles);
         return ApiResult.success();
     }
@@ -116,7 +113,7 @@ public class DmpDeviceInfoController {
      * @return
      */
     @PostMapping("/importDeviceInfo")
-    public ApiResult<Void> importDeviceInfo(@RequestBody List<DmpDeviceInfo> list){
+    public ApiResult<Void> importDeviceInfo(@RequestBody List<DmpDeviceInfo> list) {
         dmpDeviceInfoService.importDeviceInfo(list);
         return ApiResult.success();
     }
@@ -128,8 +125,8 @@ public class DmpDeviceInfoController {
      * @return
      */
     @PostMapping("/export")
-    public void export(@RequestBody DmpDeviceInfoRequest dmpDeviceInfoRequest, HttpServletResponse response){
-        dmpDeviceInfoService.export(dmpDeviceInfoRequest,response);
+    public void export(@RequestBody DmpDeviceInfoRequest dmpDeviceInfoRequest, HttpServletResponse response) {
+        dmpDeviceInfoService.export(dmpDeviceInfoRequest, response);
     }
 
     /**
@@ -143,12 +140,12 @@ public class DmpDeviceInfoController {
      * @return
      */
     @GetMapping("deviceCurrentDataList")
-    public ApiResult<CommonPage<Object>> deviceCurrentDataList(@RequestParam(value = "deviceName",required = false) String deviceName,
-                                                               @RequestParam(value = "installAddress",required = false) String installAddress,
-                                                               @RequestParam(value = "productCode",required = false) String productCode,
+    public ApiResult<CommonPage<Object>> deviceCurrentDataList(@RequestParam(value = "deviceName", required = false) String deviceName,
+                                                               @RequestParam(value = "installAddress", required = false) String installAddress,
+                                                               @RequestParam(value = "productCode", required = false) String productCode,
                                                                @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
-                                                               @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize){
-        return ApiResult.success(dmpDeviceInfoService.deviceCurrentDataList(deviceName,installAddress,productCode,pageNum,pageSize));
+                                                               @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
+        return ApiResult.success(dmpDeviceInfoService.deviceCurrentDataList(deviceName, installAddress, productCode, pageNum, pageSize));
     }
 
     /**
@@ -158,7 +155,7 @@ public class DmpDeviceInfoController {
      * @return
      */
     @PostMapping("dataTVList")
-    public ApiResult<CommonPage<DataTVResponseVO>> dataTVList(@RequestBody DataTVRequestVO requestVO){
+    public ApiResult<CommonPage<DataTVResponseVO>> dataTVList(@RequestBody DataTVRequestVO requestVO) {
         return ApiResult.success(dmpDeviceInfoService.dataTVList(requestVO));
     }
 
@@ -169,7 +166,7 @@ public class DmpDeviceInfoController {
      * @return
      */
     @PostMapping("dataTVStatistic")
-    public ApiResult<List<DataTVStatisticResponseVO>> dataTVStatistic(@RequestBody DataTVRequestVO requestVO){
+    public ApiResult<List<DataTVStatisticResponseVO>> dataTVStatistic(@RequestBody DataTVRequestVO requestVO) {
         return ApiResult.success(dmpDeviceInfoService.dataTVStatistic(requestVO));
     }
 
@@ -180,7 +177,7 @@ public class DmpDeviceInfoController {
      */
     @PostMapping("deviceDataTotal")
     @ApiOperation("获取设备某个时间端内的汇总值")
-    public ApiResult<List<Map<String,Object>>> deviceDataTotal(@RequestBody DataTotalRequestVO requestVO){
+    public ApiResult<List<Map<String, Object>>> deviceDataTotal(@RequestBody DataTotalRequestVO requestVO) {
         return ApiResult.success(dmpDeviceInfoService.deviceDataTotal(requestVO));
     }
 
@@ -191,7 +188,7 @@ public class DmpDeviceInfoController {
      */
     @PostMapping("deviceDataAverage")
     @ApiOperation("获取设备日平均、月平均、年平均值")
-    public ApiResult<List<DataAverageResponseVO>> deviceDataAverage(@RequestBody DataAverageRequestVO requestVO){
+    public ApiResult<List<DataAverageResponseVO>> deviceDataAverage(@RequestBody DataAverageRequestVO requestVO) {
         return ApiResult.success(dmpDeviceInfoService.deviceDataAverage(requestVO));
     }
 
@@ -202,10 +199,32 @@ public class DmpDeviceInfoController {
      * @throws IOException
      */
     @PostMapping("deviceDataAverageExport")
-    public void export(@RequestBody DataAverageRequestVO requestVO, HttpServletResponse response) throws IOException{
+    public void export(@RequestBody DataAverageRequestVO requestVO, HttpServletResponse response) throws IOException {
         List<DataAverageExportVO> list = dmpDeviceInfoService.DataAverageExport(requestVO);
         ExcelUtil<DataAverageExportVO> util = new ExcelUtil<DataAverageExportVO>(DataAverageExportVO.class);
-        util.exportExcel(response,list,requestVO.getSheetName(),requestVO.getTitleName());
+        util.exportExcel(response, list, requestVO.getSheetName(), requestVO.getTitleName());
+    }
+
+    /**
+     * 获取设备topic列表
+     * @param requestVO
+     * @return
+     */
+    @PostMapping("topic")
+    public ApiResult<CommonPage<DmpTopicResponseVO>> topic(@RequestBody DmpTopicRequestVO requestVO) {
+        return ApiResult.success(dmpDeviceInfoService.topic(requestVO));
+    }
+
+    /**
+     * 获取设备告警请求信息
+     * @param deviceId 设备id
+     * @param productCode 产品编码
+     * @return
+     */
+    @GetMapping("alarmResponse")
+    public ApiResult<DmpHttpAlarmResponseVO> alarmResponse(@RequestParam(value = "deviceId") String deviceId,
+                                                           @RequestParam(value = "productCode") String productCode){
+        return ApiResult.success(dmpDeviceInfoService.alarmResponse(deviceId, productCode));
     }
 }
 

+ 68 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/PmTimeConfController.java

@@ -0,0 +1,68 @@
+package com.usky.iot.controller.web;
+
+
+import com.usky.common.core.bean.CommonPage;
+import com.usky.iot.domain.PmWorkReport;
+import com.usky.iot.service.PmTimeConfService;
+import com.usky.iot.service.vo.PmSubmitCountResponseVO;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+/**
+ * <p>
+ * 工作报告提交时间配置表 前端控制器
+ * </p>
+ *
+ * @author fu
+ * @since 2025-01-10
+ */
+@RestController
+@RequestMapping("/pmTimeConf")
+public class PmTimeConfController {
+
+    @Autowired
+    private PmTimeConfService pmTimeConfService;
+
+    /**
+     * 提交统计
+     * @param submitDate 统计日期
+     * @return 统计结果
+     */
+    @GetMapping("/submitCount")
+    public PmSubmitCountResponseVO submitCount(@RequestParam(value = "submitDate", required = false) String submitDate) {
+        if (submitDate == null) {
+            LocalDateTime now = LocalDateTime.now();
+            LocalDateTime today1800 = LocalDateTime.of(now.toLocalDate(), LocalTime.of(18, 0));
+            if (now.isBefore(today1800)) {
+                submitDate = now.toLocalDate().minusDays(1).toString();
+            } else {
+                submitDate = now.toLocalDate().toString();
+            }
+        }
+        return pmTimeConfService.submitCount(submitDate);
+    }
+
+    @GetMapping("/submitPage")
+    public CommonPage<Object> submitPage(@RequestParam(value = "queryType", required = false, defaultValue = "0") Integer queryType,
+                                         @RequestParam(value = "submitDate", required = false) String submitDate,
+                                         @RequestParam(value = "reportId", required = false) Integer reportId,
+                                         @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
+                                         @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
+        if (StringUtils.isBlank(submitDate)) {
+            submitDate = LocalDate.now().toString();
+        }
+        return pmTimeConfService.submitPage(submitDate, queryType, reportId, pageNum, pageSize);
+    }
+
+}
+

+ 1 - 1
service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/PmWorkContentController.java

@@ -112,7 +112,7 @@ public class PmWorkContentController {
     @GetMapping("/slide")
     public ApiResult<PmWorkReportSlideVO> slide(@RequestParam(value = "upOrDown", required = false) Integer upOrDown,
                                                 @RequestParam(value = "slideSum", required = false) Integer slideSum,
-                                                @RequestParam(value = "submitDate", required = true) LocalDateTime submitDate){
+                                                @RequestParam(value = "submitDate") LocalDateTime submitDate){
         return ApiResult.success(pmWorkContentService.slide(upOrDown, slideSum, submitDate));
     }
 

+ 4 - 2
service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/web/PmWorkReportController.java

@@ -63,8 +63,10 @@ public class PmWorkReportController {
      * @return
      */
     @GetMapping("/workTimeTotal")
-    public ApiResult<PmProjectTotalWorkTimeVo> weekWork(Integer dateType, Integer dateNum) {
-        return ApiResult.success(pmWorkReportService.countTime(dateType, dateNum));
+    public ApiResult<PmProjectTotalWorkTimeVo> weekWork(@RequestParam(value = "nowYear", required = false) Integer nowYear,
+                                                        @RequestParam(value = "dateType") Integer dateType,
+                                                        @RequestParam(value = "dateNum") Integer dateNum) {
+        return ApiResult.success(pmWorkReportService.countTime(nowYear, dateType, dateNum));
     }
 
     /**

+ 87 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/domain/PmTimeConf.java

@@ -0,0 +1,87 @@
+package com.usky.iot.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * <p>
+ * 提交时间配置表
+ * </p>
+ *
+ * @author fu
+ * @since 2025-01-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class PmTimeConf implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 时间配置表主键ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 开始提交时间
+     */
+    private LocalTime startTime;
+
+    /**
+     * 正常提交时间
+     */
+    private LocalTime onTime;
+
+    /**
+     * 结束提交时间
+     */
+    private LocalTime endTime;
+
+    /**
+     * 配置名称
+     */
+    private String confName;
+
+    /**
+     * 配置类型(PM:工作报告提交时间配置)
+     */
+    private String confType;
+
+    /**
+     * 创建者
+     */
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新者
+     */
+    private String updateBy;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 部门ID
+     */
+    private Long deptId;
+
+    /**
+     * 租户ID
+     */
+    private Integer tenantId;
+
+
+}

+ 16 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/mapper/PmTimeConfMapper.java

@@ -0,0 +1,16 @@
+package com.usky.iot.mapper;
+
+import com.usky.iot.domain.PmTimeConf;
+import com.usky.common.mybatis.core.CrudMapper;
+
+/**
+ * <p>
+ * 工作报告提交时间配置表 Mapper 接口
+ * </p>
+ *
+ * @author fu
+ * @since 2025-01-10
+ */
+public interface PmTimeConfMapper extends CrudMapper<PmTimeConf> {
+
+}

+ 21 - 2
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/DmpDeviceInfoService.java

@@ -5,8 +5,7 @@ import com.usky.common.core.bean.CommonPage;
 import com.usky.common.mybatis.core.CrudService;
 import com.usky.demo.domain.LastInnerQueryVO;
 import com.usky.iot.domain.DmpDeviceInfo;
-import com.usky.iot.service.vo.BaseFacilityDeviceVO;
-import com.usky.iot.service.vo.DmpDeviceInfoRequest;
+import com.usky.iot.service.vo.*;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.multipart.MultipartFile;
@@ -78,4 +77,24 @@ public interface DmpDeviceInfoService extends CrudService<DmpDeviceInfo> {
     List<DataAverageExportVO> DataAverageExport(DataAverageRequestVO requestVO);
 
     Map<String,Object> control(String productCode, String deviceUuid, String commandCode, String commandValue, String domain, Long userId, String userName);
+
+    /**
+     * @description: 获取设备topic列表
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/2/7 17:49
+     * @param: [pageNum, pageSize]
+     * @return: java.util.List<com.usky.iot.service.vo.DmpTopicResponseVO>
+     **/
+    CommonPage<DmpTopicResponseVO> topic(DmpTopicRequestVO requestVO);
+
+    /**
+     * @description: 获取设备告警请求信息
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/2/7 17:49
+     * @param: [deviceId, productCode]
+     * @return: com.usky.iot.service.vo.DmpHttpAlarmResponseVO
+     **/
+    DmpHttpAlarmResponseVO alarmResponse(String deviceId, String productCode);
 }

+ 34 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/PmTimeConfService.java

@@ -0,0 +1,34 @@
+package com.usky.iot.service;
+
+import com.usky.common.core.bean.CommonPage;
+import com.usky.iot.domain.PmTimeConf;
+import com.usky.common.mybatis.core.CrudService;
+import com.usky.iot.domain.PmWorkReport;
+import com.usky.iot.service.vo.PmSubmitCountResponseVO;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 工作报告提交时间配置表 服务类
+ * </p>
+ *
+ * @author fu
+ * @since 2025-01-10
+ */
+public interface PmTimeConfService extends CrudService<PmTimeConf> {
+
+    /**
+     * 获取提交统计
+     * @param submitDate
+     * @return
+     */
+    PmSubmitCountResponseVO submitCount(String submitDate);
+
+    /**
+     * 获取提交列表
+     * @return
+     */
+    CommonPage<Object> submitPage(String submitDate, Integer queryType, Integer reportId, Integer pageNum, Integer pageSize);
+}

+ 2 - 1
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/PmWorkReportService.java

@@ -7,6 +7,7 @@ import com.usky.common.mybatis.core.CrudService;
 import com.usky.iot.service.vo.PmProjectTotalWorkTimeVo;
 
 import java.time.LocalDateTime;
+import java.time.temporal.TemporalAccessor;
 import java.util.List;
 import java.util.Map;
 
@@ -39,7 +40,7 @@ public interface PmWorkReportService extends CrudService<PmWorkReport> {
      * 工时计算
      * @return
      */
-    PmProjectTotalWorkTimeVo countTime(Integer dateType, Integer dateNum);
+    PmProjectTotalWorkTimeVo countTime(Integer nowYear, Integer dateType, Integer dateNum);
 
     /**
      * 定时发送

+ 34 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/enums/TopicInfo.java

@@ -0,0 +1,34 @@
+package com.usky.iot.service.enums;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/2/7
+ */
+public enum TopicInfo {
+
+    GATEWAY_DEVICE("网关设备","gatewayDevice"),
+    IOT_PLATFORM("物联网平台","IoTPlatform"),
+    ADD_REMARKS("网关设备添加子设备","add"),
+    INFO_REMARKS("网关设备指标数据上报","info"),
+    CONTROL_REMARKS("网关设备命令下发","control"),
+    CONTROL_RESPONSE_REMARKS("网关设备命令响应","controlResponse");
+
+    private String value;
+    private String letter;
+
+    TopicInfo(String value, String letter){
+        this.value = value;
+        this.letter = letter;
+    }
+
+
+    public String getValue() {
+        return value;
+    }
+
+    public String getLetter(){
+        return letter;
+    }
+}

File diff suppressed because it is too large
+ 446 - 214
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/DmpDeviceInfoServiceImpl.java


+ 317 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/PmTimeConfServiceImpl.java

@@ -0,0 +1,317 @@
+package com.usky.iot.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.usky.common.core.bean.CommonPage;
+import com.usky.common.core.exception.BusinessException;
+import com.usky.common.security.utils.SecurityUtils;
+import com.usky.iot.domain.PmReceive;
+import com.usky.iot.domain.PmTimeConf;
+import com.usky.iot.domain.PmWorkContent;
+import com.usky.iot.domain.PmWorkReport;
+import com.usky.iot.mapper.*;
+import com.usky.iot.service.PmTimeConfService;
+import com.usky.common.mybatis.core.AbstractCrudService;
+import com.usky.iot.service.vo.PmReportReadersVO;
+import com.usky.iot.service.vo.PmSubmitCountResponseVO;
+import com.usky.system.domain.SysUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 工作报告提交时间配置表 服务实现类
+ * </p>
+ *
+ * @author fu
+ * @since 2025-01-10
+ */
+@Service
+public class PmTimeConfServiceImpl extends AbstractCrudService<PmTimeConfMapper, PmTimeConf> implements PmTimeConfService {
+
+    @Autowired
+    private PmTimeConfMapper pmTimeConfMapper;
+
+    @Autowired
+    private PmWorkReportMapper pmWorkReportMapper;
+
+    @Autowired
+    private SysUserMapper sysUserMapper;
+
+    @Autowired
+    private PmWorkContentMapper pmWorkContentMapper;
+
+    @Autowired
+    private PmReceiveMapper pmReceiveMapper;
+
+    // 统计工作报提交
+    @Override
+    public PmSubmitCountResponseVO submitCount(String submitDate) {
+        Integer tenantId = SecurityUtils.getTenantId();
+        PmSubmitCountResponseVO responseVO = new PmSubmitCountResponseVO();
+        LocalDate countDate = LocalDate.parse(submitDate);
+
+        // 查询时间配置
+        PmTimeConf timeConf = getTimeConf(tenantId);
+        if (timeConf == null) {
+            throw new RuntimeException("未找到工作报提交统计告时间配置,请联系管理员");
+        } else if (countDate.equals(LocalDate.now()) && timeConf.getStartTime().isAfter(LocalTime.now())) {
+            throw new RuntimeException("不可查看未来数据");
+        }
+
+        LocalTime startTime = timeConf.getStartTime();
+        LocalTime onTime = timeConf.getOnTime();
+        LocalTime endTime = timeConf.getEndTime();
+        LocalDateTime startDateTime = LocalDateTime.of(countDate, startTime);
+        LocalDateTime onDateTime = LocalDateTime.of(countDate, onTime);
+        LocalDateTime endDateTime = LocalDateTime.of(countDate, endTime).plusDays(1);
+
+        // 按时提交
+        List<PmWorkReport> pmWorkReports = reportList(tenantId, 0, startDateTime, onDateTime, endDateTime);
+        Integer submitOnTime = pmWorkReports.size();
+
+        // 延迟提交
+        List<PmWorkReport> pmWorkReports2 = reportList(tenantId, 1, startDateTime, onDateTime, endDateTime);
+        Integer submitLate = pmWorkReports2.size();
+
+        Integer suerSum = users(tenantId).size();
+        // 未提交
+        Integer notSubmitted = suerSum - submitOnTime - submitLate;
+
+        responseVO.setSubmitOnTime(submitOnTime);
+        responseVO.setSubmitLate(submitLate);
+        responseVO.setNotSubmitted(notSubmitted);
+        responseVO.setStatisticalDate(countDate);
+        return responseVO;
+    }
+
+    @Override
+    public CommonPage<Object> submitPage(String submitDate, Integer queryType, Integer reportId, Integer pageNum, Integer pageSize) {
+        Integer tenantId = SecurityUtils.getTenantId();
+        Long userId2 = SecurityUtils.getUserId();
+        LocalDate countDate = LocalDate.parse(submitDate);
+
+        List<SysUser> userList = users(tenantId);
+
+        PmTimeConf timeConf = getTimeConf(tenantId);
+        if (timeConf == null) {
+            throw new BusinessException("未找到工作报提交统计告时间配置,请联系管理员");
+        }
+
+        LocalTime startTime = timeConf.getStartTime();
+        LocalTime onTime = timeConf.getOnTime();
+        LocalTime endTime = timeConf.getEndTime();
+        LocalDateTime startDateTime = LocalDateTime.of(countDate, startTime);
+        LocalDateTime onDateTime = LocalDateTime.of(countDate, onTime);
+        LocalDateTime endDateTime = LocalDateTime.of(countDate, endTime).plusDays(1);
+
+        LambdaQueryWrapper<PmWorkReport> reportQuery = Wrappers.lambdaQuery();
+        reportQuery.eq(PmWorkReport::getTenantId, tenantId).eq(PmWorkReport::getReportStatus, 1);
+
+        if (reportId != null && reportId != 0) {
+            reportQuery.eq(PmWorkReport::getId, reportId);
+        } else {
+            switch (queryType) {
+                // 按时提交
+                case 0:
+                    reportQuery.between(PmWorkReport::getSubmitDate, startDateTime, onDateTime);
+                    break;
+                // 延迟提交
+                case 1:
+                    reportQuery.between(PmWorkReport::getSubmitDate, onDateTime, endDateTime);
+                    break;
+                // 未提交
+                case 2:
+                    List<Long> userId = new ArrayList<>();
+                    // 按时提交
+                    List<PmWorkReport> pmWorkReports = reportList(tenantId, 0, startDateTime, onDateTime, endDateTime);
+                    pmWorkReports.forEach(report -> {
+                        userId.add(report.getSubmitterId());
+                    });
+                    // 延迟提交
+                    List<PmWorkReport> pmWorkReports2 = reportList(tenantId, 1, startDateTime, onDateTime, endDateTime);
+                    pmWorkReports2.forEach(report -> {
+                        userId.add(report.getSubmitterId());
+                    });
+                    // 未提交
+                    List<SysUser> unSubmitted = userList.stream().filter(user -> !userId.contains(user.getUserId())).collect(Collectors.toList());
+
+                    int total = unSubmitted.size();
+                    int start = (pageNum - 1) * pageSize;
+                    int end = Math.min(start + pageSize, total);
+
+                    List<SysUser> pageData;
+                    if (start < total) {
+                        pageData = unSubmitted.subList(start, end);
+                    } else {
+                        pageData = Collections.emptyList();
+                    }
+                    return new CommonPage<>(Collections.singletonList(pageData), total, pageSize, pageNum);
+
+                default:
+                    throw new BusinessException("报告统计分页参数错误!");
+            }
+            if (countDate.equals(LocalDate.now()) && timeConf.getStartTime().isAfter(LocalTime.now())) {
+                throw new BusinessException("不可查看未来数据");
+            }
+            reportQuery.eq(PmWorkReport::getReportDate, countDate);
+        }
+
+        List<PmWorkReport> pmWorkReports = pmWorkReportMapper.selectList(reportQuery);
+        if (pmWorkReports.isEmpty()) {
+            return new CommonPage<>();
+        }
+        List<Integer> reportIds = new ArrayList<>();
+        pmWorkReports.forEach(report -> {
+            reportIds.add(report.getId());
+        });
+
+        LambdaQueryWrapper<PmWorkContent> reportContents = Wrappers.lambdaQuery();
+        reportContents.in(PmWorkContent::getReportId, reportIds);
+        List<PmWorkContent> pmWorkContentList = pmWorkContentMapper.selectList(reportContents);
+
+        // 查询已读状态
+        LambdaQueryWrapper<PmReceive> statusQuery = Wrappers.lambdaQuery();
+        statusQuery.select(PmReceive::getReportId, PmReceive::getReadFlag).eq(PmReceive::getReceiverId, userId2);
+        if (reportId != null && reportId != 0) {
+            statusQuery.eq(PmReceive::getReportId, reportId);
+        } else {
+            statusQuery.in(PmReceive::getReportId, reportIds);
+        }
+        List<PmReceive> receiveList2 = pmReceiveMapper.selectList(statusQuery);
+
+        Map<Integer, Integer> reportReadFlags = new HashMap<>();
+        for (PmReceive pmReceive : receiveList2) {
+            Integer reportId2 = pmReceive.getReportId();
+            reportReadFlags.put(reportId2, pmReceive.getReadFlag());
+        }
+
+        List<Long> userIds = new ArrayList<>();
+
+        // 已读未读数量查询
+        List<PmReceive> receives = new ArrayList<>();
+        receives = receives(reportIds);
+        Map<Integer, List<PmReceive>> reportReceivesMap = new HashMap<>();
+        reportReceivesMap = receives.stream().collect(Collectors.groupingBy(PmReceive::getReportId));
+        for (PmWorkReport report : pmWorkReports) {
+            List<PmWorkContent> contents = pmWorkContentList.stream().filter(content -> content.getReportId().equals(report.getId())).collect(Collectors.toList());
+            report.setWorkContents(contents);
+            userIds.add(report.getSubmitterId());
+
+            Integer readFlagValue = reportReadFlags.get(report.getId());
+            report.setReadFlag(readFlagValue);
+
+            // 创建人名字替换
+            if (!userIds.isEmpty()) {
+                List<SysUser> nickNames = nickNames(userIds);
+                Map<Long, String> userNicknameMap = nickNames.stream().collect(Collectors.toMap(SysUser::getUserId, SysUser::getNickName));
+                report.setCreateBy(userNicknameMap.get(report.getSubmitterId()));
+            }
+
+            List<Long> readAlready = new ArrayList<>();
+            List<Long> readNotAlready = new ArrayList<>();
+            int readCount = 0;
+            int unreadCount = 0;
+            if (!reportReceivesMap.isEmpty()) {
+                List<PmReceive> reportReceives = reportReceivesMap.getOrDefault(report.getId(), Collections.emptyList());
+                for (PmReceive pmReceive : reportReceives) {
+                    if (pmReceive.getReadFlag() == 1) {
+                        readCount++;
+                        readAlready.add(pmReceive.getReceiverId());
+                    } else {
+                        unreadCount++;
+                        readNotAlready.add(pmReceive.getReceiverId());
+                    }
+                }
+            }
+
+            PmReportReadersVO readUnreadVO = new PmReportReadersVO(readAlready, readNotAlready, readCount, unreadCount);
+            report.setPmReportReaders(readUnreadVO);
+
+            // 头像
+            for (SysUser sysUser : userList) {
+                if (sysUser.getUserId().equals(report.getSubmitterId())) {
+                    report.setAvatar(sysUser.getAvatar());
+                    break;
+                }
+            }
+        }
+
+        int total = pmWorkReports.size();
+        int start = (pageNum - 1) * pageSize;
+        int end = Math.min(start + pageSize, total);
+
+        List<PmWorkReport> pageData;
+        if (start < total) {
+            pageData = pmWorkReports.subList(start, end);
+        } else {
+            pageData = Collections.emptyList();
+        }
+
+        return new CommonPage<>(Collections.singletonList(pageData), total, pageSize, pageNum);
+    }
+
+    // 查询已读未读
+    private List<PmReceive> receives(List<Integer> reports) {
+        LambdaQueryWrapper<PmReceive> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.select(PmReceive::getReportId, PmReceive::getReadFlag, PmReceive::getReceiverId).in(PmReceive::getReportId, reports);
+        return pmReceiveMapper.selectList(queryWrapper);
+    }
+
+    // 构建查询条件,返回按时提交和延迟提交列表
+    private List<PmWorkReport> reportList(Integer tenantId, Integer queryType, LocalDateTime startDateTime, LocalDateTime onDateTime, LocalDateTime endDateTime) {
+
+        LocalDate countDate = startDateTime.toLocalDate();
+
+        LambdaQueryWrapper<PmWorkReport> reportQuery = new LambdaQueryWrapper<>();
+        reportQuery.eq(PmWorkReport::getTenantId, tenantId)
+                .eq(PmWorkReport::getReportDate, countDate);
+        switch (queryType) {
+            // 按时提交
+            case 0:
+                reportQuery.between(PmWorkReport::getSubmitDate, startDateTime, onDateTime);
+                break;
+            // 延迟提交
+            case 1:
+                reportQuery.between(PmWorkReport::getSubmitDate, onDateTime, endDateTime);
+                break;
+        }
+        return pmWorkReportMapper.selectList(reportQuery);
+    }
+
+    // 获取报告时间配置
+    private PmTimeConf getTimeConf(Integer tenantId) {
+        LambdaQueryWrapper<PmTimeConf> timeConfQuery = new LambdaQueryWrapper<>();
+        timeConfQuery.select(PmTimeConf::getStartTime, PmTimeConf::getOnTime, PmTimeConf::getEndTime)
+                .eq(PmTimeConf::getTenantId, tenantId)
+                .eq(PmTimeConf::getConfType, "PM");
+        return pmTimeConfMapper.selectOne(timeConfQuery);
+    }
+
+    // 查询用户信息
+    private List<SysUser> users(Integer tenantId) {
+        LambdaQueryWrapper<SysUser> userQuery = new LambdaQueryWrapper<>();
+        userQuery.select(SysUser::getUserId, SysUser::getDeptId, SysUser::getUserName, SysUser::getNickName, SysUser::getPhonenumber,
+                        SysUser::getAvatar, SysUser::getSex, SysUser::getAddress, SysUser::getEmail)
+                .eq(SysUser::getTenantId, tenantId)
+                .eq(SysUser::getStatus, 0)
+                .eq(SysUser::getDelFlag, 0)
+                .eq(SysUser::getUserType, "00");
+        return sysUserMapper.selectList(userQuery);
+    }
+
+    // 获取用户昵称
+    private List<SysUser> nickNames(List<Long> userIds) {
+        LambdaQueryWrapper<SysUser> userQuery = new LambdaQueryWrapper<>();
+        userQuery.select(SysUser::getUserId, SysUser::getNickName)
+                .in(SysUser::getUserId, userIds);
+        return sysUserMapper.selectList(userQuery);
+    }
+
+}

+ 0 - 2
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/PmWorkContentServiceImpl.java

@@ -820,8 +820,6 @@ public class PmWorkContentServiceImpl extends AbstractCrudService<PmWorkContentM
         if (!userId.isEmpty()) {
             userNameQuery.eq(SysUser::getDelFlag, 0).eq(SysUser::getStatus, 0).in(SysUser::getUserId, userId);
             return sysUserMapper.selectList(userNameQuery);
-        } else if (workerOrProject == 2) {
-            userNameQuery.apply(Objects.nonNull(DataScopeContextHolder.getDataScopeSql()), DataScopeContextHolder.getDataScopeSql());
         } else {
             userNameQuery.eq(SysUser::getUserId, SecurityUtils.getUserId());
         }

+ 36 - 15
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/PmWorkReportServiceImpl.java

@@ -33,6 +33,8 @@ import java.time.DayOfWeek;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.Year;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
 import java.time.temporal.TemporalAdjusters;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -217,13 +219,13 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
 
         List<PmWorkContent> workContents = pmWorkReport.getWorkContents();
         if (workContents == null) {
-            throw new BusinessException("报告内容不能为空,请检查!");
+            throw new BusinessException("报告内容不能为空,请检查后提交!");
         } else {
             for (PmWorkContent workContent : workContents) {
                 BigDecimal workTime = workContent.getWorkTime();
                 // 单个工时大于零
                 if (workTime == null) {
-                    throw new BusinessException("工时不能为空,请检查!");
+                    throw new BusinessException("工时不能为空,请检查后提交!");
                 } else if (workTime.compareTo(BigDecimal.ZERO) <= 0) {
                     throw new BusinessException("工时必须大于零!");
                 } else if (workTime.scale() > 1) {
@@ -235,14 +237,14 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
                 String workContent1 = workContent.getWorkContent();
                 // 工作内容不允许为空或空字符串
                 if (StringUtils.isBlank(workContent1)) {
-                    throw new BusinessException("工作内容不能为空,请检查!");
+                    throw new BusinessException("工作内容不能为空,请检查后提交!");
                 }
             }
         }
         Set<Integer> projectIds2 = new HashSet<>();
         for (PmWorkContent workContent : pmWorkReport.getWorkContents()) {
             if (!projectIds2.add(workContent.getProjectId())) {
-                throw new BusinessException("存在重复项目,请检查!");
+                throw new BusinessException("存在重复项目,请检查后提交!");
             }
         }
         for (PmWorkContent a : pmWorkReport.getWorkContents()) {
@@ -251,11 +253,20 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
         // 判断总工时是否超过24h
         BigDecimal maxWorkTimePerDay = BigDecimal.valueOf(24);
         if (totalWorkTime.compareTo(maxWorkTimePerDay) >= 0) {
-            throw new BusinessException("一天24小时都不够你用,请检查当日总工时!");
+            throw new BusinessException("总工时超过24小时,请检查后提交!");
         }
 
         // 判断是否携带reportId,不写带则为新增报告,携带则为编辑(更新)报告
         if (rid == null) {
+            // 判断是否今天已提交过
+            LambdaQueryWrapper<PmWorkReport> wrapper = Wrappers.lambdaQuery();
+            wrapper.eq(PmWorkReport::getReportDate, pmWorkReport.getReportDate())
+                    .eq(PmWorkReport::getSubmitterId, userId)
+                    .eq(PmWorkReport::getTenantId, tenantId);
+            if (!pmWorkReportMapper.selectList(wrapper).isEmpty()) {
+                throw new BusinessException("今天已提交工作报告,请勿重复提交!");
+            }
+
             PmWorkReport newReport = new PmWorkReport();
             newReport.setReportDate(pmWorkReport.getReportDate());
             newReport.setSubmitterId(userId);
@@ -278,15 +289,14 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
                     newReport.setTimingTime(timingTime);
                     newReport.setReportStatus(0);
                 } else {
-                    throw new BusinessException("定时发送支持选中5分钟后的时间,请重新选择时间");
+                    throw new BusinessException("定时发送支持选中5分钟后的时间,请重新选择时间");
                 }
             }
             try {
                 pmWorkReportMapper.insert(newReport);
 
             } catch (Exception e) {
-                e.printStackTrace();
-                throw new BusinessException("已存在重复数据,一人一天一篇报告!");
+                throw new BusinessException("新增报告异常!请联系管理员" + e);
             }
 
             // 获取报告中所有项目id
@@ -356,6 +366,7 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
                 rp.setId(rid);
                 rp.setSubmitterId(pmWorkReport.getSubmitterId());
                 rp.setCcTo(ccTo);
+                rp.setSubmitDate(LocalDateTime.now());
                 rp.setCoordinateWork(pmWorkReport.getCoordinateWork());
                 rp.setTomorrowPlan(pmWorkReport.getTomorrowPlan());
                 rp.setCreateBy(pmWorkReport.getCreateBy());
@@ -464,11 +475,11 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
     }
 
     @Override
-    public PmProjectTotalWorkTimeVo countTime(Integer dateType, Integer dateNum) {
+    public PmProjectTotalWorkTimeVo countTime(Integer nowDate, Integer dateType, Integer dateNum) {
         int scale = 4;
         RoundingMode roundingMode = RoundingMode.HALF_UP;
         PmProjectTotalWorkTimeVo projectTotalWorkTimeVo = new PmProjectTotalWorkTimeVo();
-        Map<String, LocalDateTime> stringLocalDateTimeMap = countWeekOrMonth(dateType, dateNum);
+        Map<String, LocalDateTime> stringLocalDateTimeMap = countWeekOrMonth(nowDate, dateType, dateNum);
         LocalDateTime startTime = stringLocalDateTimeMap.get("start");
         LocalDateTime endTime = stringLocalDateTimeMap.get("end");
         BigDecimal totalWorkTime = BigDecimal.ZERO;
@@ -518,10 +529,12 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
      * @param: [dateType, dateNum]
      * @return: java.util.Map<java.lang.String, java.time.LocalDateTime>
      **/
-    public Map<String, LocalDateTime> countWeekOrMonth(Integer dateType, Integer dateNum) {
+    public Map<String, LocalDateTime> countWeekOrMonth(Integer nowYear, Integer dateType, Integer dateNum) {
         Map<String, LocalDateTime> timePeriod = new HashMap<>();
-        LocalDate today = LocalDate.now();
-        Year currentYear = Year.from(today);
+        Year currentYear = Year.now();
+        if (nowYear != null && nowYear > 0) {
+            currentYear = Year.of(nowYear);
+        }
 
         if (dateType == 1) {
             LocalDate lastDayOfYear = currentYear.atDay(currentYear.length());
@@ -531,8 +544,16 @@ public class PmWorkReportServiceImpl extends AbstractCrudService<PmWorkReportMap
                 throw new BusinessException("周数错误!请重新选择");
             }
 
-            LocalDate firstMonday = currentYear.atDay(1).with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
-            LocalDate startOfWeek = firstMonday.plusWeeks(dateNum - 1);
+            int yearValue = currentYear.getValue();
+            LocalDate firstDayOfYear = LocalDate.of(yearValue, 1, 1);
+            LocalDate firstMondayOfYear = firstDayOfYear.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
+
+            DayOfWeek dayOfWeek = firstDayOfYear.getDayOfWeek();
+            if (dayOfWeek != DayOfWeek.MONDAY) {
+                dateNum -= 1;
+            }
+
+            LocalDate startOfWeek = firstMondayOfYear.plusWeeks(dateNum - 1);
             LocalDate endOfWeek = startOfWeek.plusWeeks(1).minusDays(1);
             LocalDateTime startTimeOfWeek = startOfWeek.atStartOfDay();
             LocalDateTime endTimeOfWeek = endOfWeek.atTime(23, 59, 59);

+ 23 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/vo/DmpHttpAlarmResponseVO.java

@@ -0,0 +1,23 @@
+package com.usky.iot.service.vo;
+
+import lombok.Data;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/2/10
+ */
+@Data
+public class DmpHttpAlarmResponseVO {
+
+    /**
+     * 报警事件数据上报http地址
+     **/
+    private String alarmHttpUrl;
+
+    /**
+     * 报警事件数据上报参数body
+     **/
+    private String alarmPayload;
+}

+ 79 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/vo/DmpTopicRequestVO.java

@@ -0,0 +1,79 @@
+package com.usky.iot.service.vo;
+
+import lombok.Data;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/2/10
+ */
+@Data
+public class DmpTopicRequestVO {
+
+    /**
+     * topic类型
+     **/
+    private String topicType;
+
+    /**
+     * 产品编码
+     **/
+    private String productCode;
+
+    /**
+     * 产品id
+     **/
+    private Integer productId;
+
+    /**
+     * 设备id
+     **/
+    private String deviceId;
+
+    /**
+     * 设备唯一标识
+     **/
+    private String deviceUuid;
+
+    /**
+     * 设备名称
+     **/
+    private String deviceName;
+
+    /**
+     * sim卡号
+     **/
+    private String simCode;
+
+    /**
+     * 安装位置
+     **/
+    private String installAddress;
+
+    /**
+     * 时间戳
+     **/
+    private Long timestamp;
+
+    /**
+     * 属性值集合
+     **/
+    private String metrics;
+
+    /**
+     * 标签值集合
+     **/
+    private String tags;
+
+    /**
+     * 页码
+     **/
+    private Integer pageNum;
+
+    /**
+     * 每页条数
+     **/
+    private Integer pageSize;
+
+}

+ 57 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/vo/DmpTopicResponseVO.java

@@ -0,0 +1,57 @@
+package com.usky.iot.service.vo;
+
+import com.usky.iot.domain.DmpProductAttribute;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/2/7
+ */
+@Data
+public class DmpTopicResponseVO {
+
+    /**
+     * topic
+     **/
+    private String topic;
+
+    /**
+     * 发布者
+     **/
+    private String publisher;
+
+    /**
+     * 订阅者
+     **/
+    private String subscriber;
+
+    /**
+     * 备注
+     **/
+    private String remarks;
+
+    /**
+     * mqtt数据上报数据
+     **/
+    private String topicPayload;
+
+    /**
+     * http报警数据上报地址
+     **/
+    private String alarm;
+
+    /**
+     * http报警数据上报数据
+     **/
+    private String alarmPayload;
+
+    /**
+     * 产品属性
+     **/
+    private List<DmpProductAttribute> productAttributeList;
+
+}

+ 65 - 0
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/vo/PmSubmitCountResponseVO.java

@@ -0,0 +1,65 @@
+package com.usky.iot.service.vo;
+
+import java.time.LocalDate;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/1/10
+ */
+public class PmSubmitCountResponseVO {
+
+    /**
+     * 按时提交
+     **/
+    private Integer submitOnTime;
+
+    /**
+     * 迟交
+     **/
+    private Integer submitLate;
+
+    /**
+     * 未提交
+     **/
+    private Integer notSubmitted;
+
+    /**
+     * 统计日期
+     **/
+    private LocalDate statisticalDate;
+
+    public Integer getSubmitOnTime() {
+        return submitOnTime;
+    }
+
+    public void setSubmitOnTime(Integer submitOnTime) {
+        this.submitOnTime = submitOnTime;
+    }
+
+    public Integer getSubmitLate() {
+        return submitLate;
+    }
+
+    public void setSubmitLate(Integer submitLate) {
+        this.submitLate = submitLate;
+    }
+
+    public Integer getNotSubmitted() {
+        return notSubmitted;
+    }
+
+    public void setNotSubmitted(Integer notSubmitted) {
+        this.notSubmitted = notSubmitted;
+    }
+
+    public LocalDate getStatisticalDate() {
+        return statisticalDate;
+    }
+
+    public void setStatisticalDate(LocalDate statisticalDate) {
+        this.statisticalDate = statisticalDate;
+    }
+
+}

+ 19 - 0
service-iot/service-iot-biz/src/main/resources/mapper/iot/PmTimeConfMapper.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.usky.iot.mapper.PmTimeConfMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.usky.iot.domain.PmTimeConf">
+        <id column="id" property="id" />
+        <result column="start_time" property="startTime" />
+        <result column="on_time" property="onTime" />
+        <result column="end_time" property="endTime" />
+        <result column="create_by" property="createBy" />
+        <result column="create_time" property="createTime" />
+        <result column="update_by" property="updateBy" />
+        <result column="update_time" property="updateTime" />
+        <result column="dept_id" property="deptId" />
+        <result column="tenant_id" property="tenantId" />
+    </resultMap>
+
+</mapper>

+ 18 - 69
service-oa/service-oa-biz/pom.xml

@@ -14,98 +14,47 @@
             <artifactId>common-cloud-starter</artifactId>
         </dependency>
 
-        <dependency>
-            <groupId>com.usky</groupId>
-            <artifactId>service-backend-api</artifactId>
-            <version>0.0.1</version>
-        </dependency>
-
         <dependency>
             <groupId>com.usky</groupId>
             <artifactId>service-oa-api</artifactId>
             <version>0.0.1</version>
         </dependency>
 
-        <dependency>
-            <groupId>cn.afterturn</groupId>
-            <artifactId>easypoi-spring-boot-starter</artifactId>
-            <version>4.1.0</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.aliyun</groupId>
-            <artifactId>aliyun-java-sdk-core</artifactId>
-            <version>4.5.16</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.aliyun</groupId>
-            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
-            <version>1.1.0</version>
-        </dependency>
-
-        <!--MQTT依赖-->
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-integration</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.springframework.integration</groupId>
-            <artifactId>spring-integration-mqtt</artifactId>
-        </dependency>
-        <!--websocket依赖-->
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-websocket</artifactId>
-            <version>5.2.8.RELEASE</version>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
         </dependency>
+        <!-- Pagehelper -->
         <dependency>
-            <groupId>com.usky</groupId>
-            <artifactId>service-agbox-api</artifactId>
-            <version>0.0.1</version>
-            <scope>compile</scope>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
         </dependency>
 
         <dependency>
             <groupId>com.usky</groupId>
-            <artifactId>service-system-api</artifactId>
-            <version>0.0.1</version>
+            <artifactId>ruoyi-common-core</artifactId>
         </dependency>
 
         <dependency>
-            <groupId>com.github.binarywang</groupId>
-            <artifactId>weixin-java-mp</artifactId>
-            <version>4.3.0</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-amqp</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.usky</groupId>
-            <artifactId>service-alarm-api</artifactId>
-            <version>0.0.1</version>
-            <scope>compile</scope>
+        <groupId>com.usky</groupId>
+        <artifactId>service-system-api</artifactId>
+        <version>0.0.1</version>
         </dependency>
 
+        <!-- Excel & Word 工具 -->
         <dependency>
-            <groupId>com.usky</groupId>
-            <artifactId>ruoyi-common-core</artifactId>
+            <groupId>cn.afterturn</groupId>
+            <artifactId>easypoi-spring-boot-starter</artifactId>
+            <version>4.1.0</version>
         </dependency>
 
-        <!--钉钉-->
-        <!--获取企业accessToken(企业内部应用) 新版SDK-->
-        <dependency>
-            <groupId>com.aliyun</groupId>
-            <artifactId>dingtalk</artifactId>
-            <version>2.1.34</version>
-        </dependency>
-        <!--旧版SDK-->
+        <!-- 流程XML解析 -->
+        <!-- https://mvnrepository.com/artifact/org.dom4j/dom4j -->
         <dependency>
-            <groupId>com.aliyun</groupId>
-            <artifactId>alibaba-dingtalk-service-sdk</artifactId>
-            <version>2.0.0</version>
+            <groupId>org.dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>2.1.1</version>
         </dependency>
 
     </dependencies>

+ 0 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/MybatisGeneratorUtils.java


+ 0 - 2
service-oa/service-oa-biz/src/main/java/com/usky/oa/ServiceOaApplication.java

@@ -3,7 +3,6 @@ import io.swagger.annotations.SwaggerDefinition;
 import org.mybatis.spring.annotation.MapperScan;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.amqp.rabbit.annotation.EnableRabbit;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.openfeign.EnableFeignClients;
@@ -24,7 +23,6 @@ import java.net.UnknownHostException;
 @MapperScan(value = "com.usky.oa.mapper")
 @ComponentScan("com.usky")
 @SpringBootApplication
-@EnableRabbit
 public class ServiceOaApplication
 {
     private static final Logger LOGGER = LoggerFactory.getLogger(ServiceOaApplication.class);

+ 108 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/controller/MybatisGeneratorUtils.java

@@ -0,0 +1,108 @@
+package com.usky.oa.controller;// package com.usky.iot.controller;//package com.usky.dm.controller.web.business;//package com.usky.dm.controller.web;
+
+
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.generator.AutoGenerator;
+import com.baomidou.mybatisplus.generator.InjectionConfig;
+import com.baomidou.mybatisplus.generator.config.*;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author yq
+ * @date 2021/7/6 11:42
+ */
+public class MybatisGeneratorUtils {
+    public static void main(String[] args) {
+
+        shell("service-oa", "service-oa-biz");
+    }
+
+    private static void shell(String parentName, String model) {
+
+        AutoGenerator mpg = new AutoGenerator();
+        // 1、全局配置
+        GlobalConfig gc = new GlobalConfig();
+//        File file = new File(model);
+//        String path = file.getAbsolutePath();
+        String projectPath = System.getProperty("user.dir");
+        projectPath += "/" + parentName;
+        projectPath += "/" + model;
+        gc.setOutputDir(projectPath + "/src/main/java");  // 生成路径(一般都是生成在此项目的src/main/java下面)
+        // 修改为自己的名字
+        gc.setAuthor("fu"); // 设置作者
+        gc.setOpen(false);
+        gc.setFileOverride(true); // 第二次生成会把第一次生成的覆盖掉
+        gc.setServiceName("%sService"); // 生成的service接口名字首字母是否为I,这样设置就没有
+        gc.setBaseResultMap(true); // 生成resultMap
+        mpg.setGlobalConfig(gc);
+
+        // 2、数据源配置
+        // 修改数据源
+        DataSourceConfig dsc = new DataSourceConfig();
+        dsc.setUrl("jdbc:mysql://192.168.10.165:3306/usky-cloud?useUnicode=true&serverTimezone=GMT&useSSL=false&characterEncoding=utf8");
+        dsc.setDriverName("com.mysql.jdbc.Driver");
+        dsc.setUsername("root");
+        dsc.setPassword("yt123456");
+        mpg.setDataSource(dsc);
+
+        // 3、包配置
+        PackageConfig pc = new PackageConfig();
+        pc.setParent("com.usky.oa");
+        pc.setController("controller.web");
+        pc.setEntity("domain");
+        pc.setMapper("mapper");
+        pc.setService("service");
+        pc.setServiceImpl("service.impl");
+//        pc.setXml("mapper.demo");
+        // pc.setModuleName("test");
+        mpg.setPackageInfo(pc);
+
+        // 4、策略配置
+        StrategyConfig strategy = new StrategyConfig();
+        strategy.setNaming(NamingStrategy.underline_to_camel);
+        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
+        strategy.setSuperMapperClass("com.usky.common.mybatis.core.CrudMapper");
+        strategy.setSuperServiceClass("com.usky.common.mybatis.core.CrudService");
+        strategy.setSuperServiceImplClass("com.usky.common.mybatis.core.AbstractCrudService");
+        // strategy.setTablePrefix("t_"); // 表名前缀
+        strategy.setEntityLombokModel(true); // 使用lombok
+        // 修改自己想要生成的表
+        strategy.setInclude("oa_jb_document");  // 逆向工程使用的表   如果要生成多个,这里可以传入String[]
+        mpg.setStrategy(strategy);
+
+        // 关闭默认 xml 生成,调整生成 至 根目录
+        // 修改对应的模块名称
+        TemplateConfig tc = new TemplateConfig();
+        // 自定义配置
+        InjectionConfig cfg = new InjectionConfig() {
+            @Override
+            public void initMap() {
+                // to do nothing
+            }
+        };
+        // 如果模板引擎是 velocity
+        String templatePath = "/templates/mapper.xml.vm";
+        // 自定义输出配置
+        List<FileOutConfig> focList = new ArrayList<>();
+        // 自定义配置会被优先输出
+        String finalProjectPath = projectPath;
+        focList.add(new FileOutConfig(templatePath) {
+            @Override
+            public String outputFile(TableInfo tableInfo) {
+                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
+                return finalProjectPath + "/src/main/resources/mapper/oa" + "/"
+                        + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
+            }
+        });
+        cfg.setFileOutConfigList(focList);
+        mpg.setCfg(cfg);
+        tc.setXml(null);
+        mpg.setTemplate(tc);
+        // 5、执行
+        mpg.execute();
+    }
+}

+ 85 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/controller/web/OaApprovalController.java

@@ -0,0 +1,85 @@
+package com.usky.oa.controller.web;
+
+
+import com.usky.common.core.bean.CommonPage;
+import com.usky.oa.domain.OaApproval;
+import com.usky.oa.domain.OaDocument;
+import com.usky.oa.service.OaApprovalService;
+import com.usky.oa.service.vo.OaApprovalCountVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import org.springframework.stereotype.Controller;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 审批表 前端控制器
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+@RestController
+@RequestMapping("/oaApproval")
+public class OaApprovalController {
+
+    @Autowired
+    private OaApprovalService oaApprovalService;
+
+    /**
+     * @description: 审批数量统计
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2024/12/30 16:19
+     * @param: []
+     * @return: void
+     **/
+    @GetMapping("/count")
+    public OaApprovalCountVO approvalCount() {
+        return oaApprovalService.approvalCount();
+    }
+
+    /**
+     * @description: 我的待办-分页列表
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2024/12/30 16:19
+     * @param: [queryType, docNo, type, approvalStatus, startTime, endTime, pageNum, pageSize]
+     * @return: com.usky.common.core.bean.CommonPage<com.usky.oa.domain.OaApproval>
+     **/
+    @GetMapping("/pageList")
+    public CommonPage<OaApproval> pageList(@RequestParam(value = "queryType") Integer queryType,
+                                           @RequestParam(value = "docNo", required = false) String docNo,
+                                           @RequestParam(value = "formSign", required = false) String formSign,
+                                           @RequestParam(value = "approvalStatus", required = false) Integer approvalStatus,
+                                           @RequestParam(value = "startTime", required = false) String startTime,
+                                           @RequestParam(value = "endTime", required = false) String endTime,
+                                           @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
+                                           @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
+        return oaApprovalService.pageList(queryType, docNo, formSign, approvalStatus, startTime, endTime, pageNum, pageSize);
+    }
+
+    /**
+     * @description: 审批
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/17 17:32
+     * @param: [oaApproval]
+     * @return: void
+     **/
+    @PutMapping("/approve")
+    public void add(@RequestParam(value = "id") Integer id,
+                    @RequestParam(value = "approvalStatus") Integer approvalStatus,
+                    @RequestParam(value = "opinion", required = false, defaultValue = "无") String opinion) {
+        oaApprovalService.approve(id, approvalStatus, opinion);
+    }
+
+    @GetMapping("/analysisTest")
+    public void analysisTest(@RequestParam(value = "id") Integer id) {
+        oaApprovalService.analysisTest(id);
+    }
+
+}
+

+ 99 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/controller/web/OaDocumentController.java

@@ -0,0 +1,99 @@
+package com.usky.oa.controller.web;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.usky.common.core.bean.CommonPage;
+import com.usky.common.log.annotation.Log;
+import com.usky.common.log.enums.BusinessType;
+import com.usky.common.mybatis.core.CrudService;
+import com.usky.oa.domain.OaDocument;
+import com.usky.oa.service.OaDocumentService;
+import com.usky.oa.service.vo.OaApprovalCountVO;
+import org.apache.poi.ss.formula.functions.T;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import org.springframework.stereotype.Controller;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 单据总表 前端控制器
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-26
+ */
+@RestController
+@RequestMapping("/oaDocument")
+public class OaDocumentController {
+
+    @Autowired
+    private OaDocumentService oaDocumentService;
+
+    // 我的申请
+    @GetMapping("/myApplication")
+    public CommonPage<OaDocument> myApplication(@RequestParam(value = "docNo", required = false) String docNo,
+                                                @RequestParam(value = "type", required = false) String type,
+                                                @RequestParam(value = "docStatus", required = false) Integer status,
+                                                @RequestParam(value = "startTime", required = false) String startTime,
+                                                @RequestParam(value = "endTime", required = false) String endTime,
+                                                @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
+                                                @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
+        return oaDocumentService.myApplication(docNo, type, status, startTime, endTime, pageNum, pageSize);
+    }
+
+    /**
+     * @description: 新增单据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/17 14:19
+     * @param: [oaDocument]
+     * @return: void
+     **/
+    @Log(title = "新增单据", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    public void addDocument(@RequestBody JSONObject oaDocument) {
+        oaDocumentService.addDoc(oaDocument);
+    }
+
+    // 删除单据
+    @Log(title = "删除单据", businessType = BusinessType.DELETE)
+    @DeleteMapping("/delDoc/{docNo}")
+    public void delDocument(@PathVariable(value = "docNo") String docNo) {
+        oaDocumentService.delDocument(docNo);
+    }
+
+    // 单据详情
+    @GetMapping("/documentDetails")
+    public Object documentDetails(@RequestParam(value = "docNo") String docNo) {
+        return oaDocumentService.documentDetails(docNo);
+    }
+
+
+    /**
+     * @description: 更新单据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/20 15:47
+     * @param: [jsonDocument]
+     * @return: void
+     **/
+    @Log(title = "更新单据", businessType = BusinessType.UPDATE)
+    @PostMapping("/update")
+    public void approvalCount(@RequestBody JSONObject jsonDocument) {
+        oaDocumentService.updateDoc(jsonDocument);
+    }
+
+    // 提交单据
+    @Log(title = "提交单据", businessType = BusinessType.UPDATE)
+    @PutMapping("/submit")
+    public void submit(@RequestParam(value = "docNo") String docNo,
+                       @RequestParam(value = "docStatus") Integer docStatus){
+        oaDocumentService.submit(docNo, docStatus);
+    }
+
+}
+

+ 95 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/controller/web/OaFormDefinitionController.java

@@ -0,0 +1,95 @@
+package com.usky.oa.controller.web;
+
+
+import com.usky.common.core.bean.ApiResult;
+import com.usky.common.core.bean.CommonPage;
+import com.usky.common.log.annotation.Log;
+import com.usky.common.log.enums.BusinessType;
+import com.usky.oa.domain.OaFormDefinition;
+import com.usky.oa.service.OaFormDefinitionService;
+import com.usky.oa.service.enums.OaBuiltInDocument;
+import com.usky.oa.service.utils.OaDefinitionDocumentInfo;
+import com.usky.oa.service.vo.OaFormNameResponseVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 表单定义表 前端控制器
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+@RestController
+@RequestMapping("/oaFormDefinition")
+public class OaFormDefinitionController {
+
+    @Autowired
+    private OaFormDefinitionService oaFormDefinitionService;
+
+    // 新增、修改表单
+    @Log(title = "新增/修改表单", businessType = BusinessType.INSERT)
+    @PostMapping("/addForm")
+    public void addForm(@RequestBody OaFormDefinition oaFormDefinition) {
+        oaFormDefinitionService.addForm(oaFormDefinition);
+    }
+
+    // 表单状态修改(启用、停用)
+    @Log(title = "启停用表单", businessType = BusinessType.UPDATE)
+    @GetMapping("/updateStatus")
+    public void updateStatus(@RequestParam(value = "formId") Integer formId,
+                             @RequestParam(value = "formStatus") Integer formStatus) {
+        oaFormDefinitionService.validUpdateStatus(formId, formStatus);
+    }
+
+    // 删除表单
+    @Log(title = "删除表单", businessType = BusinessType.DELETE)
+    @DeleteMapping("/delForm/{formId}")
+    public void delForm(@PathVariable Integer formId) {
+        oaFormDefinitionService.delForm(formId);
+    }
+
+    // 表单管理-分页
+    @GetMapping("/manageForm")
+    public ApiResult<CommonPage<OaFormDefinition>> manageForm(@RequestParam(value = "formName", required = false) String formName,
+                                                              @RequestParam(value = "formId", required = false) Integer formId,
+                                                              @RequestParam(value = "formGroup", required = false) Integer formGroup,
+                                                              @RequestParam(value = "formStatus", required = false) Integer formStatus,
+                                                              @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
+                                                              @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
+        return ApiResult.success(oaFormDefinitionService.pageList(formId, formName, formGroup, formStatus, pageNum, pageSize));
+    }
+
+    // 内置单据枚举列表
+    @GetMapping("/builtInFormEnums")
+    public List<OaDefinitionDocumentInfo> getBuiltInDocumentList(String sign, String name) {
+        return Arrays.stream(OaBuiltInDocument.values())
+                .map(doc -> new OaDefinitionDocumentInfo(doc.getSign(), doc.getName()))
+                .filter(docInfo -> (sign == null || docInfo.getSign().equals(sign))
+                        && (name == null || docInfo.getName().contains(name)))
+                .collect(Collectors.toList());
+    }
+
+    // 我的申请-依据权限展示表单
+    @GetMapping("/myForm")
+    public List<OaFormDefinition> myForm(String formSign) {
+        return oaFormDefinitionService.selectByScope(formSign);
+    }
+
+    // 表单名称列表
+    @GetMapping("/getFormName")
+    public List<OaFormNameResponseVO> getFormName(@RequestParam(value = "formSign", required = false) String formSign,
+                                                  @RequestParam(value = "formName", required = false) String formName,
+                                                  @RequestParam(value = "formId", required = false) Integer formId) {
+        return oaFormDefinitionService.getFormName(formSign, formName, formId);
+    }
+
+
+}
+

+ 44 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/controller/web/OaJbdDocumentController.java

@@ -0,0 +1,44 @@
+package com.usky.oa.controller.web;
+
+
+import com.usky.common.log.annotation.Log;
+import com.usky.common.log.enums.BusinessType;
+import com.usky.oa.domain.OaJbdDocument;
+import com.usky.oa.service.OaJbdDocumentService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ * 加班单据表 前端控制器
+ * </p>
+ *
+ * @author fu
+ * @since 2025-01-02
+ */
+@RestController
+@RequestMapping("/oaJbDocument")
+public class OaJbdDocumentController {
+
+    @Autowired
+    private OaJbdDocumentService oaJbdDocumentService;
+
+    @Log(title = "新增加班单", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    public void addJbDocument(@RequestBody OaJbdDocument oaJbdDocument) {
+        oaJbdDocumentService.add(oaJbdDocument);
+    }
+
+    @Log(title = "更新加班单", businessType = BusinessType.UPDATE)
+    @PostMapping("/update")
+    public void updateJbDocument(OaJbdDocument oaJbdDocument) {
+        oaJbdDocumentService.update(oaJbdDocument);
+    }
+
+    @Log(title = "删除加班单", businessType = BusinessType.DELETE)
+    @DeleteMapping("/del/{docNo}")
+    public void delJbDocument(@PathVariable String docNo) {
+        oaJbdDocumentService.delByDocNo(docNo);
+    }
+
+}

+ 49 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/controller/web/OaQjdDocumentController.java

@@ -0,0 +1,49 @@
+package com.usky.oa.controller.web;
+
+
+import com.usky.common.core.bean.ApiResult;
+import com.usky.common.core.bean.CommonPage;
+import com.usky.common.log.annotation.Log;
+import com.usky.common.log.enums.BusinessType;
+import com.usky.oa.domain.OaQjdDocument;
+import com.usky.oa.service.OaQjdDocumentService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ * 请假单据表 前端控制器
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+@RestController
+@RequestMapping("/oaQjDocument")
+public class OaQjdDocumentController {
+
+    @Autowired
+    private OaQjdDocumentService oaQjdDocumentService;
+
+    // 新增请假单
+    @Log(title = "新增请假单", businessType = BusinessType.INSERT)
+    @PostMapping("/addQjDocument")
+    public void addQjDocument(@RequestBody OaQjdDocument oaQjdDocument) {
+        oaQjdDocumentService.addQjDocument(oaQjdDocument);
+    }
+
+    // 更新请假单
+    @Log(title = "更新请假单", businessType = BusinessType.UPDATE)
+    @PostMapping("/updateQjDocument")
+    public void updateQjDocument(@RequestBody OaQjdDocument oaQjdDocument) {
+        oaQjdDocumentService.updateQjDocument(oaQjdDocument);
+    }
+
+    // 删除请假单
+    @Log(title = "删除请假单", businessType = BusinessType.DELETE)
+    @DeleteMapping("/delQjDocument/{docNo}")
+    public void delQjDocument(String docNo) {
+        oaQjdDocumentService.delQjDocument(docNo);
+    }
+
+}

+ 105 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/domain/OaApproval.java

@@ -0,0 +1,105 @@
+package com.usky.oa.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * <p>
+ * 审批表
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class OaApproval implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 审批表主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 单据编号
+     */
+    private String docNo;
+
+    /**
+     * 审批人id
+     */
+    private Long approvalUid;
+
+    /**
+     * 申请人id
+     */
+    private Integer proposer;
+
+    /**
+     * 审批类型(0:审批,1:知会)
+     */
+    private Integer type;
+
+    /**
+     * 审批状态(1:审批中, 2:审批通过, 3:审批不通过)
+     */
+    private Integer approvalStatus;
+
+    /**
+     * 审批意见
+     */
+    private String opinion;
+
+    /**
+     * 提交时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime submitDate;
+
+    /**
+     * 审批时间
+     */
+    private LocalDateTime approvalDate;
+
+    /**
+     * 创建者
+     */
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新者
+     */
+    private String updateBy;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 部门id
+     */
+    private Long deptId;
+
+    /**
+     * 租户id
+     */
+    private Integer tenantId;
+
+
+}

+ 86 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/domain/OaDocument.java

@@ -0,0 +1,86 @@
+package com.usky.oa.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * <p>
+ * 单据总表
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class OaDocument implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 单据总表主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 表单定义表主键
+     */
+    private Integer formId;
+
+    /**
+     * 表单标识
+     */
+    private String type;
+
+    /**
+     * 单据编号
+     */
+    private String docNo;
+
+    /**
+     * 申请人id
+     */
+    private Long proposer;
+
+    /**
+     * 单据状态 (0:未提交可以修改,1:审批中,2:审批通过,3:审批不通过)
+     */
+    private Integer docStatus;
+
+    /**
+     * 创建者
+     */
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新者
+     */
+    private String updateBy;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 部门id
+     */
+    private Long deptId;
+
+    /**
+     * 租户id
+     */
+    private Integer tenantId;
+
+
+}

+ 135 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/domain/OaFormDefinition.java

@@ -0,0 +1,135 @@
+package com.usky.oa.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * <p>
+ * 表单定义表
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class OaFormDefinition implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 表单定义表主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 表单名称
+     */
+    private String formName;
+
+    /**
+     * 所在分组
+     */
+    private Integer formGroup;
+
+    /**
+     * 表单说明
+     */
+    private String formExplain;
+
+    /**
+     * 单据类型(0:内置表单据;1:自定义表单据)
+     */
+    private Integer formType;
+
+    /**
+     * 表单设计器配置数据
+     */
+    private String fieldInfo;
+
+    /**
+     * 流程设计器配置数据
+     */
+    private String flowInfo;
+
+    /**
+     * 表单版本
+     */
+    private Integer formVersion;
+
+    /**
+     * 表单标识(必须字母,小于4位)
+     */
+    private String formSign;
+
+    /**
+     * 表单图标
+     */
+    private String formImage;
+
+    /**
+     * 表单权限范围(0:指定部门可见;1:全员可见;2:指定人可见)
+     */
+    private Integer formScope;
+
+    /**
+     * 表单状态(1:启用;2:停用)
+     */
+    private Integer formStatus;
+
+    /*
+     * 单据编号
+     */
+    //private Integer docNo;
+
+    /**
+     * 可见部门id集合
+     */
+    private String deptIds;
+
+    /**
+     * 可见人id集合
+     */
+    private String userIds;
+
+    /**
+     * 创建者
+     */
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新者
+     */
+    private String updateBy;
+
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime updateTime;
+
+    /**
+     * 部门id
+     */
+    private Long deptId;
+
+    /**
+     * 租户id
+     */
+    private Integer tenantId;
+
+
+}

+ 118 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/domain/OaJbdDocument.java

@@ -0,0 +1,118 @@
+package com.usky.oa.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * <p>
+ * 加班单据表
+ * </p>
+ *
+ * @author fu
+ * @since 2025-01-02
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class OaJbdDocument implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 加班单据表主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 表单定义表主键
+     */
+    private Integer formId;
+
+    /**
+     * 单据编号
+     */
+    private String docNo;
+
+    /**
+     * 申请人id
+     */
+    private Long proposer;
+
+    /**
+     * 单据状态 (0:未提交可以修改,1:审批中,2:审批通过,3:审批不通过,4:撤销)
+     */
+    private Integer docStatus;
+
+    /**
+     * 开始日期
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startTime;
+
+    /**
+     * 结束日期
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime endTime;
+
+    /**
+     * 加班时长(小时)
+     */
+    private Integer duration;
+
+    /**
+     * 核算方式(默认 0:申请调休)
+     */
+    private Integer accountingMethod;
+
+    /**
+     * 加班原因
+     */
+    private String reason;
+
+    /**
+     * 图片URL(打卡记录及日报)
+     */
+    private String image;
+
+    /**
+     * 创建者
+     */
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新者
+     */
+    private String updateBy;
+
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime updateTime;
+
+    /**
+     * 部门id
+     */
+    private Long deptId;
+
+    /**
+     * 租户id
+     */
+    private Integer tenantId;
+
+
+}

+ 120 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/domain/OaQjdDocument.java

@@ -0,0 +1,120 @@
+package com.usky.oa.domain;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * <p>
+ * 请假单据表
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class OaQjdDocument implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 请假单据表主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 表单id
+     */
+    private Integer formId;
+
+    /**
+     * 1:事假,2:病假(后续附上病假单、挂号单、病历册),3:年假(连续在我司工作一年以上的,才可享受),4:调休(有已获批准的加班流程),
+     * 5:婚假(附上结婚证),6:产假(后续附上出生证明),7:陪产假(后续附上出生证明),8:丧假(父母、配偶、子女死亡可申请3天),9:工伤假,
+     * 10:孕检假(后续附上挂号单、病例册)
+     */
+    private String type;
+
+    /**
+     * 单据编号
+     */
+    private String docNo;
+
+    /**
+     * 申请人id
+     */
+    private Long proposer;
+
+    /**
+     * 单据状态 (0:未提交可以修改,1:审批中,2:审批通过,3:审批不通过,4:撤销)
+     */
+    private Integer docStatus;
+
+    /**
+     * 开始日期
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startTime;
+
+    /**
+     * 结束日期
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime endTime;
+
+    /**
+     * 请假时长(小时)
+     */
+    private Integer duration;
+
+    /**
+     * 请假事由
+     */
+    private String reason;
+
+    /**
+     * 图片URL
+     */
+    private String image;
+
+    /**
+     * 创建者
+     */
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新者
+     */
+    private String updateBy;
+
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime updateTime;
+
+    /**
+     * 部门id
+     */
+    private Long deptId;
+
+    /**
+     * 租户id
+     */
+    private Integer tenantId;
+
+
+}

+ 18 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/mapper/OaApprovalMapper.java

@@ -0,0 +1,18 @@
+package com.usky.oa.mapper;
+
+import com.usky.oa.domain.OaApproval;
+import com.usky.common.mybatis.core.CrudMapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * <p>
+ * 审批表 Mapper 接口
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+@Repository
+public interface OaApprovalMapper extends CrudMapper<OaApproval> {
+
+}

+ 34 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/mapper/OaDocumentMapper.java

@@ -0,0 +1,34 @@
+package com.usky.oa.mapper;
+
+import com.usky.oa.domain.OaDocument;
+import com.usky.common.mybatis.core.CrudMapper;
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * <p>
+ * 单据总表 Mapper 接口
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-26
+ */
+public interface OaDocumentMapper extends CrudMapper<OaDocument> {
+
+    // 动态创建表
+    void createTable(Map<String, Object> params);
+
+    // 动态插入数据
+    void insertData(Map<String, Object> params);
+
+    // 动态查询数据
+    List<Map<String, Object>> selectData(Map<String, Object> params);
+
+    // 动态更新数据
+    void updateData(Map<String, Object> params);
+
+    // 动态删除数据
+    void deleteData(Map<String, Object> params);
+}

+ 18 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/mapper/OaFormDefinitionMapper.java

@@ -0,0 +1,18 @@
+package com.usky.oa.mapper;
+
+import com.usky.oa.domain.OaFormDefinition;
+import com.usky.common.mybatis.core.CrudMapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * <p>
+ * 表单定义表 Mapper 接口
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+@Repository
+public interface OaFormDefinitionMapper extends CrudMapper<OaFormDefinition> {
+
+}

+ 18 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/mapper/OaJbdDocumentMapper.java

@@ -0,0 +1,18 @@
+package com.usky.oa.mapper;
+
+import com.usky.oa.domain.OaJbdDocument;
+import com.usky.common.mybatis.core.CrudMapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * <p>
+ * 加班单据表 Mapper 接口
+ * </p>
+ *
+ * @author fu
+ * @since 2025-01-02
+ */
+@Repository
+public interface OaJbdDocumentMapper extends CrudMapper<OaJbdDocument> {
+
+}

+ 18 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/mapper/OaQjdDocumentMapper.java

@@ -0,0 +1,18 @@
+package com.usky.oa.mapper;
+
+import com.usky.oa.domain.OaQjdDocument;
+import com.usky.common.mybatis.core.CrudMapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * <p>
+ * 请假单据表 Mapper 接口
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+@Repository
+public interface OaQjdDocumentMapper extends CrudMapper<OaQjdDocument> {
+
+}

+ 15 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/mapper/SysUserMapper.java

@@ -0,0 +1,15 @@
+package com.usky.oa.mapper;
+
+import com.usky.common.mybatis.core.CrudMapper;
+import com.usky.system.domain.SysUser;
+import org.springframework.stereotype.Repository;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/1/21
+ */
+@Repository
+public interface SysUserMapper extends CrudMapper<SysUser> {
+}

+ 50 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/OaApprovalService.java

@@ -0,0 +1,50 @@
+package com.usky.oa.service;
+
+import com.usky.common.core.bean.CommonPage;
+import com.usky.oa.domain.OaApproval;
+import com.usky.common.mybatis.core.CrudService;
+import com.usky.oa.domain.OaDocument;
+import com.usky.oa.service.vo.OaApprovalCountVO;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 审批表 服务类
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+public interface OaApprovalService extends CrudService<OaApproval> {
+
+    /**
+     * 审批统计
+     * @return OaApprovalCountVO
+     */
+    OaApprovalCountVO approvalCount();
+
+    /**
+     * 审批列表
+     * @param queryType 查询类型(1:待处理,2:已处理,3:我收到)
+     * @param docNo 单据编号
+     * @param formSign 单据类型(请假申请-QJD...按标识查询)
+     * @param approvalStatus 审批状态(1:审批中,2:审批通过,3:审批不通过)
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @param pageNum 页码
+     * @param pageSize 页大小
+     * @return CommonPage<OaApproval>
+     */
+    CommonPage<OaApproval> pageList(Integer queryType, String docNo, String formSign, Integer approvalStatus, String startTime, String endTime, Integer pageNum, Integer pageSize);
+
+    /**
+     * 审批
+     * @param id 审批ID
+     * @param approvalStatus 审批状态(1:审批中,2:审批通过,3:审批不通过)
+     */
+    void approve(Integer id, Integer approvalStatus, String opinion);
+
+    void analysisTest(Integer id);
+}

+ 80 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/OaDocumentService.java

@@ -0,0 +1,80 @@
+package com.usky.oa.service;
+
+import com.alibaba.fastjson.JSONObject;
+import com.usky.common.core.bean.CommonPage;
+import com.usky.oa.domain.OaDocument;
+import com.usky.common.mybatis.core.CrudService;
+import com.usky.oa.service.vo.OaApprovalCountVO;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 单据总表 服务类
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-26
+ */
+public interface OaDocumentService extends CrudService<OaDocument> {
+
+    /**
+     * @description: 我的申请
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2024/12/31 13:17
+     * @param: []
+     * @return: java.util.List<com.usky.oa.domain.OaDocument>
+     **/
+    CommonPage<OaDocument> myApplication(String docNo, String type, Integer status, String startTime, String endTime, Integer pageNum, Integer pageSize);
+
+    /**
+     * @description: 单据详情
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2024/12/31 13:17
+     * @param: []
+     * @return: java.util.List<com.usky.oa.domain.OaDocument>
+     **/
+    Object documentDetails(String docNo);
+
+    /**
+     * @description: 删除单据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2024/12/31 13:17
+     * @param: []
+     * @return: java.util.List<com.usky.oa.domain.OaDocument>
+     **/
+    void delDocument(String docNo);
+
+    /**
+     * @description: 新增单据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/6 16:32
+     * @param: [oaDocument]
+     * @return: void
+     **/
+    void addDoc(JSONObject oaDocument);
+
+    /**
+     * @description: 修改单据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/6 16:34
+     * @param: [oaDocument]
+     * @return: com.usky.oa.domain.OaDocument
+     **/
+    void updateDoc(JSONObject jsonDocument);
+
+    /**
+     * @description: 提交单据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/6 16:34
+     * @param: [docNo]
+     * @return: void
+     **/
+    void submit(String docNo, Integer docStatus);
+}

+ 72 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/OaFormDefinitionService.java

@@ -0,0 +1,72 @@
+package com.usky.oa.service;
+
+import com.usky.common.core.bean.CommonPage;
+import com.usky.common.log.annotation.Log;
+import com.usky.common.log.enums.BusinessType;
+import com.usky.oa.domain.OaFormDefinition;
+import com.usky.common.mybatis.core.CrudService;
+import com.usky.oa.service.vo.OaFormNameResponseVO;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 表单定义表 服务类
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+public interface OaFormDefinitionService extends CrudService<OaFormDefinition> {
+
+    /**
+     * 新增/更新 表单
+     * @param oaFormDefinition
+     */
+    void addForm(OaFormDefinition oaFormDefinition);
+
+    /**
+     * 删除表单
+     * @param formId
+     */
+    void delForm(Integer formId);
+
+    /**
+     * 分页查询表单列表
+     * @param formName 表单名称
+     * @param pageNum 页码
+     * @param pageSize 页大小
+     * @return
+     */
+    CommonPage<OaFormDefinition> pageList(Integer formId, String formName, Integer formGroup, Integer formStatus, Integer pageNum, Integer pageSize);
+
+    /**
+     * 更新表单状态并校验
+     * @param formId
+     * @param formStatus
+     */
+    void validUpdateStatus(Integer formId, Integer formStatus);
+
+    /**
+     * @description: 根据表单标识查询表单信息-数据权限
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/3 14:07
+     * @param: [formSign]
+     * @return: java.util.List<com.usky.oa.domain.OaFormDefinition>
+     **/
+    List<OaFormDefinition> selectByScope(String formSign);
+
+    /**
+     * @description: 获取表单名称列表
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/3 14:07
+     * @param: []
+     * @return: java.util.Map<java.lang.Integer,java.lang.String>
+     **/
+    List<OaFormNameResponseVO> getFormName(String formSign, String formName, Integer formId);
+
+}

+ 46 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/OaJbdDocumentService.java

@@ -0,0 +1,46 @@
+package com.usky.oa.service;
+
+import com.usky.oa.domain.OaJbdDocument;
+import com.usky.common.mybatis.core.CrudService;
+
+/**
+ * <p>
+ * 加班单据表 服务类
+ * </p>
+ *
+ * @author fu
+ * @since 2025-01-02
+ */
+public interface OaJbdDocumentService extends CrudService<OaJbdDocument> {
+
+    /**
+     * @description: 新增加班单据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/2 14:00
+     * @param: [oaJbDocument]
+     * @return: void
+     **/
+    void add(OaJbdDocument oaJbdDocument);
+
+    /**
+     * @description: 更新加班单据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/2 15:43
+     * @param: [oaJbDocument]
+     * @return: void
+     **/
+    void update(OaJbdDocument oaJbdDocument);
+
+    /**
+     * @description: 删除加班单据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/2 15:43
+     * @param: [id]
+     * @return: void
+     **/
+    void delByDocNo(String docNo);
+
+}

+ 45 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/OaQjdDocumentService.java

@@ -0,0 +1,45 @@
+package com.usky.oa.service;
+
+import com.usky.oa.domain.OaQjdDocument;
+import com.usky.common.mybatis.core.CrudService;
+
+/**
+ * <p>
+ * 请假单据表 服务类
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+public interface OaQjdDocumentService extends CrudService<OaQjdDocument> {
+
+    /**
+     * @description: 新增请假单据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2024/12/26 14:15
+     * @param: [oaQjDocument]
+     * @return: void
+     **/
+    void addQjDocument(OaQjdDocument oaQjdDocument);
+
+    /**
+     * @description: 修改请假单据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2024/12/26 14:15
+     * @param: [oaQjDocument]
+     * @return: void
+     **/
+    void updateQjDocument(OaQjdDocument oaQjdDocument);
+
+    /**
+     * @description: 删除请假单据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2024/12/26 15:20
+     * @param: [id]
+     * @return: void
+     **/
+    void delQjDocument(String docNo);
+}

+ 49 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/enums/OaBuiltInDocument.java

@@ -0,0 +1,49 @@
+package com.usky.oa.service.enums;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2024/12/25
+ */
+public enum OaBuiltInDocument {
+
+    QJD("QJD", "请假单"),
+    JBD("JBD", "加班单");
+    // LZD("LZ", "离职单"),
+    // CCD("CC", "出差单"),
+    // WCD("WC", "外出单"),
+    // BHSQ("BHSQ", "项目编号申请单"),
+    // MPD("MPYS", "名片印刷单"),
+    // JPD("DJP", "机票单"),
+    // GDZC("ZCLY", "固定资产领用单"),
+    // ZZJY("ZZJY", "印章资质借用单"),
+    // HTJY("HTJY", "合同借用单"),
+    // //XMCG("XMCG", "项目采购表单");
+    // // 项目采购;固定资产采购;行政(特殊)用品采购
+    // CGD("CGSQ", "采购单"),
+    // //XZCG("XZCG", "行政(特殊)用品采购表单"),
+    // YYD("YYSQ", "用印申请单");
+
+    private final String sign;
+    private final String name;
+
+    OaBuiltInDocument(String sign, String name) {
+        this.sign = sign;
+        this.name = name;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+}

+ 236 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/impl/OaApprovalServiceImpl.java

@@ -0,0 +1,236 @@
+package com.usky.oa.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.usky.common.core.bean.CommonPage;
+import com.usky.common.core.exception.BusinessException;
+import com.usky.common.security.utils.SecurityUtils;
+import com.usky.oa.domain.OaApproval;
+import com.usky.oa.domain.OaDocument;
+import com.usky.oa.domain.OaFormDefinition;
+import com.usky.oa.mapper.OaApprovalMapper;
+import com.usky.oa.mapper.OaDocumentMapper;
+import com.usky.oa.mapper.OaFormDefinitionMapper;
+import com.usky.oa.service.OaApprovalService;
+import com.usky.common.mybatis.core.AbstractCrudService;
+import com.usky.oa.service.utils.OaProcessAnalysis;
+import com.usky.oa.service.utils.OaSendMessageCenter;
+import com.usky.oa.service.vo.OaApprovalCountVO;
+import com.usky.system.domain.SysUser;
+import org.apache.commons.lang3.StringUtils;
+import org.hibernate.validator.internal.constraintvalidators.bv.time.futureorpresent.FutureOrPresentValidatorForReadableInstant;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * <p>
+ * 审批表 服务实现类
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+@Service
+public class OaApprovalServiceImpl extends AbstractCrudService<OaApprovalMapper, OaApproval> implements OaApprovalService {
+
+    @Autowired
+    private OaApprovalMapper oaApprovalMapper;
+
+    @Autowired
+    private OaDocumentMapper oaDocumentMapper;
+
+    @Autowired
+    private OaSendMessageCenter oaSendMessageCenter;
+
+    @Autowired
+    private OaProcessAnalysis oaProcessAnalysis;
+
+    @Autowired
+    private OaFormDefinitionMapper oaFormDefinitionMapper;
+
+
+    // 我的申请-待处理、已处理、我发起、我收到-统计(暂时统计近一年数据)
+    @Override
+    public OaApprovalCountVO approvalCount() {
+        Long userId = SecurityUtils.getUserId();
+        String username = SecurityUtils.getUsername();
+        Integer tenantId = SecurityUtils.getTenantId();
+
+        LocalDateTime now = LocalDateTime.now();
+        // 一年前时间
+        LocalDateTime oneYearAgo = now.minusYears(1);
+
+        OaApprovalCountVO oaApprovalCountVO = new OaApprovalCountVO();
+        // 待处理
+        oaApprovalCountVO.setPendingSum(getPendingSum(tenantId, userId, oneYearAgo, now).size());
+        // 已处理
+        oaApprovalCountVO.setAlreadySum(getAlreadySum(tenantId, userId, oneYearAgo, now).size());
+        // 我发起
+        oaApprovalCountVO.setMyInitiated(getMyInitiated(tenantId, username, oneYearAgo, now).size());
+        // 我收到
+        oaApprovalCountVO.setMyReceived(getMyReceived(tenantId, userId, oneYearAgo, now).size());
+
+        return oaApprovalCountVO;
+    }
+
+    // 我的代办-待处理、已处理、我收到-分页
+    @Override
+    public CommonPage<OaApproval> pageList(Integer queryType, String docNo, String formSign, Integer approvalStatus, String startTime, String endTime, Integer pageNum, Integer pageSize) {
+        Long userId = SecurityUtils.getUserId();
+        Integer tenantId = SecurityUtils.getTenantId();
+        IPage<OaApproval> page = new Page<>(pageNum, pageSize);
+
+        List<Integer> processed = Stream.of(2, 3).collect(Collectors.toList());
+
+        LambdaQueryWrapper<OaApproval> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(OaApproval::getTenantId, tenantId)
+                .eq(OaApproval::getApprovalUid, userId).orderByDesc(OaApproval::getApprovalDate);
+
+        switch (queryType) {
+            case 1:
+                queryWrapper.eq(OaApproval::getApprovalStatus, 1)
+                        .like(StringUtils.isNotBlank(docNo), OaApproval::getDocNo, docNo)
+                        .like(StringUtils.isNotBlank(formSign), OaApproval::getDocNo, formSign)
+                        .between(StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime), OaApproval::getSubmitDate, startTime, endTime);
+                break;
+            case 2:
+                queryWrapper.like(StringUtils.isNotBlank(docNo), OaApproval::getDocNo, docNo)
+                        .like(StringUtils.isNotBlank(formSign), OaApproval::getDocNo, formSign)
+                        .eq(approvalStatus != null && approvalStatus > 1 && approvalStatus < 4, OaApproval::getApprovalStatus, approvalStatus)
+                        .in(OaApproval::getApprovalStatus, processed)
+                        .between(StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime), OaApproval::getSubmitDate, startTime, endTime);
+                break;
+            case 3:
+                queryWrapper.like(StringUtils.isNotBlank(docNo), OaApproval::getDocNo, docNo)
+                        .like(StringUtils.isNotBlank(formSign), OaApproval::getDocNo, formSign)
+                        .eq(OaApproval::getType, 1)
+                        .eq(approvalStatus != null && approvalStatus > 0 && approvalStatus < 4, OaApproval::getApprovalStatus, approvalStatus)
+                        .between(StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime), OaApproval::getSubmitDate, startTime, endTime);
+                break;
+            default:
+                throw new RuntimeException("查询类型参数错误");
+        }
+        return ToCommonPage(oaApprovalMapper.selectPage(page, queryWrapper));
+    }
+
+    // 审批
+    @Override
+    public void approve(Integer id, Integer approvalStatus, String opinion) {
+        LambdaQueryWrapper<OaApproval> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(OaApproval::getId, id);
+        OaApproval oaApproval = oaApprovalMapper.selectOne(queryWrapper);
+
+        if (!oaApproval.getApprovalUid().equals(SecurityUtils.getUserId())) {
+            throw new BusinessException("审批权限不足,暂时无法更改!");
+        }
+
+        if (oaApproval.getApprovalStatus() != 1) {
+            throw new BusinessException("审批状态异常,暂时无法更改!");
+        }
+        if (approvalStatus < 2 || approvalStatus > 3) {
+            throw new BusinessException("审批类型错误,请重试!");
+        }
+
+        String username = SecurityUtils.getUsername();
+
+        LocalDateTime now = LocalDateTime.now();
+
+        oaApproval.setApprovalStatus(approvalStatus);
+        oaApproval.setOpinion(opinion);
+        oaApproval.setApprovalDate(now);
+        oaApproval.setUpdateBy(username);
+        oaApproval.setUpdateTime(now);
+        oaApprovalMapper.updateById(oaApproval);
+
+        int isPass = 1;
+        if (approvalStatus == 3) {
+            isPass = 0;
+        }
+
+        List<Long> receivers = Collections.singletonList(Long.valueOf(oaApproval.getProposer()));
+        oaSendMessageCenter.sendAsyncMessage(oaApproval.getCreateBy(), Long.valueOf(oaApproval.getProposer()), oaApproval.getId(), receivers, isPass);
+    }
+
+    @Override
+    public void analysisTest(Integer id) {
+        LambdaQueryWrapper<OaFormDefinition> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(OaFormDefinition::getId, id);
+        String flowInfo = oaFormDefinitionMapper.selectOne(queryWrapper).getFlowInfo();
+        oaProcessAnalysis.processAnalysis(flowInfo);
+    }
+
+    // 待处理
+    private List<OaApproval> getPendingSum(Integer tenantId, Long userId, LocalDateTime oneYearAgo, LocalDateTime now) {
+        LambdaQueryWrapper<OaApproval> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(OaApproval::getTenantId, tenantId)
+                .eq(OaApproval::getApprovalUid, userId)
+                .eq(OaApproval::getApprovalStatus, 1)
+                .between(OaApproval::getSubmitDate, oneYearAgo, now);
+        List<OaApproval> oaApprovals = oaApprovalMapper.selectList(queryWrapper);
+        return oaApprovals == null ? Collections.emptyList() : oaApprovals;
+    }
+
+    // 已处理
+    private List<OaApproval> getAlreadySum(Integer tenantId, Long userId, LocalDateTime oneYearAgo, LocalDateTime now) {
+        LambdaQueryWrapper<OaApproval> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(OaApproval::getTenantId, tenantId)
+                .eq(OaApproval::getApprovalUid, userId)
+                .and(wrapper -> wrapper
+                        .eq(OaApproval::getApprovalStatus, 2)
+                        .or()
+                        .eq(OaApproval::getApprovalStatus, 3))
+                .between(OaApproval::getSubmitDate, oneYearAgo, now);
+        List<OaApproval> oaApprovals = oaApprovalMapper.selectList(queryWrapper);
+        return oaApprovals == null ? Collections.emptyList() : oaApprovals;
+    }
+
+    // 我发起
+    /*private List<OaApproval> getMyInitiated(Integer tenantId, String username) {
+        List<String> docNoList = oaDocumentMapper.selectList(new QueryWrapper<OaDocument>().lambda()
+                .select(OaDocument::getDocNo)
+                .eq(OaDocument::getTenantId, tenantId)
+                .eq(OaDocument::getCreateBy, username)
+                // 已发起只计算 审批中、审通过、审批不通过
+                .in(OaDocument::getDocStatus, 1, 2, 3)).stream().map(OaDocument::getDocNo).collect(Collectors.toList());
+
+        LambdaQueryWrapper<OaApproval> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.in(OaApproval::getDocNo, docNoList);
+        List<OaApproval> oaApprovals = oaApprovalMapper.selectList(queryWrapper);
+        return oaApprovals == null ? Collections.emptyList() : oaApprovals;
+    }*/
+
+    // 我发起
+    private List<OaDocument> getMyInitiated(Integer tenantId, String username, LocalDateTime oneYearAgo, LocalDateTime now) {
+        List<OaDocument> oaDocuments = oaDocumentMapper.selectList(new QueryWrapper<OaDocument>().lambda()
+                .select(OaDocument::getDocNo)
+                .eq(OaDocument::getTenantId, tenantId)
+                .eq(OaDocument::getCreateBy, username)
+                .in(OaDocument::getDocStatus, 1, 2, 3)
+                .between(OaDocument::getCreateTime, oneYearAgo, now));
+        return oaDocuments == null ? Collections.emptyList() : oaDocuments;
+    }
+
+    // 我收到
+    private List<OaApproval> getMyReceived(Integer tenantId, Long userId, LocalDateTime oneYearAgo, LocalDateTime now) {
+        LambdaQueryWrapper<OaApproval> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(OaApproval::getTenantId, tenantId)
+                .eq(OaApproval::getApprovalUid, userId)
+                .eq(OaApproval::getType, 1)
+                .between(OaApproval::getSubmitDate, oneYearAgo, now);
+        List<OaApproval> oaApprovals = oaApprovalMapper.selectList(queryWrapper);
+        return oaApprovals == null ? Collections.emptyList() : oaApprovals;
+    }
+
+}

+ 236 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/impl/OaDocumentServiceImpl.java

@@ -0,0 +1,236 @@
+package com.usky.oa.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+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.usky.common.core.bean.CommonPage;
+import com.usky.common.core.exception.BusinessException;
+import com.usky.common.security.utils.SecurityUtils;
+import com.usky.oa.domain.*;
+import com.usky.oa.mapper.*;
+import com.usky.oa.service.OaDocumentService;
+import com.usky.common.mybatis.core.AbstractCrudService;
+import com.usky.oa.service.OaJbdDocumentService;
+import com.usky.oa.service.OaQjdDocumentService;
+import com.usky.oa.service.utils.OaSendMessageCenter;
+import org.apache.commons.lang3.RandomUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 单据总表 服务实现类
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-26
+ */
+@Service
+public class OaDocumentServiceImpl extends AbstractCrudService<OaDocumentMapper, OaDocument> implements OaDocumentService {
+
+    @Autowired
+    private OaDocumentMapper oaDocumentMapper;
+
+    @Autowired
+    private OaQjdDocumentMapper oaQjdDocumentMapper;
+
+    @Autowired
+    private OaQjdDocumentService oaQjdDocumentService;
+
+    @Autowired
+    private OaJbdDocumentService oaJbdDocumentService;
+
+    @Autowired
+    private OaJbdDocumentMapper oaJbdDocumentMapper;
+
+    @Autowired
+    private OaDocumentMapper documentMapper;
+
+    @Autowired
+    private OaFormDefinitionMapper oaFormDefinitionMapper;
+
+    @Autowired
+    private OaApprovalMapper oaApprovalMapper;
+
+    @Autowired
+    private OaSendMessageCenter oaSendMessageCenter;
+
+    private static final String TABLE_HEAD = "oa_";
+    private static final String TABLE_SUFFIX = "_document";
+
+    // 我的申请
+    @Override
+    public CommonPage<OaDocument> myApplication(String docNo, String type, Integer status, String startTime, String endTime, Integer pageNum, Integer pageSize) {
+        Long userId = SecurityUtils.getUserId();
+        Integer tenantId = SecurityUtils.getTenantId();
+
+        LambdaQueryWrapper<OaDocument> wrapper = Wrappers.lambdaQuery();
+        wrapper.eq(OaDocument::getTenantId, tenantId).eq(OaDocument::getProposer, userId)
+                .like(StringUtils.isNotBlank(docNo), OaDocument::getDocNo, docNo)
+                .eq(StringUtils.isNotBlank(type), OaDocument::getType, type)
+                .eq(status != null, OaDocument::getDocStatus, status)
+                .between(StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime), OaDocument::getCreateTime, startTime, endTime)
+                .orderByDesc(OaDocument::getId);
+
+        return ToCommonPage(page(new Page<>(pageNum, pageSize), wrapper));
+    }
+
+    // 单据详情
+    @Override
+    public Object documentDetails(String docNo) {
+        Object documentDetails = null;
+        String type = getFormSign(docNo);
+
+        switch (type) {
+            case "QJD":
+                documentDetails = oaQjdDocumentMapper.selectOne(Wrappers.lambdaQuery(OaQjdDocument.class).eq(OaQjdDocument::getDocNo, docNo));
+                break;
+            case "JBD":
+                documentDetails = oaJbdDocumentMapper.selectOne(Wrappers.lambdaQuery(OaJbdDocument.class).eq(OaJbdDocument::getDocNo, docNo));
+                break;
+        }
+
+        return documentDetails;
+    }
+
+    // 删除单据
+    @Override
+    public void delDocument(String docNo) {
+        String type = getFormSign(docNo);
+        switch (type) {
+            case "QJD":
+                oaQjdDocumentMapper.delete(Wrappers.lambdaQuery(OaQjdDocument.class).eq(OaQjdDocument::getDocNo, docNo));
+                break;
+            case "JBD":
+                oaJbdDocumentMapper.delete(Wrappers.lambdaQuery(OaJbdDocument.class).eq(OaJbdDocument::getDocNo, docNo));
+                break;
+        }
+        oaDocumentMapper.delete(Wrappers.lambdaQuery(OaDocument.class).eq(OaDocument::getDocNo, docNo));
+    }
+
+    // 新增单据
+    @Override
+    public void addDoc(JSONObject oaDocument) {
+        LambdaQueryWrapper<OaFormDefinition> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.select(OaFormDefinition::getFieldInfo).eq(OaFormDefinition::getId, oaDocument.get("formId"));
+        OaFormDefinition oaFormDefinition = oaFormDefinitionMapper.selectOne(queryWrapper);
+        String sign = oaFormDefinition.getFieldInfo();
+
+        switch (sign) {
+            case "QJD":
+                oaQjdDocumentService.addQjDocument(JSON.parseObject(oaDocument.toJSONString(), OaQjdDocument.class));
+                break;
+            case "JBD":
+                oaJbdDocumentService.add(JSON.parseObject(oaDocument.toJSONString(), OaJbdDocument.class));
+                break;
+        }
+    }
+
+    // 更新单据
+    @Override
+    public void updateDoc(JSONObject jsonDocument) {
+        LambdaQueryWrapper<OaFormDefinition> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.select(OaFormDefinition::getFieldInfo).eq(OaFormDefinition::getId, jsonDocument.get("formId"));
+        OaFormDefinition oaFormDefinition = oaFormDefinitionMapper.selectOne(queryWrapper);
+        String sign = oaFormDefinition.getFieldInfo();
+
+        switch (sign) {
+            case "QJD":
+                oaQjdDocumentService.updateQjDocument(JSON.parseObject(jsonDocument.toJSONString(), OaQjdDocument.class));
+                break;
+            case "JBD":
+                oaJbdDocumentService.update(JSON.parseObject(jsonDocument.toJSONString(), OaJbdDocument.class));
+                break;
+        }
+    }
+
+    // 提交单据
+    @Override
+    public void submit(String docNo, Integer docStatus) {
+        if (docStatus != 1) {
+            throw new RuntimeException("单据提交异常,请联系管理员!");
+        } else {
+            LambdaQueryWrapper<OaDocument> queryWrapper = Wrappers.lambdaQuery();
+            queryWrapper.eq(OaDocument::getDocNo, docNo);
+            OaDocument oaDocument = oaDocumentMapper.selectOne(queryWrapper);
+            if (oaDocument.getDocStatus() == 1) {
+                throw new RuntimeException("单据已提交,请勿重复提交!");
+            }
+        }
+
+        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
+        Integer tenantId = SecurityUtils.getTenantId();
+        String username = SecurityUtils.getUsername();
+        Long userId = SecurityUtils.getUserId();
+        LocalDateTime now = LocalDateTime.now();
+
+        String formSign = getFormSign(docNo);
+
+        switch (formSign) {
+            case "QJD":
+                oaQjdDocumentMapper.update(null, Wrappers.lambdaUpdate(OaQjdDocument.class)
+                        .set(OaQjdDocument::getDocStatus, docStatus)
+                        .set(OaQjdDocument::getUpdateBy, username)
+                        .set(OaQjdDocument::getUpdateTime, now)
+                        .eq(OaQjdDocument::getDocNo, docNo));
+                break;
+            case "JBD":
+                oaJbdDocumentMapper.update(null, Wrappers.lambdaUpdate(OaJbdDocument.class)
+                        .set(OaJbdDocument::getDocStatus, docStatus)
+                        .set(OaJbdDocument::getUpdateBy, username)
+                        .set(OaJbdDocument::getUpdateTime, now)
+                        .eq(OaJbdDocument::getDocNo, docNo));
+                break;
+        }
+        oaDocumentMapper.update(null, Wrappers.lambdaUpdate(OaDocument.class)
+                .set(OaDocument::getDocStatus, docStatus)
+                .set(OaDocument::getUpdateBy, username)
+                .set(OaDocument::getUpdateTime, now)
+                .eq(OaDocument::getDocNo, docNo));
+
+        // 生成审批记录
+        OaApproval oaApproval = new OaApproval();
+        oaApproval.setDocNo(docNo);
+        oaApproval.setType(0);
+        oaApproval.setApprovalStatus(1);
+        // 随机选择一个审批人(涛、哲)
+        long approvalUid = RandomUtils.nextBoolean() ? 101 : 105;
+        oaApproval.setApprovalUid(approvalUid);
+        oaApproval.setProposer(Math.toIntExact(userId));
+        oaApproval.setCreateBy(username);
+        oaApproval.setCreateTime(now);
+        oaApproval.setSubmitDate(now);
+        oaApproval.setDeptId(deptId);
+        oaApproval.setTenantId(tenantId);
+        oaApprovalMapper.insert(oaApproval);
+
+        // 发送审批消息
+        List<Long> receivers = Collections.singletonList(oaApproval.getApprovalUid());
+        oaSendMessageCenter.sendAsyncMessage(oaApproval.getCreateBy(), userId, oaApproval.getId(), receivers,3);
+    }
+
+    // 获取单据类型
+    private String getFormSign(String docNo) {
+        if (StringUtils.isBlank(docNo)) {
+            throw new RuntimeException("单据号不能为空!");
+        } else if (docNo.split("-").length != 2 ||
+                docNo.split("-")[0].length() > 4 ||
+                docNo.split("-")[0].length() < 3 ||
+                docNo.split("-")[1].length() != 12) {
+            throw new RuntimeException("单据号格式错误!");
+        }
+        return docNo.split("-")[0];
+    }
+
+}

+ 331 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/impl/OaFormDefinitionServiceImpl.java

@@ -0,0 +1,331 @@
+package com.usky.oa.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.datascope.context.DataScopeContextHolder;
+import com.usky.common.core.bean.CommonPage;
+import com.usky.common.core.exception.BusinessException;
+import com.usky.common.security.utils.SecurityUtils;
+import com.usky.oa.domain.OaDocument;
+import com.usky.oa.domain.OaFormDefinition;
+import com.usky.oa.mapper.OaDocumentMapper;
+import com.usky.oa.mapper.OaFormDefinitionMapper;
+import com.usky.oa.service.OaDocumentService;
+import com.usky.oa.service.OaFormDefinitionService;
+import com.usky.common.mybatis.core.AbstractCrudService;
+import com.usky.oa.service.vo.OaFormNameResponseVO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 表单定义表 服务实现类
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+@Service
+public class OaFormDefinitionServiceImpl extends AbstractCrudService<OaFormDefinitionMapper, OaFormDefinition> implements OaFormDefinitionService {
+
+    @Autowired
+    private OaFormDefinitionMapper oaFormDefinitionMapper;
+
+    @Autowired
+    private OaDocumentMapper oaDocumentMapper;
+
+    /**
+     * 新增/更新 表单
+     * 此方法负责验证表单定义的合法性,包括表单名称和标识的唯一性、长度限制,并最终保存合法的表单定义
+     * @param oaFormDefinition 表单定义对象,包含表单的详细信息
+     * @throws BusinessException 当表单名称或标识不符合规范或已存在时抛出
+     */
+    @Override
+    public void addForm(OaFormDefinition oaFormDefinition) {
+
+        String formName = oaFormDefinition.getFormName();
+        String formSign = oaFormDefinition.getFormSign();
+        String formExplain = oaFormDefinition.getFormExplain();
+        // 判断 表单名称、标识、说明 是否为空或超长
+        validateFormProperties(formName, formSign, formExplain);
+
+        // 判断 表单分组 是否为空、有效
+        isValidFormGroup(oaFormDefinition.getFormGroup());
+
+        if (Objects.isNull(oaFormDefinition.getFormType())) {
+            throw new BusinessException("表单字段信息不能为空");
+        } else if (oaFormDefinition.getFormType() < 0 || oaFormDefinition.getFormType() > 1) {
+            throw new BusinessException("表单类型不正确");
+        }
+
+        // 判断 表单可见范围 是否为空、有效
+        validFromScope(oaFormDefinition);
+
+        // 获取用户基本信息
+        Long userId = SecurityUtils.getUserId();
+        Integer tenantId = SecurityUtils.getTenantId();
+        String username = SecurityUtils.getUsername();
+        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
+        LocalDateTime now = LocalDateTime.now();
+
+        // 判断表单是新增或者修改
+        if (oaFormDefinition.getId() == null) {
+            // BeanUtils.copyBeanProp(oaFormDefinition, oaFormDefinition);
+            // 判断表单名称和标识是否重复
+            selectByNameOrSign(formName, formSign);
+
+            oaFormDefinition.setCreateBy(username);
+            oaFormDefinition.setDeptId(deptId);
+            oaFormDefinition.setTenantId(tenantId);
+            oaFormDefinition.setCreateTime(now);
+            oaFormDefinition.setFormVersion(1);
+            oaFormDefinition.setFormStatus(2);
+            oaFormDefinitionMapper.insert(oaFormDefinition);
+        } else {
+            oaFormDefinition.setUpdateBy(username);
+            oaFormDefinition.setUpdateTime(now);
+
+            OaFormDefinition oaFormDefinition1 = oaFormDefinitionMapper.selectById(oaFormDefinition.getId());
+            // 判断表单版本号是否需要更新
+            if (versionUpdateValid(oaFormDefinition)) {
+                oaFormDefinition.setFormVersion(oaFormDefinition1.getFormVersion() + 1);
+            }
+            if (!Objects.equals(oaFormDefinition.getFormSign(), oaFormDefinition1.getFormSign())) {
+                throw new BusinessException("表单标识不可修改!");
+            }
+
+            oaFormDefinitionMapper.updateById(oaFormDefinition);
+        }
+    }
+
+    /**
+     * 删除表单
+     * @param formId 表单ID,用于删除特定的表单定义
+     */
+    @Override
+    public void delForm(Integer formId) {
+        if (formId > 0) {
+            OaFormDefinition oaFormDefinition = oaFormDefinitionMapper.selectById(formId);
+            if (oaFormDefinition == null) {
+                throw new BusinessException("表单不存在!");
+            }
+            if (validDelete(formId) != null) {
+                throw new BusinessException("当前表单下存在单据,不可删除!");
+            }
+            oaFormDefinitionMapper.deleteById(oaFormDefinition);
+        } else {
+            throw new BusinessException("表单ID不能为空或者小于0");
+        }
+    }
+
+    // 判断表单下是否存在已生成单据
+    private OaDocument validDelete(Integer formId) {
+        LambdaQueryWrapper<OaDocument> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(OaDocument::getFormId, formId);
+        return oaDocumentMapper.selectOne(queryWrapper);
+    }
+
+
+    // 表单管理-分页查询
+    @Override
+    public CommonPage<OaFormDefinition> pageList(Integer formId, String formName, Integer formGroup, Integer formStatus, Integer pageNum, Integer pageSize) {
+        IPage<OaFormDefinition> page = new Page<>(pageNum, pageSize);
+        LambdaQueryWrapper<OaFormDefinition> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(formId != null, OaFormDefinition::getId, formId)
+                .like(StringUtils.isNotBlank(formName), OaFormDefinition::getFormName, formName)
+                .eq(formGroup != null, OaFormDefinition::getFormGroup, formGroup)
+                .eq(formStatus != null, OaFormDefinition::getFormStatus, formStatus)
+                .orderByDesc(OaFormDefinition::getId)
+                // 数据权限控制
+                .apply(Objects.nonNull(DataScopeContextHolder.getDataScopeSql()), DataScopeContextHolder.getDataScopeSql());
+        return ToCommonPage(oaFormDefinitionMapper.selectPage(page, queryWrapper));
+    }
+
+    // 表单管理-修改表单状态
+    @Override
+    public void validUpdateStatus(Integer formId, Integer formStatus) {
+        if (formId == null || formId <= 0) {
+            throw new BusinessException("表单ID不能为空或者小于0!");
+        }
+        OaFormDefinition oaFormDefinition = oaFormDefinitionMapper.selectById(formId);
+        if (oaFormDefinition == null) {
+            throw new BusinessException("表单不存在!");
+        }
+
+        if (formStatus == null || formStatus < 1 || formStatus > 2) {
+            throw new BusinessException("表单状态为空或不在设定值范围!");
+        }
+        oaFormDefinition.setFormStatus(formStatus);
+        oaFormDefinitionMapper.updateById(oaFormDefinition);
+    }
+
+    // 我的申请-根据权限查询表单
+    @Override
+    public List<OaFormDefinition> selectByScope(String formSign) {
+        Long userId = SecurityUtils.getUserId();
+        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
+        Integer tenantId = SecurityUtils.getTenantId();
+
+        List<OaFormDefinition> oaFormDefinitions = new ArrayList<>();
+
+        LambdaQueryWrapper<OaFormDefinition> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(OaFormDefinition::getTenantId, tenantId);
+
+        if (StringUtils.isNotBlank(formSign)) {
+            queryWrapper.eq(OaFormDefinition::getFormSign, formSign);
+            OaFormDefinition oaFormDefinition = oaFormDefinitionMapper.selectOne(queryWrapper);
+            if (oaFormDefinition != null) {
+                oaFormDefinitions.add(oaFormDefinition);
+            }
+            return oaFormDefinitions;
+        }
+
+        queryWrapper.eq(OaFormDefinition::getFormStatus, 1)
+                .and(qw -> qw
+                        .eq(OaFormDefinition::getFormScope, 1)
+                        .or()
+                        .apply("FIND_IN_SET('" + deptId + "', dept_ids) > 0")
+                        .or()
+                        .apply("FIND_IN_SET('" + userId + "', user_ids) > 0"));
+        oaFormDefinitions = oaFormDefinitionMapper.selectList(queryWrapper);
+        return oaFormDefinitions;
+    }
+
+    // 表单管理-根据权限查询表单
+    @Override
+    public List<OaFormNameResponseVO> getFormName(String formSign, String formName, Integer formId) {
+        Long userId = SecurityUtils.getUserId();
+        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
+        Integer tenantId = SecurityUtils.getTenantId();
+        LambdaQueryWrapper<OaFormDefinition> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.select(OaFormDefinition::getId, OaFormDefinition::getFormName, OaFormDefinition::getFormSign)
+                .eq(OaFormDefinition::getTenantId, tenantId)
+                .eq(StringUtils.isNotBlank(formSign), OaFormDefinition::getFormSign, formSign)
+                .eq(StringUtils.isNotBlank(formName), OaFormDefinition::getFormName, formName)
+                .eq(formId != null && formId > 0, OaFormDefinition::getId, formId)
+                .eq(OaFormDefinition::getFormStatus, 1)
+                .and(qw -> qw
+                        .eq(OaFormDefinition::getFormScope, 1)
+                        .or()
+                        .apply("FIND_IN_SET('" + deptId + "', dept_ids) > 0")
+                        .or()
+                        .apply("FIND_IN_SET('" + userId + "', user_ids) > 0"));
+        List<OaFormDefinition> oaFormDefinitions = oaFormDefinitionMapper.selectList(queryWrapper);
+
+        List<OaFormNameResponseVO> formNameList = new ArrayList<>();
+        for (OaFormDefinition oaFormDefinition : oaFormDefinitions) {
+            OaFormNameResponseVO oaFormNameResponseVO = new OaFormNameResponseVO();
+            oaFormNameResponseVO.setFormId(oaFormDefinition.getId());
+            oaFormNameResponseVO.setFormName(oaFormDefinition.getFormName());
+            oaFormNameResponseVO.setFormSign(oaFormDefinition.getFormSign());
+            formNameList.add(oaFormNameResponseVO);
+        }
+        return formNameList;
+    }
+
+
+    // 表单版本更新验证
+    private Boolean versionUpdateValid(OaFormDefinition oaFormDefinition) {
+        boolean update = false;
+        OaFormDefinition selectOne = oaFormDefinitionMapper.selectById(oaFormDefinition.getId());
+        if (!selectOne.getFlowInfo().equals(oaFormDefinition.getFlowInfo()) || !selectOne.getFormExplain().equals(oaFormDefinition.getFormExplain())) {
+            update = true;
+        }
+        return update;
+    }
+
+    /**
+     * 根据表单id、名称查询
+     * @param formName 表单名称,用于查询特定的表单定义
+     * @return 返回查询到的表单定义对象,如果没有找到匹配的表单,则返回null
+     */
+    public void selectByNameOrSign(String formName, String formSign) {
+        LambdaQueryWrapper<OaFormDefinition> queryName = Wrappers.lambdaQuery();
+        queryName.eq(StringUtils.isNotBlank(formName), OaFormDefinition::getFormName, formName);
+        OaFormDefinition fromByName = oaFormDefinitionMapper.selectOne(queryName);
+
+        LambdaQueryWrapper<OaFormDefinition> querySign = Wrappers.lambdaQuery();
+        querySign.eq(StringUtils.isNotBlank(formSign), OaFormDefinition::getFormSign, formSign);
+        OaFormDefinition fromBySign = oaFormDefinitionMapper.selectOne(querySign);
+
+        if (fromByName != null) {
+            throw new BusinessException("表单名称已存在,请更换");
+        } else if (fromBySign != null) {
+            throw new BusinessException("表单标识已存在,请更换");
+        }
+    }
+
+    // 表单管理-表单属性(表单名称、标识、说明)验证
+    private void validateFormProperties(String formName, String formSign, String formExplain) {
+        // 判断表单名称是否为空或者超长
+        if (StringUtils.isBlank(formName) || formName.length() > 10) {
+            throw new BusinessException("表单名称不能为空或空字符串");
+        }
+
+        // 判断表单标识是否为空或者超长
+        if (StringUtils.isBlank(formSign)) {
+            throw new BusinessException("表单标识不能为空");
+        } else if (formSign.length() < 3 || formSign.length() > 4) {
+            throw new BusinessException("表单标识长度不能少于3个字符或超过4个字符");
+        } else if (!formSign.matches("^[A-Z]+$")) {
+            throw new BusinessException("表单标识只能包含大写字母!");
+        }
+
+        // 判断表单说明是否超长
+        if (StringUtils.isNotBlank(formExplain) && formExplain.length() > 100) {
+            throw new BusinessException("表单说明长度不能超过100个字符");
+        }
+    }
+
+    // 判断表单所在分组是否有效
+    private void isValidFormGroup(Integer formGroup) {
+        if (formGroup == null) {
+            throw new BusinessException("表单所在分组不能为空");
+        } else if (formGroup < 0 || formGroup > 6) {
+            throw new BusinessException("表单所在分组异常!请联系管理员");
+        }
+    }
+
+    // 校验表单可见范围是否有效
+    private void validFromScope(OaFormDefinition oaFormDefinition) {
+        if (oaFormDefinition.getFormScope() == null) {
+            throw new BusinessException("表单可见范围不能为空");
+        } else {
+            Integer formScope = oaFormDefinition.getFormScope();
+            String deptIds = oaFormDefinition.getDeptIds();
+            String userIds = oaFormDefinition.getUserIds();
+            switch (formScope) {
+                case 0:
+                    if (StringUtils.isBlank(deptIds)) {
+                        throw new BusinessException("表单可见范围为部门,部门集合不能为空");
+                    } else if (!deptIds.matches("^(?:\\d+)(,\\d+)*$")) {
+                        throw new BusinessException("部门集合格式不正确!");
+                    }
+                    break;
+
+                case 1:
+                    break;
+
+                case 2:
+                    if (StringUtils.isBlank(userIds)) {
+                        throw new BusinessException("表单可见范围为人员,人员集合不能为空");
+                    } else if (!userIds.matches("^(?:\\d+)(,\\d+)*$")) {
+                        throw new BusinessException("人员集合格式不正确!");
+                    }
+                    break;
+                default:
+                    throw new BusinessException("表单可见范围为异常!请联系管理员");
+            }
+        }
+
+    }
+
+}

+ 215 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/impl/OaJbdDocumentServiceImpl.java

@@ -0,0 +1,215 @@
+package com.usky.oa.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.usky.common.core.exception.BusinessException;
+import com.usky.common.security.utils.SecurityUtils;
+import com.usky.oa.domain.OaApproval;
+import com.usky.oa.domain.OaDocument;
+import com.usky.oa.domain.OaJbdDocument;
+import com.usky.oa.mapper.OaApprovalMapper;
+import com.usky.oa.mapper.OaDocumentMapper;
+import com.usky.oa.mapper.OaJbdDocumentMapper;
+import com.usky.oa.service.OaJbdDocumentService;
+import com.usky.common.mybatis.core.AbstractCrudService;
+import com.usky.oa.service.enums.OaBuiltInDocument;
+import com.usky.oa.service.utils.OaSendMessageCenter;
+import org.apache.commons.lang3.RandomUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * <p>
+ * 加班单据表 服务实现类
+ * </p>
+ *
+ * @author fu
+ * @since 2025-01-02
+ */
+@Service
+public class OaJbdDocumentServiceImpl extends AbstractCrudService<OaJbdDocumentMapper, OaJbdDocument> implements OaJbdDocumentService {
+
+    @Autowired
+    private OaJbdDocumentMapper oaJbdDocumentMapper;
+
+    @Autowired
+    private OaDocumentMapper oaDocumentMapper;
+
+    @Autowired
+    private OaApprovalMapper oaApprovalMapper;
+
+    @Autowired
+    private OaSendMessageCenter oaSendMessageCenter;
+
+    @Override
+    public void add(OaJbdDocument oaJbdDocument) {
+        Long userId = SecurityUtils.getUserId();
+        String username = SecurityUtils.getUsername();
+        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
+        Integer tenantId = SecurityUtils.getTenantId();
+
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMddHHmmss");
+        LocalDateTime now = LocalDateTime.now();
+        String formattedDate = now.format(formatter);
+        String sign = OaBuiltInDocument.JBD.getSign();
+        String docNo = sign + "-" + formattedDate;
+
+        validateOaJbDocument(oaJbdDocument);
+
+        oaJbdDocument.setDocNo(docNo);
+        oaJbdDocument.setAccountingMethod(0);
+        oaJbdDocument.setProposer(userId);
+        oaJbdDocument.setCreateBy(username);
+        oaJbdDocument.setCreateTime(now);
+        oaJbdDocument.setDeptId(deptId);
+        oaJbdDocument.setTenantId(tenantId);
+        oaJbdDocumentMapper.insert(oaJbdDocument);
+
+        OaDocument oaDocument = new OaDocument();
+        oaDocument.setFormId(oaJbdDocument.getFormId());
+        oaDocument.setType(sign);
+        oaDocument.setDocNo(docNo);
+        oaDocument.setProposer(userId);
+        oaDocument.setDocStatus(oaJbdDocument.getDocStatus());
+        oaDocument.setCreateBy(username);
+        oaDocument.setCreateTime(oaJbdDocument.getCreateTime());
+        oaDocument.setDeptId(deptId);
+        oaDocument.setTenantId(tenantId);
+        oaDocumentMapper.insert(oaDocument);
+
+        // 如果直接提交则生成一条单据记录
+        Integer docStatus = oaJbdDocument.getDocStatus();
+        if (docStatus.equals(1)) {
+            // 生成一条审批记录数据
+            OaApproval oaApproval = new OaApproval();
+            oaApproval.setDocNo(oaJbdDocument.getDocNo());
+            oaApproval.setType(0);
+            oaApproval.setApprovalStatus(1);
+            oaApproval.setApprovalUid(105L);
+            oaApproval.setProposer(Math.toIntExact(userId));
+            oaApproval.setCreateBy(oaJbdDocument.getCreateBy());
+            oaApproval.setCreateTime(now);
+            oaApproval.setSubmitDate(now);
+            oaApproval.setDeptId(oaJbdDocument.getDeptId());
+            oaApproval.setTenantId(oaJbdDocument.getTenantId());
+            oaApprovalMapper.insert(oaApproval);
+
+            // 发送审批消息
+            List<Long> receivers = Collections.singletonList(oaApproval.getApprovalUid());
+            oaSendMessageCenter.sendAsyncMessage(oaApproval.getCreateBy(), userId, oaApproval.getId(), receivers, 3);
+        }
+    }
+
+    @Override
+    public void update(OaJbdDocument oaJbdDocument) {
+        if (StringUtils.isBlank(oaJbdDocument.getDocNo())) {
+            throw new BusinessException("更新单据编号传参异常!");
+        }
+
+        LocalDateTime now = LocalDateTime.now();
+        Long userId = SecurityUtils.getUserId();
+
+        validateOaJbDocument(oaJbdDocument);
+        oaJbdDocument.setUpdateBy(SecurityUtils.getUsername());
+        oaJbdDocument.setUpdateTime(LocalDateTime.now());
+        oaJbdDocumentMapper.updateById(oaJbdDocument);
+
+        oaDocumentMapper.update(null, Wrappers.lambdaUpdate(OaDocument.class)
+                .eq(OaDocument::getDocNo, oaJbdDocument.getDocNo())
+                .set(OaDocument::getDocStatus, oaJbdDocument.getDocStatus())
+                .set(OaDocument::getUpdateBy, oaJbdDocument.getCreateBy())
+                .set(OaDocument::getUpdateTime, oaJbdDocument.getUpdateTime())
+        );
+
+        Integer docStatus = oaJbdDocument.getDocStatus();
+        if (docStatus.equals(1)) {
+            // 生成一条审批记录数据
+            OaApproval oaApproval = new OaApproval();
+            oaApproval.setDocNo(oaJbdDocument.getDocNo());
+            oaApproval.setType(0);
+            oaApproval.setApprovalStatus(1);
+            oaApproval.setApprovalUid(105L);
+            oaApproval.setProposer(Math.toIntExact(userId));
+            oaApproval.setCreateBy(oaJbdDocument.getCreateBy());
+            oaApproval.setCreateTime(now);
+            oaApproval.setSubmitDate(now);
+            oaApproval.setDeptId(oaJbdDocument.getDeptId());
+            oaApproval.setTenantId(oaJbdDocument.getTenantId());
+            oaApprovalMapper.insert(oaApproval);
+
+            // 发送审批消息
+            List<Long> receivers = Collections.singletonList(oaApproval.getApprovalUid());
+            oaSendMessageCenter.sendAsyncMessage(oaApproval.getCreateBy(), userId, oaApproval.getId(), receivers, 3);
+        }
+    }
+
+    /**
+     * @description: 验证加班单据参数
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/2 18:29
+     * @param: [oaJbdDocument]
+     * @return: void
+     **/
+    private void validateOaJbDocument(OaJbdDocument oaJbdDocument) {
+
+        if (oaJbdDocument.getFormId() == null || oaJbdDocument.getFormId() <= 0) {
+            throw new BusinessException("表单ID必须大于0!");
+        }
+
+        LocalDateTime startTime = oaJbdDocument.getStartTime();
+        LocalDateTime endTime = oaJbdDocument.getEndTime();
+        Integer duration = oaJbdDocument.getDuration();
+
+        if (startTime == null || endTime == null || startTime.isAfter(endTime)) {
+            throw new BusinessException("加班开始时间或结束时间输入异常!请确保开始时间不晚于结束时间");
+        }
+
+        if (duration == null || duration <= 0) {
+            throw new BusinessException("加班时长必须大于0!");
+        }
+
+        if (StringUtils.isBlank(oaJbdDocument.getReason())) {
+            throw new BusinessException("加班原因不能为空!");
+        } else if (oaJbdDocument.getReason().length() > 255) {
+            throw new BusinessException("加班原因超出字数限制,请重试!");
+        }
+
+        if (oaJbdDocument.getImage() == null) {
+            throw new BusinessException("打卡记录及日报图片不能为空!");
+        } else if (oaJbdDocument.getImage().length() > 500) {
+            throw new BusinessException("上传图片数量超出限制,请重试!");
+        }
+    }
+
+    @Override
+    public void delByDocNo(String docNo) {
+
+        if (StringUtils.isBlank(docNo)) {
+            throw new BusinessException("加班单据编号不能为空!");
+        }
+
+        Integer tenantId = SecurityUtils.getTenantId();
+        Long userId = SecurityUtils.getUserId();
+
+        LambdaQueryWrapper<OaJbdDocument> jbdDeleteWrapper = new LambdaQueryWrapper<>();
+        jbdDeleteWrapper.eq(OaJbdDocument::getTenantId, tenantId)
+                .eq(OaJbdDocument::getProposer, userId)
+                .eq(OaJbdDocument::getDocNo, docNo);
+        oaJbdDocumentMapper.delete(jbdDeleteWrapper);
+
+        LambdaQueryWrapper<OaDocument> deleteWrapper = new LambdaQueryWrapper<>();
+        deleteWrapper.eq(OaDocument::getTenantId, tenantId)
+                .eq(OaDocument::getProposer, userId)
+                .eq(OaDocument::getDocNo, docNo);
+        oaDocumentMapper.delete(deleteWrapper);
+    }
+
+}

+ 231 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/impl/OaQjdDocumentServiceImpl.java

@@ -0,0 +1,231 @@
+package com.usky.oa.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.usky.common.core.exception.BusinessException;
+import com.usky.common.log.annotation.Log;
+import com.usky.common.security.utils.SecurityUtils;
+import com.usky.oa.domain.OaApproval;
+import com.usky.oa.domain.OaDocument;
+import com.usky.oa.domain.OaFormDefinition;
+import com.usky.oa.domain.OaQjdDocument;
+import com.usky.oa.mapper.OaApprovalMapper;
+import com.usky.oa.mapper.OaDocumentMapper;
+import com.usky.oa.mapper.OaFormDefinitionMapper;
+import com.usky.oa.mapper.OaQjdDocumentMapper;
+import com.usky.oa.service.OaQjdDocumentService;
+import com.usky.common.mybatis.core.AbstractCrudService;
+import com.usky.oa.service.enums.OaBuiltInDocument;
+import com.usky.oa.service.utils.OaSendMessageCenter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.RandomUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * <p>
+ * 请假单据表 服务实现类
+ * </p>
+ *
+ * @author fu
+ * @since 2024-12-10
+ */
+@Slf4j
+@Service
+public class OaQjdDocumentServiceImpl extends AbstractCrudService<OaQjdDocumentMapper, OaQjdDocument> implements OaQjdDocumentService {
+
+    @Autowired
+    private OaQjdDocumentMapper oaQjdDocumentMapper;
+
+    @Autowired
+    private OaFormDefinitionMapper oaFormDefinitionMapper;
+
+    @Autowired
+    private OaDocumentMapper oaDocumentMapper;
+
+    @Autowired
+    private OaApprovalMapper oaApprovalMapper;
+
+    @Autowired
+    private OaSendMessageCenter oaSendMessageCenter;
+
+    @Override
+    public void addQjDocument(OaQjdDocument oaQjdDocument) {
+
+        // 校验表单数据
+        validateOaQjDocument(oaQjdDocument);
+
+        Long userId = SecurityUtils.getUserId();
+        String username = SecurityUtils.getUsername();
+        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
+        Integer tenantId = SecurityUtils.getTenantId();
+
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMddHHmmss");
+        LocalDateTime now = LocalDateTime.now();
+        String formattedDate = now.format(formatter);
+
+        LambdaQueryWrapper<OaFormDefinition> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.select(OaFormDefinition::getFormSign).eq(OaFormDefinition::getId, oaQjdDocument.getFormId());
+        OaFormDefinition oaFormDefinition = oaFormDefinitionMapper.selectOne(queryWrapper);
+        String sign = oaFormDefinition.getFormSign();
+        String docNo = sign + "-" + formattedDate;
+
+        // 插入请假表数据
+        oaQjdDocument.setDocNo(docNo);
+        oaQjdDocument.setProposer(userId);
+        oaQjdDocument.setCreateBy(username);
+        oaQjdDocument.setCreateTime(now);
+        oaQjdDocument.setDeptId(deptId);
+        oaQjdDocument.setTenantId(tenantId);
+        oaQjdDocumentMapper.insert(oaQjdDocument);
+
+        // 插入单据表数据
+        OaDocument oaDocument = new OaDocument();
+        oaDocument.setFormId(oaQjdDocument.getFormId());
+        oaDocument.setType(sign);
+        oaDocument.setDocNo(docNo);
+        oaDocument.setProposer(userId);
+        oaDocument.setDocStatus(oaQjdDocument.getDocStatus());
+        oaDocument.setCreateBy(username);
+        oaDocument.setCreateTime(oaQjdDocument.getCreateTime());
+        oaDocument.setDeptId(deptId);
+        oaDocument.setTenantId(tenantId);
+        oaDocumentMapper.insert(oaDocument);
+
+        if (oaQjdDocument.getDocStatus().equals(1)) {
+            // 生成一条审批记录数据
+            OaApproval oaApproval = new OaApproval();
+            oaApproval.setDocNo(docNo);
+            oaApproval.setType(0);
+            oaApproval.setApprovalStatus(1);
+            oaApproval.setApprovalUid(101L);
+            oaApproval.setProposer(Math.toIntExact(userId));
+            oaApproval.setCreateBy(username);
+            oaApproval.setCreateTime(now);
+            oaApproval.setSubmitDate(now);
+            oaApproval.setDeptId(deptId);
+            oaApproval.setTenantId(tenantId);
+            oaApprovalMapper.insert(oaApproval);
+
+            // 发送审批消息
+            List<Long> receivers = Collections.singletonList(oaApproval.getApprovalUid());
+            oaSendMessageCenter.sendAsyncMessage(oaApproval.getCreateBy(), userId, oaApproval.getId(), receivers, 3);
+        }
+    }
+
+    @Override
+    public void updateQjDocument(OaQjdDocument oaQjdDocument) {
+
+        if (StringUtils.isBlank(oaQjdDocument.getDocNo())) {
+            throw new BusinessException("更新请假单据ID异常");
+        }
+
+        validateOaQjDocument(oaQjdDocument);
+        String username = SecurityUtils.getUsername();
+        LocalDateTime now = LocalDateTime.now();
+        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
+        Integer tenantId = SecurityUtils.getTenantId();
+        Long userId = SecurityUtils.getUserId();
+
+        oaQjdDocument.setUpdateBy(username);
+        oaQjdDocument.setUpdateTime(now);
+        oaQjdDocumentMapper.updateById(oaQjdDocument);
+
+        oaDocumentMapper.update(null, Wrappers.lambdaUpdate(OaDocument.class)
+                .eq(OaDocument::getDocNo, oaQjdDocument.getDocNo())
+                .set(OaDocument::getDocStatus, oaQjdDocument.getDocStatus())
+                .set(OaDocument::getUpdateBy, username)
+                .set(OaDocument::getUpdateTime, oaQjdDocument.getUpdateTime())
+        );
+
+        if (oaQjdDocument.getDocStatus().equals(1)) {
+            // 生成一条审批记录数据
+            OaApproval oaApproval = new OaApproval();
+            oaApproval.setDocNo(oaQjdDocument.getDocNo());
+            oaApproval.setType(0);
+            oaApproval.setApprovalStatus(1);
+            oaApproval.setApprovalUid(101L);
+            oaApproval.setProposer(Math.toIntExact(userId));
+            oaApproval.setCreateBy(username);
+            oaApproval.setCreateTime(now);
+            oaApproval.setSubmitDate(now);
+            oaApproval.setDeptId(deptId);
+            oaApproval.setTenantId(tenantId);
+            oaApprovalMapper.insert(oaApproval);
+
+            // 发送审批消息
+            List<Long> receivers = Collections.singletonList(oaApproval.getApprovalUid());
+            oaSendMessageCenter.sendAsyncMessage(oaApproval.getCreateBy(), userId, oaApproval.getId(), receivers, 3);
+        }
+    }
+
+    /**
+     * @description: 校验请假单据表数据
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2024/12/27 10:04
+     * @param: [oaQjDocument]
+     * @return: void
+     **/
+    public void validateOaQjDocument(OaQjdDocument oaQjdDocument) {
+
+        if (oaQjdDocument.getFormId() == null || oaQjdDocument.getFormId() <= 0) {
+            throw new BusinessException("表单ID不能为空或小于等于0");
+        }
+
+        if (StringUtils.isBlank(oaQjdDocument.getType())) {
+            throw new BusinessException("请假类型不能为空");
+        }
+
+        if (oaQjdDocument.getType().length() > 4) {
+            throw new BusinessException("请假类型长度不能超过4个字符");
+        }
+
+        if (oaQjdDocument.getStartTime() == null || oaQjdDocument.getEndTime() == null) {
+            throw new BusinessException("请假开始时间或结束时间不能为空");
+        }
+
+        if (oaQjdDocument.getStartTime().isAfter(oaQjdDocument.getEndTime())) {
+            throw new BusinessException("请假开始时间不能大于结束时间");
+        }
+
+        if (oaQjdDocument.getDuration() == null || oaQjdDocument.getDuration() <= 0) {
+            throw new BusinessException("请假时长不能为空或小于等于0");
+        }
+
+        if (StringUtils.isBlank(oaQjdDocument.getReason())) {
+            throw new BusinessException("请假原因不能为空");
+        }
+
+        if (oaQjdDocument.getReason().length() > 255) {
+            throw new BusinessException("请假原因超出字数限制,请重试");
+        }
+
+        if (oaQjdDocument.getImage() != null && oaQjdDocument.getImage().length() > 500) {
+            throw new BusinessException("上传图片数量超出限制,请重试");
+        }
+    }
+
+    @Override
+    public void delQjDocument(String docNo) {
+
+        if (StringUtils.isBlank(docNo)) {
+            throw new BusinessException("请假单据编号不能为空!");
+        }
+
+        LambdaQueryWrapper<OaQjdDocument> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(OaQjdDocument::getDocNo, docNo);
+        oaQjdDocumentMapper.delete(queryWrapper);
+
+        LambdaQueryWrapper<OaDocument> deleteWrapper = Wrappers.lambdaQuery();
+        deleteWrapper.eq(OaDocument::getDocNo, docNo);
+        oaDocumentMapper.delete(deleteWrapper);
+    }
+}

+ 33 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/utils/OaDefinitionDocumentInfo.java

@@ -0,0 +1,33 @@
+package com.usky.oa.service.utils;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2024/12/25
+ */
+public class OaDefinitionDocumentInfo {
+    private String sign;
+    private String name;
+
+    public OaDefinitionDocumentInfo(String sign, String name) {
+        this.sign = sign;
+        this.name = name;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

+ 53 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/utils/OaProcessAnalysis.java

@@ -0,0 +1,53 @@
+package com.usky.oa.service.utils;
+
+import com.usky.common.core.exception.BusinessException;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+
+import java.io.StringReader;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/1/23
+ */
+@Slf4j
+@Configuration
+public class OaProcessAnalysis {
+    public void processAnalysis(String xmlString) {
+        try {
+            // 创建 SAXReader 对象
+            SAXReader reader = new SAXReader();
+            // 将 XML 字符串解析为 Document 对象
+            Document document = reader.read(new StringReader(xmlString));
+
+            // 获取根元素
+            Element root = document.getRootElement();
+
+            // 遍历根元素的子元素
+            parseElement(root);
+        } catch (DocumentException e) {
+            throw new BusinessException("解析流程xml文件失败" + e);
+        }
+    }
+
+    private void parseElement(Element element) {
+        // 输出元素名称
+        System.out.println("元素名称: " + element.getName());
+        // 处理元素的属性
+        element.attributes().forEach(attribute -> {
+            System.out.println("元素属性: " + attribute.getName() + ", 元素值: " + attribute.getValue());
+        });
+        // 遍历子元素
+        element.elements().forEach(subElement -> {
+            // 递归处理子元素
+            parseElement((Element) subElement);
+        });
+    }
+}

+ 93 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/utils/OaSendMessageCenter.java

@@ -0,0 +1,93 @@
+package com.usky.oa.service.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.usky.common.core.bean.ApiResult;
+import com.usky.common.core.exception.BusinessException;
+import com.usky.oa.mapper.SysUserMapper;
+import com.usky.system.RemoteMceService;
+import com.usky.system.domain.SysUser;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.Async;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/1/9
+ */
+@Slf4j
+@Configuration
+public class OaSendMessageCenter {
+
+    @Autowired
+    private RemoteMceService remoteMceService;
+
+    @Autowired
+    private SysUserMapper sysUserMapper;
+
+    private static final String INFO_TITLE = "审批提醒";
+    private static final String INFO_CONTENT = "的申请";
+    private static final String INFO_APPROVE_FAIL = "审核不通过";
+    private static final String INFO_APPROVE_SUCCESS = "审核通过";
+    private static final int INFO_TYPE = 3;
+
+    /**
+     * 异步发送消息
+     *
+     * @param username 提交人账号名
+     * @param submitterId 提交人id
+     * @param id 数据id
+     * @param receivers 接收人userId集合
+     * @param isPass 是否通过(0:不通过,1:通过)
+     */
+    @Async
+    public void sendAsyncMessage(String username, Long submitterId, Integer id, List<Long> receivers, Integer isPass) {
+
+        log.info(username + "的申请开始发送消息中心-----------------------------------");
+
+        LambdaQueryWrapper<SysUser> nickNameQuery = Wrappers.lambdaQuery();
+        nickNameQuery.select(SysUser::getNickName)
+                .eq(SysUser::getUserId, submitterId);
+        SysUser nickName = sysUserMapper.selectOne(nickNameQuery);
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("infoTitle", INFO_TITLE);
+
+        switch (isPass) {
+            case 0:
+                jsonObject.put("infoContent", nickName.getNickName() + INFO_APPROVE_FAIL);
+                break;
+            case 1:
+                jsonObject.put("infoContent", nickName.getNickName() + INFO_APPROVE_SUCCESS);
+                break;
+            default:
+                jsonObject.put("infoContent", nickName.getNickName() + INFO_CONTENT);
+        }
+
+        jsonObject.put("infoType", INFO_TYPE);
+        jsonObject.put("id", id);
+        jsonObject.put("infoTypeName", INFO_TITLE);
+        jsonObject.put("userName", username);
+        jsonObject.put("userIds", receivers);
+        try {
+            // 推送消息中心
+            ApiResult<Void> voidApiResult = remoteMceService.addMce(jsonObject.toString());
+
+            if (voidApiResult.isSuccess()) {
+                log.info("申请消息发送成功!");
+            } else {
+                log.error("申请消息发送失败!");
+            }
+        } catch (Exception e) {
+            log.error("申请发送消息时发生异常", e);
+        }
+        log.info(username + "的申请发送消息中心完成-----------------------------------");
+    }
+
+}

+ 54 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/vo/OaApprovalCountVO.java

@@ -0,0 +1,54 @@
+package com.usky.oa.service.vo;
+
+import lombok.Data;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2024/12/30
+ */
+@Data
+public class OaApprovalCountVO {
+
+    /**
+     * @description: 待处理
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/2 9:54
+     * @param:
+     * @return:
+     **/
+    private Integer pendingSum;
+
+    /**
+     * @description: 已处理
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/2 9:54
+     * @param:
+     * @return:
+     **/
+    private Integer alreadySum;
+
+    /**
+     * @description: 已发起
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/2 9:54
+     * @param:
+     * @return:
+     **/
+    private Integer myInitiated;
+
+    /**
+     * @description: 我收到的
+     * @author: fyc
+     * @email yuchuan.fu@chinausky.com
+     * @date: 2025/1/2 9:54
+     * @param:
+     * @return:
+     **/
+    private Integer myReceived;
+
+}

+ 23 - 0
service-oa/service-oa-biz/src/main/java/com/usky/oa/service/vo/OaFormNameResponseVO.java

@@ -0,0 +1,23 @@
+package com.usky.oa.service.vo;
+
+import lombok.Data;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/1/3
+ */
+@Data
+public class OaFormNameResponseVO {
+
+    /** 表单id */
+    private Integer formId;
+
+    /** 表单标识 */
+    private String formSign;
+
+    /** 表单名 */
+    private String formName;
+
+}

+ 1 - 1
service-oa/service-oa-biz/src/main/resources/bootstrap.yml

@@ -1,6 +1,6 @@
 # Tomcat
 server:
-  port: 9889
+  port: 8100
 
 # Spring
 spring: 

+ 24 - 0
service-oa/service-oa-biz/src/main/resources/mapper/oa/OaApprovalMapper.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.usky.oa.mapper.OaApprovalMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.usky.oa.domain.OaApproval">
+        <id column="id" property="id" />
+        <result column="doc_no" property="docNo" />
+        <result column="approval_uid" property="approvalUid" />
+        <result column="proposer" property="proposer" />
+        <result column="type" property="type" />
+        <result column="approval_status" property="approvalStatus" />
+        <result column="opinion" property="opinion" />
+        <result column="submit_date" property="submitDate" />
+        <result column="approval_date" property="approvalDate" />
+        <result column="create_by" property="createBy" />
+        <result column="create_time" property="createTime" />
+        <result column="update_by" property="updateBy" />
+        <result column="update_time" property="updateTime" />
+        <result column="dept_id" property="deptId" />
+        <result column="tenant_id" property="tenantId" />
+    </resultMap>
+
+</mapper>

+ 81 - 0
service-oa/service-oa-biz/src/main/resources/mapper/oa/OaDocumentMapper.xml

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.usky.oa.mapper.OaDocumentMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.usky.oa.domain.OaDocument">
+        <id column="id" property="id"/>
+        <result column="form_id" property="formId"/>
+        <result column="type" property="type"/>
+        <result column="doc_no" property="docNo"/>
+        <result column="proposer" property="proposer"/>
+        <result column="doc_status" property="docStatus"/>
+        <result column="create_by" property="createBy"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_by" property="updateBy"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="dept_id" property="deptId"/>
+        <result column="tenant_id" property="tenantId"/>
+    </resultMap>
+
+    <!-- 动态创建表-->
+    <update id="createTable">
+        create table if not exists ${tableName} (
+        <foreach collection="columns" item="column" separator=",">
+            ${column.name} ${column.type}
+        </foreach>
+        , PRIMARY KEY (${primaryKey})
+        )
+    </update>
+
+    <!-- 动态更新数据 -->
+    <update id="updateData" parameterType="map">
+        update ${(tableName)}
+        <set>
+            <if test="map != null and !map.isEmpty()">
+                <foreach collection="map" item="entry" index="key" separator=",">
+                    #{key} = #{entry.value}
+                </foreach>
+            </if>
+        </set>
+        where id = #{id}
+    </update>
+
+    <!-- 动态查询数据 -->
+    <select id="selectData" parameterType="map" resultType="map">
+        select *
+        from ${tableName}
+        <where>
+            <foreach collection="conditions" item="condition" separator="and">
+                ${condition.column} ${condition.operator} #{condition.value}
+            </foreach>
+        </where>
+        <if test="limit != null and offset != null">
+            limit #{limit} offset #{offset}
+        </if>
+    </select>
+
+    <!-- 动态插入数据 -->
+    <insert id="insertData">
+        insert into ${tableName} (
+        <foreach collection="columns" item="column" separator=",">
+            ${column}
+        </foreach>
+        ) values (
+        <foreach collection="values" item="value" separator=",">
+            #{value}
+        </foreach>
+        )
+    </insert>
+
+    <!-- 动态删除数据 -->
+    <delete id="deleteData" parameterType="map">
+        delete from ${tableName}
+        <where>
+            <foreach collection="conditions" item="condition" separator="and">
+                ${condition.column} ${condition.operator} #{condition.value}
+            </foreach>
+        </where>
+    </delete>
+
+</mapper>

+ 30 - 0
service-oa/service-oa-biz/src/main/resources/mapper/oa/OaFormDefinitionMapper.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.usky.oa.mapper.OaFormDefinitionMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.usky.oa.domain.OaFormDefinition">
+        <id column="id" property="id" />
+        <result column="form_name" property="formName" />
+        <result column="form_group" property="formGroup" />
+        <result column="form_explain" property="formExplain" />
+        <result column="form_type" property="formType" />
+        <result column="field_info" property="fieldInfo" />
+        <result column="flow_info" property="flowInfo" />
+        <result column="form_version" property="formVersion" />
+        <result column="form_sign" property="formSign" />
+        <result column="form_image" property="formImage" />
+        <result column="form_scope" property="formScope" />
+        <result column="form_status" property="formStatus" />
+        <!--<result column="doc_no" property="docNo" />-->
+        <result column="dept_ids" property="deptIds" />
+        <result column="user_ids" property="userIds" />
+        <result column="create_by" property="createBy" />
+        <result column="create_time" property="createTime" />
+        <result column="update_by" property="updateBy" />
+        <result column="update_time" property="updateTime" />
+        <result column="dept_id" property="deptId" />
+        <result column="tenant_id" property="tenantId" />
+    </resultMap>
+
+</mapper>

+ 26 - 0
service-oa/service-oa-biz/src/main/resources/mapper/oa/OaJbdDocumentMapper.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.usky.oa.mapper.OaJbdDocumentMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.usky.oa.domain.OaJbdDocument">
+        <id column="id" property="id" />
+        <result column="form_id" property="formId" />
+        <result column="doc_no" property="docNo" />
+        <result column="proposer" property="proposer" />
+        <result column="doc_status" property="docStatus" />
+        <result column="start_time" property="startTime" />
+        <result column="end_time" property="endTime" />
+        <result column="duration" property="duration" />
+        <result column="accounting_method" property="accountingMethod" />
+        <result column="reason" property="reason" />
+        <result column="image" property="image" />
+        <result column="create_by" property="createBy" />
+        <result column="create_time" property="createTime" />
+        <result column="update_by" property="updateBy" />
+        <result column="update_time" property="updateTime" />
+        <result column="dept_id" property="deptId" />
+        <result column="tenant_id" property="tenantId" />
+    </resultMap>
+
+</mapper>

+ 25 - 0
service-oa/service-oa-biz/src/main/resources/mapper/oa/OaQjdDocumentMapper.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.usky.oa.mapper.OaQjdDocumentMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.usky.oa.domain.OaQjdDocument">
+        <id column="id" property="id" />
+        <result column="type" property="type" />
+        <result column="doc_no" property="docNo" />
+        <result column="proposer" property="proposer" />
+        <result column="doc_status" property="docStatus" />
+        <result column="start_time" property="startTime" />
+        <result column="end_time" property="endTime" />
+        <result column="duration" property="duration" />
+        <result column="reason" property="reason" />
+        <result column="image" property="image" />
+        <result column="create_by" property="createBy" />
+        <result column="create_time" property="createTime" />
+        <result column="update_by" property="updateBy" />
+        <result column="update_time" property="updateTime" />
+        <result column="dept_id" property="deptId" />
+        <result column="tenant_id" property="tenantId" />
+    </resultMap>
+
+</mapper>

Some files were not shown because too many files changed in this diff