src/main/java/com/ruoyi/approve/bean/dto/ApprovalInstanceDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,21 @@ package com.ruoyi.approve.bean.dto; import com.ruoyi.approve.pojo.ApprovalInstance; import com.ruoyi.basic.dto.StorageBlobDTO; import lombok.Data; import java.util.List; @Data public class ApprovalInstanceDto extends ApprovalInstance { private String approveAction; private String approveComment; private String createTimeEnd; private String createTimeStart; private List<StorageBlobDTO> storageBlobDTOs; } src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,12 @@ package com.ruoyi.approve.bean.dto; import com.ruoyi.approve.pojo.ApprovalTemplate; import lombok.Data; import java.util.List; @Data public class ApprovalTemplateDto extends ApprovalTemplate { private List<ApprovalTemplateNodeDto> nodes; } src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateNodeApproverDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,8 @@ package com.ruoyi.approve.bean.dto; import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover; import lombok.Data; @Data public class ApprovalTemplateNodeApproverDto extends ApprovalTemplateNodeApprover { } src/main/java/com/ruoyi/approve/bean/dto/ApprovalTemplateNodeDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,12 @@ package com.ruoyi.approve.bean.dto; import com.ruoyi.approve.pojo.ApprovalTemplateNode; import lombok.Data; import java.util.List; @Data public class ApprovalTemplateNodeDto extends ApprovalTemplateNode { private List<ApprovalTemplateNodeApproverDto> approvers; } src/main/java/com/ruoyi/approve/bean/dto/FinReimbursementDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,21 @@ package com.ruoyi.approve.bean.dto; import com.ruoyi.approve.pojo.FinReimbursement; import com.ruoyi.approve.pojo.FinReimbursementDetail; import com.ruoyi.approve.pojo.FinReimbursementTravel; import com.ruoyi.basic.dto.StorageBlobDTO; import lombok.Data; import java.util.List; @Data public class FinReimbursementDto extends FinReimbursement { private String createTimeStart; private String createTimeEnd; private FinReimbursementTravel travel; private List<FinReimbursementDetail> details; private List<ApprovalTemplateNodeDto> nodes; private List<StorageBlobDTO> storageBlobDTOs; } src/main/java/com/ruoyi/approve/bean/vo/ApprovalInstanceVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,28 @@ package com.ruoyi.approve.bean.vo; import com.ruoyi.approve.pojo.ApprovalInstance; import com.ruoyi.approve.pojo.ApprovalRecord; import com.ruoyi.approve.pojo.ApprovalTask; import com.ruoyi.basic.dto.StorageBlobVO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.List; @Data public class ApprovalInstanceVo extends ApprovalInstance { //å½åç¨æ·æ¯å¦å¯ä»¥å®¡æ¹ @Schema(description = "å½åç¨æ·æ¯å¦å¯ä»¥å®¡æ¹") private Boolean isApprove; //å®¡æ¹æµç¨ private List<ApprovalTask> tasks; //审æ¹è®°å½ private List<ApprovalRecord> records; @Schema(description = "ä¸å¡åç§°") private String businessName; private List<StorageBlobVO> storageBlobVOList; } src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateNodeApproverVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,9 @@ package com.ruoyi.approve.bean.vo; import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover; import lombok.Data; @Data public class ApprovalTemplateNodeApproverVo extends ApprovalTemplateNodeApprover { } src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateNodeVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,13 @@ package com.ruoyi.approve.bean.vo; import com.ruoyi.approve.pojo.ApprovalTemplateNode; import lombok.Data; import java.util.List; @Data public class ApprovalTemplateNodeVo extends ApprovalTemplateNode { private List<ApprovalTemplateNodeApproverVo> approvers; } src/main/java/com/ruoyi/approve/bean/vo/ApprovalTemplateVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,14 @@ package com.ruoyi.approve.bean.vo; import com.ruoyi.approve.pojo.ApprovalTemplate; import lombok.Data; import java.util.List; @Data public class ApprovalTemplateVo extends ApprovalTemplate { private List<ApprovalTemplateNodeVo> nodes; private String createdUserName; } src/main/java/com/ruoyi/approve/bean/vo/FinReimbursementVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,34 @@ package com.ruoyi.approve.bean.vo; import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.approve.pojo.*; import com.ruoyi.basic.dto.StorageBlobVO; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; import java.util.List; @Data public class FinReimbursementVo extends FinReimbursement { private String createTimeStart; private String createTimeEnd; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime startTime; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime endTime; private FinReimbursementTravel travel; private List<FinReimbursementDetail> details; //å®¡æ¹æµç¨ private List<ApprovalTask> tasks; //审æ¹è®°å½ private List<ApprovalRecord> records; private List<StorageBlobVO> storageBlobVOList; } src/main/java/com/ruoyi/approve/controller/ApprovalInstanceController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,67 @@ package com.ruoyi.approve.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.approve.bean.dto.ApprovalInstanceDto; import com.ruoyi.approve.bean.vo.ApprovalInstanceVo; import com.ruoyi.approve.service.ApprovalInstanceService; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; import com.ruoyi.framework.web.controller.BaseController; import com.ruoyi.framework.web.domain.R; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.*; import java.util.List; /** * <p> * 审æ¹å®ä¾è¡¨ å端æ§å¶å¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:27:46 */ @RestController @RequestMapping("/approvalInstance") @Tag(name = "审æ¹å®ä¾è¡¨") @AllArgsConstructor public class ApprovalInstanceController extends BaseController { private final ApprovalInstanceService approvalInstanceService; @GetMapping("/listPage") @Operation(summary = "å页æ¥è¯¢") @Log(title = "审æ¹å表å页æ¥è¯¢", businessType = BusinessType.OTHER) public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) { return approvalInstanceService.listPage(page, approvalInstanceDto); } @PostMapping("/save") @Operation(summary = "ä¿å") @Log(title = "审æ¹å表ä¿å", businessType = BusinessType.INSERT) public R save(@RequestBody ApprovalInstanceDto approvalInstanceDto) { return approvalInstanceService.add(approvalInstanceDto) ? R.ok() : R.fail(); } @PutMapping("/update") @Operation(summary = "æ´æ°") @Log(title = "审æ¹åè¡¨æ´æ°", businessType = BusinessType.UPDATE) public R update(@RequestBody ApprovalInstanceDto approvalInstanceDto) { return approvalInstanceService.update(approvalInstanceDto) ? R.ok() : R.fail(); } @DeleteMapping("/delete") @Log(title = "审æ¹å表å é¤", businessType = BusinessType.DELETE) @Operation(summary = "å é¤") public R delete(@RequestBody List<Long> ids) { return approvalInstanceService.delete(ids) ? R.ok() : R.fail(); } @Operation(summary = "审æ¹") @PostMapping("/approve") @Log(title = "审æ¹å表审æ¹", businessType = BusinessType.UPDATE) public R approve(@RequestBody ApprovalInstanceDto approvalInstanceDto) { return approvalInstanceService.approve(approvalInstanceDto); } } src/main/java/com/ruoyi/approve/controller/ApprovalInstanceNodeController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,19 @@ package com.ruoyi.approve.controller; import com.ruoyi.framework.web.controller.BaseController; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * 审æ¹èç¹å®ä¾è¡¨ å端æ§å¶å¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:27:54 */ @RestController @RequestMapping("/approvalInstanceNode") public class ApprovalInstanceNodeController extends BaseController { } src/main/java/com/ruoyi/approve/controller/ApprovalRecordController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * 审æ¹è®°å½è¡¨ å端æ§å¶å¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:28:21 */ @RestController @RequestMapping("/approvalRecord") public class ApprovalRecordController { } src/main/java/com/ruoyi/approve/controller/ApprovalTaskController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * 审æ¹ä»»å¡è¡¨ å端æ§å¶å¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:32:37 */ @RestController @RequestMapping("/approvalTask") public class ApprovalTaskController { } src/main/java/com/ruoyi/approve/controller/ApprovalTemplateController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,74 @@ package com.ruoyi.approve.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.approve.bean.dto.ApprovalTemplateDto; import com.ruoyi.approve.bean.vo.ApprovalTemplateVo; import com.ruoyi.approve.service.ApprovalTemplateService; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; import com.ruoyi.framework.web.controller.BaseController; import com.ruoyi.framework.web.domain.R; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.*; import java.util.List; /** * <p> * å®¡æ¹æ¨¡æ¿è¡¨ å端æ§å¶å¨ * </p> * * @author èéè½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:08 */ @RestController @RequestMapping("/approvalTemplate") @Tag(name = "å®¡æ¹æ¨¡æ¿è¡¨") @AllArgsConstructor public class ApprovalTemplateController extends BaseController { private final ApprovalTemplateService approvalTemplateService; @GetMapping("/listPage") @Operation(summary = "å页æ¥è¯¢") @Log(title = "å®¡æ¹æ¨¡æ¿å页æ¥è¯¢", businessType = BusinessType.OTHER) public R listPage(Page<ApprovalTemplateVo> page, ApprovalTemplateDto approvalTemplateDto) { return R.ok(approvalTemplateService.listPage(page, approvalTemplateDto)); } @PostMapping("/add") @Operation(summary = "æ·»å ") @Log(title = "æ·»å å®¡æ¹æ¨¡æ¿", businessType = BusinessType.INSERT) public R add(@RequestBody ApprovalTemplateDto approvalTemplateDto) { return R.ok(approvalTemplateService.saveApprovalTemplateDto(approvalTemplateDto)); } @PutMapping("/update") @Operation(summary = "ä¿®æ¹") @Log(title = "ä¿®æ¹å®¡æ¹æ¨¡æ¿", businessType = BusinessType.UPDATE) public R update(@RequestBody ApprovalTemplateDto approvalTemplateDto) { return R.ok(approvalTemplateService.updateApprovalTemplateDto(approvalTemplateDto)); } @PostMapping("/delete") @Operation(summary = "å é¤") @Log(title = "å é¤å®¡æ¹æ¨¡æ¿", businessType = BusinessType.DELETE) public R delete(@RequestBody List<Long> ids) { return R.ok(approvalTemplateService.delete(ids)); } @GetMapping("/list/{type}") @Operation(summary = "æ¥è¯¢ææå®¡æ¹æ¨¡æ¿") public R list(@PathVariable("type") Integer type) { return R.ok(approvalTemplateService.listApprovalTemplateVo(type)); } @GetMapping("/detail/{id}") @Operation(summary = "æ¥è¯¢å®¡æ¹æ¨¡æ¿è¯¦æ ") @Log(title = "æ¥è¯¢å®¡æ¹æ¨¡æ¿è¯¦æ ", businessType = BusinessType.OTHER) public R detail(@PathVariable("id") Long id) { return R.ok(approvalTemplateService.getApprovalTemplateVoById(id)); } } src/main/java/com/ruoyi/approve/controller/ApprovalTemplateNodeApproverController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * å®¡æ¹æ¨¡æ¿èç¹å®¡æ¹äººè¡¨ å端æ§å¶å¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:30 */ @RestController @RequestMapping("/approvalTemplateNodeApprover") public class ApprovalTemplateNodeApproverController { } src/main/java/com/ruoyi/approve/controller/ApprovalTemplateNodeController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * å®¡æ¹æ¨¡æ¿èç¹è¡¨ å端æ§å¶å¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:19 */ @RestController @RequestMapping("/approvalTemplateNode") public class ApprovalTemplateNodeController { } src/main/java/com/ruoyi/approve/controller/FinReimbursementController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,60 @@ package com.ruoyi.approve.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.approve.bean.dto.FinReimbursementDto; import com.ruoyi.approve.bean.vo.FinReimbursementVo; import com.ruoyi.approve.service.FinReimbursementService; import com.ruoyi.framework.web.domain.R; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.*; import java.util.List; /** * <p> * æ¥éå主表 å端æ§å¶å¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:15 */ @RestController @RequestMapping("/finReimbursement") @Tag(name = "æ¥éå主表", description = "æ¥éå主表") @AllArgsConstructor public class FinReimbursementController { private final FinReimbursementService finReimbursementService; @GetMapping("/listPage") @Operation(summary = "å页æ¥è¯¢") public R listPage(Page<FinReimbursementVo> page, FinReimbursementDto finReimbursementDto) { return R.ok(finReimbursementService.listPage(finReimbursementDto, page)); } @PostMapping("/save") @Operation(summary = "ä¿å") public R save(@RequestBody FinReimbursementDto finReimbursementDto) { return R.ok(finReimbursementService.add(finReimbursementDto)); } @GetMapping("/detail") @Operation(summary = "详æ ") public R detail(Long id) { return R.ok(finReimbursementService.detail(id)); } @PostMapping("/update") @Operation(summary = "ä¿®æ¹") public R update(@RequestBody FinReimbursementDto finReimbursementDto) { return R.ok(finReimbursementService.update(finReimbursementDto)); } @DeleteMapping("/delete") @Operation(summary = "å é¤") public R delete(@RequestBody List<Long> ids) { return R.ok(finReimbursementService.delete(ids)); } } src/main/java/com/ruoyi/approve/controller/FinReimbursementDetailController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * æ¥éåæç»è¡¨ å端æ§å¶å¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:38 */ @RestController @RequestMapping("/finReimbursementDetail") public class FinReimbursementDetailController { } src/main/java/com/ruoyi/approve/controller/FinReimbursementTravelController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * å·®æ æ¥éæ©å±è¡¨ å端æ§å¶å¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:47 */ @RestController @RequestMapping("/finReimbursementTravel") public class FinReimbursementTravelController { } src/main/java/com/ruoyi/approve/mapper/ApprovalInstanceMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,24 @@ package com.ruoyi.approve.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.approve.bean.dto.ApprovalInstanceDto; import com.ruoyi.approve.bean.vo.ApprovalInstanceVo; import com.ruoyi.approve.pojo.ApprovalInstance; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * <p> * 审æ¹å®ä¾è¡¨ Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:27:46 */ @Mapper public interface ApprovalInstanceMapper extends BaseMapper<ApprovalInstance> { IPage<ApprovalInstanceVo> listPage(Page<ApprovalInstanceVo> page,@Param("ew") ApprovalInstanceDto approvalInstanceDto); } src/main/java/com/ruoyi/approve/mapper/ApprovalInstanceNodeMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.approve.pojo.ApprovalInstanceNode; import org.apache.ibatis.annotations.Mapper; /** * <p> * 审æ¹èç¹å®ä¾è¡¨ Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:27:54 */ @Mapper public interface ApprovalInstanceNodeMapper extends BaseMapper<ApprovalInstanceNode> { } src/main/java/com/ruoyi/approve/mapper/ApprovalRecordMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.approve.pojo.ApprovalRecord; import org.apache.ibatis.annotations.Mapper; /** * <p> * 审æ¹è®°å½è¡¨ Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:28:21 */ @Mapper public interface ApprovalRecordMapper extends BaseMapper<ApprovalRecord> { } src/main/java/com/ruoyi/approve/mapper/ApprovalTaskMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.approve.pojo.ApprovalTask; import org.apache.ibatis.annotations.Mapper; /** * <p> * 审æ¹ä»»å¡è¡¨ Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:32:37 */ @Mapper public interface ApprovalTaskMapper extends BaseMapper<ApprovalTask> { } src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,24 @@ package com.ruoyi.approve.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.approve.bean.dto.ApprovalTemplateDto; import com.ruoyi.approve.bean.vo.ApprovalTemplateVo; import com.ruoyi.approve.pojo.ApprovalTemplate; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * <p> * å®¡æ¹æ¨¡æ¿è¡¨ Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:08 */ @Mapper public interface ApprovalTemplateMapper extends BaseMapper<ApprovalTemplate> { IPage<ApprovalTemplateVo> listPage(Page<ApprovalTemplateVo> page,@Param("ew") ApprovalTemplateDto approvalTemplateDto); } src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateNodeApproverMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover; import org.apache.ibatis.annotations.Mapper; /** * <p> * å®¡æ¹æ¨¡æ¿èç¹å®¡æ¹äººè¡¨ Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:30 */ @Mapper public interface ApprovalTemplateNodeApproverMapper extends BaseMapper<ApprovalTemplateNodeApprover> { } src/main/java/com/ruoyi/approve/mapper/ApprovalTemplateNodeMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.approve.pojo.ApprovalTemplateNode; import org.apache.ibatis.annotations.Mapper; /** * <p> * å®¡æ¹æ¨¡æ¿èç¹è¡¨ Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:19 */ @Mapper public interface ApprovalTemplateNodeMapper extends BaseMapper<ApprovalTemplateNode> { } src/main/java/com/ruoyi/approve/mapper/FinReimbursementDetailMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.approve.pojo.FinReimbursementDetail; import org.apache.ibatis.annotations.Mapper; /** * <p> * æ¥éåæç»è¡¨ Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:38 */ @Mapper public interface FinReimbursementDetailMapper extends BaseMapper<FinReimbursementDetail> { } src/main/java/com/ruoyi/approve/mapper/FinReimbursementMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,24 @@ package com.ruoyi.approve.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.approve.bean.dto.FinReimbursementDto; import com.ruoyi.approve.bean.vo.FinReimbursementVo; import com.ruoyi.approve.pojo.FinReimbursement; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * <p> * æ¥éå主表 Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:15 */ @Mapper public interface FinReimbursementMapper extends BaseMapper<FinReimbursement> { IPage<FinReimbursementVo> listPage(@Param("ew") FinReimbursementDto finReimbursementDto, Page<FinReimbursementVo> page); } src/main/java/com/ruoyi/approve/mapper/FinReimbursementTravelMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.approve.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.approve.pojo.FinReimbursementTravel; import org.apache.ibatis.annotations.Mapper; /** * <p> * å·®æ æ¥éæ©å±è¡¨ Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:47 */ @Mapper public interface FinReimbursementTravelMapper extends BaseMapper<FinReimbursementTravel> { } src/main/java/com/ruoyi/approve/pojo/ApprovalInstance.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,152 @@ package com.ruoyi.approve.pojo; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serializable; import java.time.LocalDateTime; /** * <p> * 审æ¹å®ä¾è¡¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:27:46 */ @Getter @Setter @ToString @TableName("approval_instance") @ApiModel(value = "ApprovalInstance对象", description = "审æ¹å®ä¾è¡¨") public class ApprovalInstance implements Serializable { private static final long serialVersionUID = 1L; /** * 审æ¹å®ä¾ID */ @Schema(description ="审æ¹å®ä¾ID") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 审æ¹ç¼å· */ @Schema(description ="审æ¹ç¼å·") private String instanceNo; /** * 模æ¿ID */ @Schema(description ="模æ¿ID") private Long templateId; /** * 模æ¿åç§° */ @Schema(description ="模æ¿åç§°") private String templateName; /** * ä¸å¡ID */ @Schema(description ="ä¸å¡ID") private Long businessId; /** * ä¸å¡ç±»å */ @Schema(description ="ä¸å¡ç±»å") private Long businessType; /** * å®¡æ¹æ é¢ */ @Schema(description ="å®¡æ¹æ é¢") private String title; /** * 审æ¹ç¶æ */ @Schema(description ="审æ¹ç¶æ PENDING - å¾ å®¡æ¹/è¿è¡ä¸ APPROVED - å·²éè¿/已宿 REJECTED - 已驳å") private String status; /** * å½å审æ¹çº§å« */ @Schema(description ="å½å审æ¹çº§å«") private Integer currentLevel; /** * ç³è¯·äººID */ @Schema(description ="ç³è¯·äººID") private Long applicantId; /** * ç³è¯·äººåç§° */ @Schema(description ="ç³è¯·äººåç§°") private String applicantName; /** * ç³è¯·æ¶é´ */ @Schema(description ="ç³è¯·æ¶é´") private LocalDateTime applyTime; /** * 宿æ¶é´ */ @Schema(description ="宿æ¶é´") private LocalDateTime finishTime; /** * å建人 */ @Schema(description ="å建人") @TableField(fill = FieldFill.INSERT) private Long createUser; /** * å建æ¶é´ */ @Schema(description ="å建æ¶é´") @TableField(fill = FieldFill.INSERT) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; /** * æ´æ°äºº */ @Schema(description ="æ´æ°äºº") @TableField(fill = FieldFill.INSERT_UPDATE) private Long updateUser; /** * æ´æ°æ¶é´ */ @Schema(description ="æ´æ°æ¶é´") @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; @TableField(fill = FieldFill.INSERT) private Long deptId; /** * é»è¾å é¤ */ @Schema(description ="é»è¾å é¤") private Byte deleted; @Schema(description = "è¡¨åæ°æ®") private String formConfig; } src/main/java/com/ruoyi/approve/pojo/ApprovalInstanceNode.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,106 @@ package com.ruoyi.approve.pojo; import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import lombok.ToString; import java.io.Serializable; import java.time.LocalDateTime; /** * <p> * 审æ¹èç¹å®ä¾è¡¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:27:54 */ @Getter @Setter @ToString @TableName("approval_instance_node") @ApiModel(value = "ApprovalInstanceNode对象", description = "审æ¹èç¹å®ä¾è¡¨") public class ApprovalInstanceNode implements Serializable { private static final long serialVersionUID = 1L; /** * èç¹å®ä¾ID */ @Schema(description ="èç¹å®ä¾ID") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 审æ¹å®ä¾ID */ @Schema(description ="审æ¹å®ä¾ID") private Long instanceId; /** * 审æ¹çº§å« */ @Schema(description ="审æ¹çº§å«") private Integer levelNo; /** * 审æ¹ç±»å */ @Schema(description ="审æ¹ç±»å") private String approveType; /** * èç¹ç¶æ */ @Schema(description ="èç¹ç¶æ PENDING - å¾ å¤ç APPROVED - å·²éè¿ REJECTED - 已驳å") private String status; /** * å¼å§æ¶é´ */ @Schema(description ="å¼å§æ¶é´") private LocalDateTime startTime; /** * 宿æ¶é´ */ @Schema(description ="宿æ¶é´") private LocalDateTime finishTime; /** * å建人 */ @Schema(description ="å建人") @TableField(fill = FieldFill.INSERT) private Long createUser; /** * å建æ¶é´ */ @Schema(description ="å建æ¶é´") @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; /** * æ´æ°äºº */ @Schema(description ="æ´æ°äºº") @TableField(fill = FieldFill.INSERT_UPDATE) private Long updateUser; /** * æ´æ°æ¶é´ */ @Schema(description ="æ´æ°æ¶é´") @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; /** * é»è¾å é¤ */ @Schema(description ="é»è¾å é¤") private Byte deleted; } src/main/java/com/ruoyi/approve/pojo/ApprovalRecord.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,98 @@ package com.ruoyi.approve.pojo; import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import lombok.ToString; import java.io.Serializable; import java.time.LocalDateTime; /** * <p> * 审æ¹è®°å½è¡¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:28:21 */ @Getter @Setter @ToString @TableName("approval_record") @ApiModel(value = "ApprovalRecord对象", description = "审æ¹è®°å½è¡¨") public class ApprovalRecord implements Serializable { private static final long serialVersionUID = 1L; /** * 审æ¹è®°å½ID */ @Schema(description ="审æ¹è®°å½ID") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 审æ¹å®ä¾ID */ @Schema(description ="审æ¹å®ä¾ID") private Long instanceId; /** * èç¹å®ä¾ID */ @Schema(description ="èç¹å®ä¾ID") private Long nodeId; /** * 审æ¹ä»»å¡ID */ @Schema(description ="审æ¹ä»»å¡ID") private Long taskId; /** * æä½äººID */ @Schema(description ="æä½äººID") private Long operatorId; /** * æä½äººåç§° */ @Schema(description ="æä½äººåç§°") private String operatorName; /** * æä½ç±»å */ @Schema(description ="æä½ç±»å") private String action; /** * å®¡æ¹æè§ */ @Schema(description ="å®¡æ¹æè§") private String comment; /** * å建人 */ @Schema(description ="å建人") @TableField(fill = FieldFill.INSERT) private Long createUser; /** * å建æ¶é´ */ @Schema(description ="å建æ¶é´") @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; /** * é»è¾å é¤ */ @Schema(description ="é»è¾å é¤") private Byte deleted; } src/main/java/com/ruoyi/approve/pojo/ApprovalTask.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,128 @@ package com.ruoyi.approve.pojo; import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import lombok.ToString; import java.io.Serializable; import java.time.LocalDateTime; /** * <p> * 审æ¹ä»»å¡è¡¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:32:37 */ @Getter @Setter @ToString @TableName("approval_task") @ApiModel(value = "ApprovalTask对象", description = "审æ¹ä»»å¡è¡¨") public class ApprovalTask implements Serializable { private static final long serialVersionUID = 1L; /** * 审æ¹ä»»å¡ID */ @Schema(description ="审æ¹ä»»å¡ID") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 审æ¹å®ä¾ID */ @Schema(description ="审æ¹å®ä¾ID") private Long instanceId; /** * èç¹å®ä¾ID */ @Schema(description ="èç¹å®ä¾ID") private Long nodeId; /** * 审æ¹çº§å« */ @Schema(description ="审æ¹çº§å«") private Integer levelNo; /** * 审æ¹äººID */ @Schema(description ="审æ¹äººID") private Long approverId; /** * 审æ¹äººåç§° */ @Schema(description ="审æ¹äººåç§°") private String approverName; /** * ä»»å¡ç¶æ */ @Schema(description ="ä»»å¡ç¶æ PENDING - å¾ å®¡æ¹ APPROVED - å·²åæ REJECTED - å·²æç»") private String taskStatus; /** * å®¡æ¹æ¶é´ */ @Schema(description ="å®¡æ¹æ¶é´") private LocalDateTime approveTime; /** * å®¡æ¹æè§ */ @Schema(description ="å®¡æ¹æè§") private String comment; /** * æ¯å¦å·²è¯» */ @Schema(description ="æ¯å¦å·²è¯»") private Byte isRead; /** * å建人 */ @Schema(description ="å建人") @TableField(fill = FieldFill.INSERT) private Long createUser; /** * å建æ¶é´ */ @Schema(description ="å建æ¶é´") @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; /** * æ´æ°äºº */ @Schema(description ="æ´æ°äºº") @TableField(fill = FieldFill.INSERT_UPDATE) private Long updateUser; /** * æ´æ°æ¶é´ */ @Schema(description ="æ´æ°æ¶é´") @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; /** * é»è¾å é¤ */ @Schema(description ="é»è¾å é¤") private Byte deleted; @Schema(description ="é¨é¨ID") @TableField(fill = FieldFill.INSERT) private Long deptId; } src/main/java/com/ruoyi/approve/pojo/ApprovalTemplate.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,107 @@ package com.ruoyi.approve.pojo; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serializable; import java.time.LocalDateTime; /** * <p> * å®¡æ¹æ¨¡æ¿è¡¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:08 */ @Getter @Setter @ToString @TableName("approval_template") @ApiModel(value = "ApprovalTemplate对象", description = "å®¡æ¹æ¨¡æ¿è¡¨") public class ApprovalTemplate implements Serializable { private static final long serialVersionUID = 1L; /** * 模æ¿ID */ @Schema(description ="模æ¿ID") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 模æ¿åç§° */ @Schema(description ="模æ¿åç§°") private String templateName; /** * å¯ç¨ç¶æï¼1å¯ç¨ï¼0åç¨ */ @Schema(description ="å¯ç¨ç¶æï¼1å¯ç¨ï¼0åç¨") private Byte enabled; /** * 模æ¿è¯´æ */ @Schema(description ="模æ¿è¯´æ") private String description; /** * å建人 */ @Schema(description ="å建人") @TableField(fill = FieldFill.INSERT) private Long createUser; /** * å建æ¶é´ */ @Schema(description ="å建æ¶é´") @TableField(fill = FieldFill.INSERT) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; /** * æ´æ°äºº */ @Schema(description ="æ´æ°äºº") @TableField(fill = FieldFill.UPDATE) private Long updateUser; /** * æ´æ°æ¶é´ */ @Schema(description ="æ´æ°æ¶é´") @TableField(fill = FieldFill.UPDATE) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime updateTime; /** * é»è¾å é¤ï¼0å¦ï¼1æ¯ */ @Schema(description ="é»è¾å é¤ï¼0å¦ï¼1æ¯") private Integer deleted; @TableField(fill = FieldFill.INSERT) private Long deptId; @Schema(description = "表åé ç½®") private String formConfig; @Schema(description = "模æ¿ç±»åï¼0ç³»ç»å ç½®ï¼1èªå®ä¹") private Integer templateType; @Schema(description = "ä¸å¡ç±»å") private Long businessType; } src/main/java/com/ruoyi/approve/pojo/ApprovalTemplateNode.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,66 @@ package com.ruoyi.approve.pojo; import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import lombok.ToString; import java.io.Serializable; import java.time.LocalDateTime; /** * <p> * å®¡æ¹æ¨¡æ¿èç¹è¡¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:19 */ @Getter @Setter @ToString @TableName("approval_template_node") @ApiModel(value = "ApprovalTemplateNode对象", description = "å®¡æ¹æ¨¡æ¿èç¹è¡¨") public class ApprovalTemplateNode implements Serializable { private static final long serialVersionUID = 1L; /** * èç¹ID */ @Schema(description ="èç¹ID") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * å®¡æ¹æ¨¡æ¿ID */ @Schema(description ="å®¡æ¹æ¨¡æ¿ID") private Long templateId; /** * 审æ¹çº§å«ï¼ä»1å¼å§ */ @Schema(description ="审æ¹çº§å«ï¼ä»1å¼å§") private Integer levelNo; /** * å®¡æ¹æ¹å¼ï¼ANDä¼ç¾ï¼ORæç¾ */ @Schema(description ="å®¡æ¹æ¹å¼ï¼ANDä¼ç¾ï¼ORæç¾") private String approveType; @TableField(fill = FieldFill.INSERT) private Long createUser; @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; @TableField(fill = FieldFill.UPDATE) private LocalDateTime updateTime; @TableField(fill = FieldFill.INSERT) private Long deptId; } src/main/java/com/ruoyi/approve/pojo/ApprovalTemplateNodeApprover.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,76 @@ package com.ruoyi.approve.pojo; import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import lombok.ToString; import java.io.Serializable; import java.time.LocalDateTime; /** * <p> * å®¡æ¹æ¨¡æ¿èç¹å®¡æ¹äººè¡¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:30 */ @Getter @Setter @ToString @TableName("approval_template_node_approver") @ApiModel(value = "ApprovalTemplateNodeApprover对象", description = "å®¡æ¹æ¨¡æ¿èç¹å®¡æ¹äººè¡¨") public class ApprovalTemplateNodeApprover implements Serializable { private static final long serialVersionUID = 1L; /** * 主é®ID */ @Schema(description = "主é®ID") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 审æ¹èç¹ID */ @Schema(description ="审æ¹èç¹ID") private Long nodeId; /** * å®¡æ¹æ¨¡æ¿ID */ @Schema(description ="å®¡æ¹æ¨¡æ¿ID") private Long templateId; /** * 审æ¹äººID */ @Schema(description ="审æ¹äººID") private Long approverId; /** * 审æ¹äººåç§°åä½ */ @Schema(description ="审æ¹äººåç§°åä½") private String approverName; /** * 审æ¹äººæåº */ @Schema(description ="审æ¹äººæåº") private Integer sortNo; @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; @TableField(fill = FieldFill.INSERT) private Long createUser; @TableField(fill = FieldFill.INSERT) private Long deleted ; @TableField(fill = FieldFill.INSERT) private Long deptId; } src/main/java/com/ruoyi/approve/pojo/FinReimbursement.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,210 @@ package com.ruoyi.approve.pojo; import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import lombok.ToString; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; /** * <p> * æ¥éå主表 * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:15 */ @Getter @Setter @ToString @TableName("fin_reimbursement") @ApiModel(value = "FinReimbursement对象", description = "æ¥éå主表") public class FinReimbursement implements Serializable { private static final long serialVersionUID = 1L; /** * 主é®ID */ @Schema(description = "主é®ID") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * æ¥éåå· */ @Schema(description = "æ¥éåå·") private String billNo; /** * æ¥éç±»åï¼1-å·®æ æ¥éï¼2-è´¹ç¨æ¥é */ @Schema(description = "æ¥éç±»åï¼1-å·®æ æ¥éï¼2-è´¹ç¨æ¥é") private Byte reimbursementType; /** * è´¹ç¨ç±»åï¼å·®æ è´¹/åå ¬éè´/ä¸å¡æå¾ /交éè´¹/é讯费/å ¶ä» */ @Schema(description = "è´¹ç¨ç±»åï¼å·®æ è´¹/åå ¬éè´/ä¸å¡æå¾ /交éè´¹/é讯费/å ¶ä»") private String expenseType; /** * ç³è¯·äººID */ @Schema(description = "ç³è¯·äººID") private Long applicantId; /** * åå·¥ç¼å· */ @Schema(description = "åå·¥ç¼å·") private String applicantCode; /** * åå·¥å§å */ @Schema(description = "åå·¥å§å") private String applicantName; /** * ç³è¯·é¨é¨ID */ @Schema(description = "ç³è¯·é¨é¨ID") private Long applicantDeptId; /** * ç³è¯·é¨é¨åç§° */ @Schema(description = "ç³è¯·é¨é¨åç§°") private String applicantDeptName; /** * æ¥éåå */ @Schema(description = "æ¥éåå ") private String reason; /** * ç³è¯·éé¢ */ @Schema(description = "ç³è¯·éé¢") private BigDecimal applyAmount; /** * æç»æ±æ»éé¢ */ @Schema(description = "æç»æ±æ»éé¢") private BigDecimal detailTotalAmount; /** * æ¶æ¬¾äºº */ @Schema(description = "æ¶æ¬¾äºº") private String payeeName; /** * æ¶æ¬¾è´¦å· */ @Schema(description = "æ¶æ¬¾è´¦å·") private String payeeAccount; /** * 弿·æ¯è¡ */ @Schema(description = "弿·æ¯è¡") private String payeeBank; /** * 审æ¹å®ä¾IDï¼å¯¹åº approval_instance.id */ @Schema(description = "审æ¹å®ä¾IDï¼å¯¹åº approval_instance.id") private Long approvalInstanceId; /** * å®¡æ¹æµç¨IDï¼å¯¹åº approve_process.id */ @Schema(description = "å®¡æ¹æµç¨IDï¼å¯¹åº approve_process.id") private Long approveProcessId; /** * åæ®ç¶æï¼DRAFT-è稿ï¼IN_APPROVAL-审æ¹ä¸ï¼APPROVED-审æ¹éè¿ï¼REJECTED-审æ¹é©³åï¼WITHDRAWN-å·²æ¤åï¼PAID-已仿¬¾ */ @Schema(description = "åæ®ç¶æï¼DRAFT-è稿ï¼IN_APPROVAL-审æ¹ä¸ï¼APPROVED-审æ¹éè¿ï¼REJECTED-审æ¹é©³åï¼WITHDRAWN-å·²æ¤åï¼PAID-已仿¬¾") private String billStatus; /** * 审æ¹éè¿æ¶é´ */ @Schema(description = "审æ¹éè¿æ¶é´") private LocalDateTime approvedTime; /** * 仿¬¾æ¶é´ */ @Schema(description = "仿¬¾æ¶é´") private LocalDateTime paidTime; /** * çæçè´¢å¡æ¯åºè®°å½IDï¼å¯¹åº account_expense.id */ @Schema(description = "çæçè´¢å¡æ¯åºè®°å½IDï¼å¯¹åº account_expense.id") private Long accountExpenseId; /** * 夿³¨ */ @Schema(description = "夿³¨") private String remark; /** * ç§æ·ID */ @Schema(description = "ç§æ·ID") private Long tenantId; /** * å建人 */ @Schema(description = "å建人") @TableField(fill = FieldFill.INSERT) private Long createUser; /** * å建æ¶é´ */ @Schema(description = "å建æ¶é´") @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; /** * æ´æ°äºº */ @Schema(description = "æ´æ°äºº") @TableField(fill = FieldFill.INSERT_UPDATE) private Long updateUser; /** * æ´æ°æ¶é´ */ @Schema(description = "æ´æ°æ¶é´") @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; /** * å½å±é¨é¨ID */ @Schema(description = "å½å±é¨é¨ID") @TableField(fill = FieldFill.INSERT) private Long deptId; /** * é»è¾å é¤ï¼0-å¦ï¼1-æ¯ */ @Schema(description = "é»è¾å é¤ï¼0-å¦ï¼1-æ¯") private Byte deleted; } src/main/java/com/ruoyi/approve/pojo/FinReimbursementDetail.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,157 @@ package com.ruoyi.approve.pojo; import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import lombok.ToString; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; /** * <p> * æ¥éåæç»è¡¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:38 */ @Getter @Setter @ToString @TableName("fin_reimbursement_detail") @ApiModel(value = "FinReimbursementDetail对象", description = "æ¥éåæç»è¡¨") public class FinReimbursementDetail implements Serializable { private static final long serialVersionUID = 1L; /** * 主é®ID */ @Schema(description = "主é®ID") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * æ¥éåIDï¼å¯¹åº fin_reimbursement.id */ @Schema(description = "æ¥éåIDï¼å¯¹åº fin_reimbursement.id") private Long reimbursementId; /** * æç»è¡å· */ @Schema(description = "æç»è¡å·") private Integer rowNo; /** * åç¥¨æ¥æ */ @Schema(description = "åç¥¨æ¥æ") private LocalDate invoiceDate; /** * è´¹ç¨ç§ç® */ @Schema(description = "è´¹ç¨ç§ç®") private String expenseCategory; /** * éé¢ */ @Schema(description = "éé¢") private BigDecimal amount; /** * æè¿° */ @Schema(description = "æè¿°") private String description; /** * å票å·ç */ @Schema(description = "å票å·ç ") private String invoiceNo; /** * å票类å */ @Schema(description = "å票类å") private String invoiceType; /** * 票é¢éé¢ */ @Schema(description = "票é¢éé¢") private BigDecimal invoiceAmount; /** * ç¨ç */ @Schema(description = "ç¨ç") private BigDecimal taxRate; /** * ç¨é¢ */ @Schema(description = "ç¨é¢") private BigDecimal taxAmount; /** * 夿³¨ */ @Schema(description = "夿³¨") private String remark; /** * ç§æ·ID */ @Schema(description = "ç§æ·ID") private Long tenantId; /** * å建人 */ @Schema(description = "å建人") @TableField(fill = FieldFill.INSERT) private Long createUser; /** * å建æ¶é´ */ @Schema(description = "å建æ¶é´") @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; /** * æ´æ°äºº */ @Schema(description = "æ´æ°äºº") @TableField(fill = FieldFill.INSERT_UPDATE) private Long updateUser; /** * æ´æ°æ¶é´ */ @Schema(description = "æ´æ°æ¶é´") @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; /** * å½å±é¨é¨ID */ @Schema(description = "å½å±é¨é¨ID") @TableField(fill = FieldFill.INSERT) private Long deptId; /** * é»è¾å é¤ï¼0-å¦ï¼1-æ¯ */ @Schema(description = "é»è¾å é¤ï¼0-å¦ï¼1-æ¯") private Byte deleted; } src/main/java/com/ruoyi/approve/pojo/FinReimbursementTravel.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,162 @@ package com.ruoyi.approve.pojo; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; /** * <p> * å·®æ æ¥éæ©å±è¡¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:47 */ @Getter @Setter @ToString @TableName("fin_reimbursement_travel") @ApiModel(value = "FinReimbursementTravel对象", description = "å·®æ æ¥éæ©å±è¡¨") public class FinReimbursementTravel implements Serializable { private static final long serialVersionUID = 1L; /** * 主é®ID */ @Schema(description = "主é®ID") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * æ¥éåIDï¼å¯¹åº fin_reimbursement.id */ @Schema(description = "æ¥éåIDï¼å¯¹åº fin_reimbursement.id") private Long reimbursementId; /** * åºå·®å¼å§æ¶é´ */ @Schema(description = "åºå·®å¼å§æ¶é´") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime startTime; /** * åºå·®ç»ææ¶é´ */ @Schema(description = "åºå·®ç»ææ¶é´") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime endTime; /** * åºå·®å¤©æ° */ @Schema(description = "åºå·®å¤©æ°") private BigDecimal travelDays; /** * åºå·®å°/åºååå¸ */ @Schema(description = "åºå·®å°/åºååå¸") private String departureCity; /** * ç®çå°/ç®çåå¸ */ @Schema(description = "ç®çå°/ç®çåå¸") private String destinationCity; /** * é åºæ å */ @Schema(description = "é åºæ å") private BigDecimal hotelStandard; /** * ä½å®¿å¤©æ° */ @Schema(description = "ä½å®¿å¤©æ°") private BigDecimal lodgingDays; /** * çæ´»è¡¥è´´ */ @Schema(description = "çæ´»è¡¥è´´") private BigDecimal mealAllowance; /** * 交é补贴 */ @Schema(description = "交é补贴") private BigDecimal transportAllowance; /** * ä½å®¿éé¢ */ @Schema(description = "ä½å®¿éé¢") private BigDecimal lodgingLimit; /** * ç¹æ¹æ è®°ææ¬ï¼å¦å¨æ åèå´å /è¶ æ ç¹æ¹ */ @Schema(description = "ç¹æ¹æ è®°ææ¬ï¼å¦å¨æ åèå´å /è¶ æ ç¹æ¹") private String standardTag; /** * æ¯å¦å¨æ åå ï¼1-æ¯ï¼0-å¦ */ @Schema(description = "æ¯å¦å¨æ åå ï¼1-æ¯ï¼0-å¦") private Byte withinStandard; /** * ç§æ·ID */ @Schema(description = "ç§æ·ID") private Long tenantId; /** * å建人 */ @Schema(description = "å建人") @TableField(fill = FieldFill.INSERT) private Long createUser; /** * å建æ¶é´ */ @Schema(description = "å建æ¶é´") @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; /** * æ´æ°äºº */ @Schema(description = "æ´æ°äºº") @TableField(fill = FieldFill.INSERT_UPDATE) private Long updateUser; /** * æ´æ°æ¶é´ */ @Schema(description = "æ´æ°æ¶é´") @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; /** * å½å±é¨é¨ID */ @Schema(description = "å½å±é¨é¨ID") @TableField(fill = FieldFill.INSERT) private Long deptId; } src/main/java/com/ruoyi/approve/service/ApprovalInstanceNodeService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ package com.ruoyi.approve.service; import com.ruoyi.approve.pojo.ApprovalInstanceNode; import com.baomidou.mybatisplus.extension.service.IService; /** * <p> * 审æ¹èç¹å®ä¾è¡¨ æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:27:54 */ public interface ApprovalInstanceNodeService extends IService<ApprovalInstanceNode> { } src/main/java/com/ruoyi/approve/service/ApprovalInstanceService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,31 @@ package com.ruoyi.approve.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.approve.bean.dto.ApprovalInstanceDto; import com.ruoyi.approve.bean.vo.ApprovalInstanceVo; import com.ruoyi.approve.pojo.ApprovalInstance; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.framework.web.domain.R; import java.util.List; /** * <p> * 审æ¹å®ä¾è¡¨ æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:27:46 */ public interface ApprovalInstanceService extends IService<ApprovalInstance> { R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto); Boolean add(ApprovalInstanceDto approvalInstanceDto); Boolean update(ApprovalInstanceDto approvalInstanceDto); Boolean delete(List<Long> ids); R approve(ApprovalInstanceDto approvalInstanceDto); } src/main/java/com/ruoyi/approve/service/ApprovalRecordService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ package com.ruoyi.approve.service; import com.ruoyi.approve.pojo.ApprovalRecord; import com.baomidou.mybatisplus.extension.service.IService; /** * <p> * 审æ¹è®°å½è¡¨ æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:28:21 */ public interface ApprovalRecordService extends IService<ApprovalRecord> { } src/main/java/com/ruoyi/approve/service/ApprovalTaskService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ package com.ruoyi.approve.service; import com.ruoyi.approve.pojo.ApprovalTask; import com.baomidou.mybatisplus.extension.service.IService; /** * <p> * 审æ¹ä»»å¡è¡¨ æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:32:37 */ public interface ApprovalTaskService extends IService<ApprovalTask> { } src/main/java/com/ruoyi/approve/service/ApprovalTemplateNodeApproverService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ package com.ruoyi.approve.service; import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover; import com.baomidou.mybatisplus.extension.service.IService; /** * <p> * å®¡æ¹æ¨¡æ¿èç¹å®¡æ¹äººè¡¨ æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:30 */ public interface ApprovalTemplateNodeApproverService extends IService<ApprovalTemplateNodeApprover> { } src/main/java/com/ruoyi/approve/service/ApprovalTemplateNodeService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ package com.ruoyi.approve.service; import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeDto; import com.ruoyi.approve.pojo.ApprovalTemplateNode; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; /** * <p> * å®¡æ¹æ¨¡æ¿èç¹è¡¨ æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:19 */ public interface ApprovalTemplateNodeService extends IService<ApprovalTemplateNode> { Boolean saveApprovalTemplateNode(Long id, List<ApprovalTemplateNodeDto> nodes); } src/main/java/com/ruoyi/approve/service/ApprovalTemplateService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,34 @@ package com.ruoyi.approve.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.approve.bean.dto.ApprovalTemplateDto; import com.ruoyi.approve.bean.vo.ApprovalTemplateVo; import com.ruoyi.approve.pojo.ApprovalTemplate; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; /** * <p> * å®¡æ¹æ¨¡æ¿è¡¨ æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:08 */ public interface ApprovalTemplateService extends IService<ApprovalTemplate> { IPage<ApprovalTemplateVo> listPage(Page<ApprovalTemplateVo> page, ApprovalTemplateDto approvalTemplateDto); Boolean saveApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto); Boolean updateApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto); Boolean delete(List<Long> ids); List<ApprovalTemplateVo> listApprovalTemplateVo(Integer type); ApprovalTemplateVo getApprovalTemplateVoById(Long id); } src/main/java/com/ruoyi/approve/service/FinReimbursementDetailService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ package com.ruoyi.approve.service; import com.ruoyi.approve.pojo.FinReimbursementDetail; import com.baomidou.mybatisplus.extension.service.IService; /** * <p> * æ¥éåæç»è¡¨ æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:38 */ public interface FinReimbursementDetailService extends IService<FinReimbursementDetail> { } src/main/java/com/ruoyi/approve/service/FinReimbursementService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,31 @@ package com.ruoyi.approve.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.approve.bean.dto.FinReimbursementDto; import com.ruoyi.approve.bean.vo.FinReimbursementVo; import com.ruoyi.approve.pojo.FinReimbursement; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; /** * <p> * æ¥éå主表 æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:15 */ public interface FinReimbursementService extends IService<FinReimbursement> { IPage<FinReimbursementVo> listPage(FinReimbursementDto finReimbursementDto, Page<FinReimbursementVo> page); Boolean add(FinReimbursementDto finReimbursementDto); FinReimbursementVo detail(Long id); Boolean update(FinReimbursementDto finReimbursementDto); Boolean delete(List<Long> ids); } src/main/java/com/ruoyi/approve/service/FinReimbursementTravelService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ package com.ruoyi.approve.service; import com.ruoyi.approve.pojo.FinReimbursementTravel; import com.baomidou.mybatisplus.extension.service.IService; /** * <p> * å·®æ æ¥éæ©å±è¡¨ æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:47 */ public interface FinReimbursementTravelService extends IService<FinReimbursementTravel> { } src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceNodeServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ package com.ruoyi.approve.service.impl; import com.ruoyi.approve.pojo.ApprovalInstanceNode; import com.ruoyi.approve.mapper.ApprovalInstanceNodeMapper; import com.ruoyi.approve.service.ApprovalInstanceNodeService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * <p> * 审æ¹èç¹å®ä¾è¡¨ æå¡å®ç°ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:27:54 */ @Service public class ApprovalInstanceNodeServiceImpl extends ServiceImpl<ApprovalInstanceNodeMapper, ApprovalInstanceNode> implements ApprovalInstanceNodeService { } src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,753 @@ package com.ruoyi.approve.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.approve.bean.dto.ApprovalInstanceDto; import com.ruoyi.approve.bean.vo.ApprovalInstanceVo; import com.ruoyi.approve.mapper.ApprovalInstanceMapper; import com.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper; import com.ruoyi.approve.mapper.FinReimbursementMapper; import com.ruoyi.approve.pojo.*; import com.ruoyi.approve.service.*; import com.ruoyi.approve.utils.ApproveProcessConfigNodeUtils; import com.ruoyi.basic.enums.ApplicationTypeEnum; import com.ruoyi.basic.enums.RecordTypeEnum; import com.ruoyi.basic.utils.FileUtil; import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsMapper; import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeDeptMapper; import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeUserMapper; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser; import com.ruoyi.common.enums.*; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.OrderUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.framework.security.LoginUser; import com.ruoyi.framework.web.domain.R; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.project.system.domain.SysDept; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysDeptMapper; import com.ruoyi.project.system.mapper.SysUserDeptMapper; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.project.system.service.ISysNoticeService; import com.ruoyi.purchase.mapper.PurchaseLedgerMapper; import com.ruoyi.purchase.pojo.PurchaseLedger; import com.ruoyi.quality.utils.QualityInspectHelper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.mapper.SalesQuotationMapper; import com.ruoyi.sales.mapper.ShippingInfoMapper; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.pojo.SalesQuotation; import com.ruoyi.sales.pojo.ShippingInfo; import com.ruoyi.staff.mapper.HolidayApplicationMapper; import com.ruoyi.staff.pojo.HolidayApplication; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; /** * <p> * 审æ¹å®ä¾æå¡å®ç°ç±» * </p> * * @since 2026-05-18 03:27:46 */ @Service @RequiredArgsConstructor public class ApprovalInstanceServiceImpl extends ServiceImpl<ApprovalInstanceMapper, ApprovalInstance> implements ApprovalInstanceService { private static final String ENTERPRISE_NEWS_STATUS_PUBLISHED = "PUBLISHED"; private static final String ENTERPRISE_NEWS_STATUS_REJECTED = "REJECTED"; private final ApprovalInstanceMapper approvalInstanceMapper; private final ApproveProcessConfigNodeUtils approveProcessConfigNodeUtils; private final ApprovalInstanceNodeService approvalInstanceNodeService; private final ApprovalTaskService approvalTaskService; private final ApprovalRecordService approvalRecordService; private final ApprovalTemplateNodeService approvalTemplateNodeService; private final FinReimbursementMapper finReimbursementMapper; private final FileUtil fileUtil; private final ISysNoticeService sysNoticeService; private final PurchaseLedgerMapper purchaseLedgerMapper; private final SalesLedgerProductMapper salesLedgerProductMapper; private final StockUtils stockUtils; private final SalesQuotationMapper salesQuotationMapper; private final ShippingInfoMapper shippingInfoMapper; private final QualityInspectHelper qualityInspectHelper; private final EnterpriseNewsScopeUserMapper enterpriseNewsScopeUserMapper; private final SysUserMapper sysUserMapper; private final SysUserDeptMapper sysUserDeptMapper; private final SysDeptMapper sysDeptMapper; private final HolidayApplicationMapper holidayApplicationMapper; private final EnterpriseNewsMapper enterpriseNewsMapper; private final EnterpriseNewsScopeDeptMapper enterpriseNewsScopeDeptMapper; private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper; @Override public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) { IPage<ApprovalInstanceVo> approvalInstanceVoIPage = approvalInstanceMapper.listPage(page, approvalInstanceDto); List<ApprovalInstanceVo> records = approvalInstanceVoIPage.getRecords(); if (records == null || records.isEmpty()) { return R.ok(approvalInstanceVoIPage); } records.forEach(vo -> { vo.setBusinessName(TypeEnums.getLabelByValue(vo.getBusinessType())); }); Long currentUserId = SecurityUtils.getUserId(); List<Long> instanceIds = records.stream() .map(ApprovalInstanceVo::getId) .filter(id -> id != null) .distinct() .collect(Collectors.toList()); if (!instanceIds.isEmpty()) { Map<Long, List<ApprovalRecord>> recordMap = approvalRecordService.list( Wrappers.<ApprovalRecord>lambdaQuery() .in(ApprovalRecord::getInstanceId, instanceIds) .eq(ApprovalRecord::getDeleted, 0) ).stream().collect(Collectors.groupingBy(ApprovalRecord::getInstanceId)); Map<Long, List<ApprovalTask>> taskMap = approvalTaskService.list( Wrappers.<ApprovalTask>lambdaQuery() .in(ApprovalTask::getInstanceId, instanceIds) .eq(ApprovalTask::getDeleted, 0) ).stream().collect(Collectors.groupingBy(ApprovalTask::getInstanceId)); for (ApprovalInstanceVo vo : records) { vo.setIsApprove(approveProcessConfigNodeUtils.isCurrentApprover(vo.getId(), currentUserId)); vo.setRecords(recordMap.getOrDefault(vo.getId(), new ArrayList<>())); vo.setTasks(taskMap.getOrDefault(vo.getId(), new ArrayList<>())); vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.APPROVAL_INSTANCE, vo.getId())); } } return R.ok(approvalInstanceVoIPage); } @Override @Transactional(rollbackFor = Exception.class) public Boolean add(ApprovalInstanceDto approvalInstanceDto) { String instanceNo = OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no"); approvalInstanceDto.setInstanceNo(instanceNo); approvalInstanceDto.setStatus("PENDING"); approvalInstanceDto.setCurrentLevel(1); boolean saved = this.save(approvalInstanceDto); if (!saved) { return false; } approveProcessConfigNodeUtils.createCurrentNodeAndTasks(approvalInstanceDto); fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, approvalInstanceDto.getId(), approvalInstanceDto.getStorageBlobDTOs()); sendApproveNotice(approvalInstanceDto, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId())); return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean update(ApprovalInstanceDto approvalInstanceDto) { if (approvalInstanceDto == null || approvalInstanceDto.getId() == null) { return false; } // 夿æ¯å¦ææ£å¨è¿è¡ç审æ¹ä»»å¡ï¼æåä¸å è®¸ä¿®æ¹ long pendingTaskCount = approvalTaskService.count( Wrappers.<ApprovalTask>lambdaQuery() .eq(ApprovalTask::getInstanceId, approvalInstanceDto.getId()) .eq(ApprovalTask::getTaskStatus, "PENDING") .eq(ApprovalTask::getDeleted, 0) ); if (pendingTaskCount > 0) { throw new ServiceException("该审æ¹åææ£å¨è¿è¡ç审æ¹ä»»å¡ï¼ä¸å 许修æ¹"); } boolean updated = this.updateById(approvalInstanceDto); if (!updated) { return false; } fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, approvalInstanceDto.getId(), approvalInstanceDto.getStorageBlobDTOs()); return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean delete(List<Long> ids) { if (ids == null || ids.isEmpty()) { return false; } fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, ids); int instanceRows = approvalInstanceMapper.update( null, Wrappers.<ApprovalInstance>lambdaUpdate() .in(ApprovalInstance::getId, ids) .eq(ApprovalInstance::getDeleted, 0) .set(ApprovalInstance::getDeleted, (byte) 1) ); LambdaUpdateWrapper<ApprovalInstanceNode> nodeUpdateWrapper = Wrappers.lambdaUpdate(); nodeUpdateWrapper.in(ApprovalInstanceNode::getInstanceId, ids) .eq(ApprovalInstanceNode::getDeleted, 0) .set(ApprovalInstanceNode::getDeleted, (byte) 1); approvalInstanceNodeService.update(nodeUpdateWrapper); LambdaUpdateWrapper<ApprovalTask> taskUpdateWrapper = Wrappers.lambdaUpdate(); taskUpdateWrapper.in(ApprovalTask::getInstanceId, ids) .eq(ApprovalTask::getDeleted, 0) .set(ApprovalTask::getDeleted, (byte) 1); approvalTaskService.update(taskUpdateWrapper); LambdaUpdateWrapper<ApprovalRecord> recordUpdateWrapper = Wrappers.lambdaUpdate(); recordUpdateWrapper.in(ApprovalRecord::getInstanceId, ids) .eq(ApprovalRecord::getDeleted, 0) .set(ApprovalRecord::getDeleted, (byte) 1); approvalRecordService.update(recordUpdateWrapper); return instanceRows > 0; } @Override @Transactional(rollbackFor = Exception.class) public R approve(ApprovalInstanceDto approvalInstanceDto) { if (approvalInstanceDto == null || approvalInstanceDto.getId() == null) { return R.fail("审æ¹å®ä¾ ID ä¸è½ä¸ºç©º"); } String approveAction = normalizeApproveAction(approvalInstanceDto.getApproveAction()); if (approveAction == null) { return R.fail("审æ¹å¨ä½åªæ¯æ APPROVED æ REJECTED"); } ApprovalInstance instance = getPendingApprovalInstance(approvalInstanceDto.getId()); if (instance == null) { return R.fail("审æ¹å®ä¾ä¸åå¨"); } ApprovalInstanceNode currentNode = approveProcessConfigNodeUtils.getCurrentNode(instance.getId()); if (currentNode == null) { return R.fail("å½å没æå¾ å¤çç审æ¹èç¹"); } Long currentUserId = SecurityUtils.getUserId(); ApprovalTask currentTask = approveProcessConfigNodeUtils.getCurrentUserTask(instance.getId(), currentUserId); if (currentTask == null) { return R.fail("å½åç¨æ·æ²¡æå¯å®¡æ¹ä»»å¡"); } LoginUser loginUser = SecurityUtils.getLoginUser(); String operatorName = loginUser.getUser() != null ? loginUser.getUser().getNickName() : SecurityUtils.getUsername(); LocalDateTime now = LocalDateTime.now(); if (!updateCurrentTask(approvalInstanceDto, approveAction, currentTask, now)) { return R.fail("å½åä»»å¡å·²è¢«å¤çï¼è¯·å·æ°åéè¯"); } saveApprovalRecord( instance.getId(), currentNode.getId(), currentTask.getId(), currentUserId, operatorName, approveAction, approvalInstanceDto.getApproveComment() ); //å®¡æ¹æç»çå¤ç if ("REJECTED".equals(approveAction)) { return rejectCurrentNode(instance, currentNode, now); } if (!approveProcessConfigNodeUtils.canProceedToNextLevel(instance.getId(), currentNode.getApproveType())) { return R.ok("å®¡æ¹æåï¼çå¾ å ¶ä»å®¡æ¹äººå¤ç"); } return approveAndMoveNext(instance, currentNode, approvalInstanceDto, now); } private String normalizeApproveAction(String approveAction) { if (!StringUtils.hasText(approveAction)) { return null; } String normalizedAction = approveAction.trim().toUpperCase(Locale.ROOT); return "APPROVED".equals(normalizedAction) || "REJECTED".equals(normalizedAction) ? normalizedAction : null; } private ApprovalInstance getPendingApprovalInstance(Long instanceId) { return this.getOne( new LambdaQueryWrapper<ApprovalInstance>() .eq(ApprovalInstance::getId, instanceId) .eq(ApprovalInstance::getDeleted, 0) .last("LIMIT 1") ); } private boolean updateCurrentTask(ApprovalInstanceDto approvalInstanceDto, String approveAction, ApprovalTask currentTask, LocalDateTime now) { // ä» å è®¸å¾ å®¡æ¹ä»»å¡è¢«æåå¤ç䏿¬¡ï¼é¿å å¹¶åä¸éå¤å®¡æ¹æåã return approvalTaskService.update( Wrappers.<ApprovalTask>lambdaUpdate() .eq(ApprovalTask::getId, currentTask.getId()) .eq(ApprovalTask::getTaskStatus, "PENDING") .eq(ApprovalTask::getDeleted, 0) .set(ApprovalTask::getTaskStatus, approveAction) .set(ApprovalTask::getComment, approvalInstanceDto.getApproveComment()) .set(ApprovalTask::getApproveTime, now) .set(ApprovalTask::getIsRead, (byte) 1) ); } private R rejectCurrentNode(ApprovalInstance instance, ApprovalInstanceNode currentNode, LocalDateTime now) { if (!updateCurrentNodeStatus(currentNode.getId(), "REJECTED", now)) { return R.ok("å½åèç¹å·²å¤ç宿"); } closePendingTasks(instance.getId(), currentNode.getId()); instance.setStatus("REJECTED"); instance.setFinishTime(now); this.updateById(instance); // 驳å对åºçä¼ä¸æ°é»ï¼ å·®æ æ¥é if (instance.getBusinessType().equals(TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode())) { enterpriseNewsMapper.update( new LambdaUpdateWrapper<EnterpriseNews>() .eq(EnterpriseNews::getId, instance.getBusinessId()) .set(EnterpriseNews::getStatus, "REJECTED") ); }else if (instance.getBusinessType().equals(TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode())||instance.getBusinessType().equals(TypeEnums.EXPENSE_APPROVAL.getCode())) { finReimbursementMapper.update( new LambdaUpdateWrapper<FinReimbursement>() .eq(FinReimbursement::getId, instance.getBusinessId()) .set(FinReimbursement::getBillStatus, "REJECTED") ); } return R.ok("审æ¹å·²é©³å"); } private R approveAndMoveNext(ApprovalInstance instance, ApprovalInstanceNode currentNode, ApprovalInstanceDto approvalInstanceDto, LocalDateTime now) { if (!updateCurrentNodeStatus(currentNode.getId(), "APPROVED", now)) { return R.ok("å½åèç¹å·²å¤ç宿"); } closePendingTasks(instance.getId(), currentNode.getId()); int nextLevel = currentNode.getLevelNo() + 1; ApprovalInstanceNode nextInstanceNode = approvalInstanceNodeService.getOne( new LambdaQueryWrapper<ApprovalInstanceNode>() .eq(ApprovalInstanceNode::getInstanceId, instance.getId()) .eq(ApprovalInstanceNode::getLevelNo, nextLevel) .eq(ApprovalInstanceNode::getDeleted, 0) .orderByAsc(ApprovalInstanceNode::getId) .last("LIMIT 1") ); if (nextInstanceNode != null) { if (!activateNextInstanceNode(nextInstanceNode.getId(), now)) { return R.ok("ä¸ä¸å®¡æ¹èç¹å·²è¢«æ¿æ´»ï¼è¯·å·æ°åéè¯"); } instance.setCurrentLevel(nextLevel); instance.setStatus("PENDING"); this.updateById(instance); List<ApprovalTask> nextTasks = approvalTaskService.list( Wrappers.<ApprovalTask>lambdaQuery() .eq(ApprovalTask::getInstanceId, instance.getId()) .eq(ApprovalTask::getNodeId, nextInstanceNode.getId()) .eq(ApprovalTask::getTaskStatus, "PENDING") .eq(ApprovalTask::getDeleted, 0) ); sendApproveNotice(instance, nextTasks); return R.ok("å®¡æ¹æåï¼å·²æµè½¬å°ä¸ä¸èç¹"); } ApprovalTemplateNode nextTemplateNode = approvalTemplateNodeService.getOne( new LambdaQueryWrapper<ApprovalTemplateNode>() .eq(ApprovalTemplateNode::getTemplateId, instance.getTemplateId()) .eq(ApprovalTemplateNode::getLevelNo, nextLevel) .orderByAsc(ApprovalTemplateNode::getId) .last("LIMIT 1") ); if (nextTemplateNode == null) { instance.setStatus("APPROVED"); instance.setFinishTime(now); this.updateById(instance); handleBusinessAfterApprovalFinished(instance); return R.ok("审æ¹å·²å®æ"); } instance.setCurrentLevel(nextLevel); instance.setStatus("PENDING"); this.updateById(instance); approveProcessConfigNodeUtils.createCurrentNodeAndTasks(instance, false); sendApproveNotice(instance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId())); return R.ok("å®¡æ¹æåï¼å·²æµè½¬å°ä¸ä¸èç¹"); } private boolean activateNextInstanceNode(Long nodeId, LocalDateTime now) { return approvalInstanceNodeService.update( Wrappers.<ApprovalInstanceNode>lambdaUpdate() .eq(ApprovalInstanceNode::getId, nodeId) .eq(ApprovalInstanceNode::getStatus, "WAITING") .eq(ApprovalInstanceNode::getDeleted, 0) .set(ApprovalInstanceNode::getStatus, "PENDING") .set(ApprovalInstanceNode::getStartTime, now) ); } private boolean updateCurrentNodeStatus(Long nodeId, String targetStatus, LocalDateTime now) { // ä» å 许ä¸ä¸ªè¯·æ±å°å½åèç¹ä»å¾ å¤çæ¨è¿å°ç®æ ç¶æï¼é¿å é夿µè½¬ã return approvalInstanceNodeService.update( Wrappers.<ApprovalInstanceNode>lambdaUpdate() .eq(ApprovalInstanceNode::getId, nodeId) .eq(ApprovalInstanceNode::getStatus, "PENDING") .eq(ApprovalInstanceNode::getDeleted, 0) .set(ApprovalInstanceNode::getStatus, targetStatus) .set(ApprovalInstanceNode::getFinishTime, now) ); } private void handleBusinessAfterApprovalFinished(ApprovalInstance instance) { String status = instance.getStatus(); Long businessType = instance.getBusinessType(); if (TypeEnums.PURCHASE_APPROVAL.getCode().equals(businessType)) { handlePurchaseApprovalFinished(instance, status); return; } if (TypeEnums.QUOTATION_APPROVAL.getCode().equals(businessType)) { handleSalesQuotationApprovalFinished(instance, status); return; } if (TypeEnums.SHIPPING_APPROVAL.getCode().equals(businessType)) { handleShippingApprovalFinished(instance, status); return; } if (TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode().equals(businessType) || TypeEnums.EXPENSE_APPROVAL.getCode().equals(businessType)) { handleReimbursementApprovalFinished(instance, status); return; } // 驳å对åºçä¼ä¸æ°é»ãå çç³è¯·ã请åç³è¯·å¯ä»¥éæ°åæäº¤ if (TypeEnums.LEAVE_APPROVAL.getCode().equals(businessType) || TypeEnums.OVERTIME_APPROVAL.getCode().equals(businessType)) { handleHolidayApplicationApprovalFinished(instance, status); return; } if (TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode().equals(businessType)) { handleNewsApprovalFinished(instance, status); } } private void handleReimbursementApprovalFinished(ApprovalInstance instance, String status) { if (instance == null || instance.getBusinessId() == null) { return; } FinReimbursement reimbursement = new FinReimbursement(); reimbursement.setId(instance.getBusinessId()); if ("APPROVED".equals(status)) { reimbursement.setBillStatus("APPROVED"); reimbursement.setApprovedTime(instance.getFinishTime()); } else if ("REJECTED".equals(status)) { reimbursement.setBillStatus("REJECTED"); } else if ("PENDING".equals(status)) { reimbursement.setBillStatus("IN_APPROVAL"); } else { return; } finReimbursementMapper.updateById(reimbursement); } private void handleNewsApprovalFinished(ApprovalInstance instance, String status) { if (instance == null || instance.getBusinessId() == null) { return; } EnterpriseNews enterpriseNews = new EnterpriseNews(); enterpriseNews.setId(instance.getBusinessId()); if ("APPROVED".equals(status)) { enterpriseNews.setStatus(ENTERPRISE_NEWS_STATUS_PUBLISHED); enterpriseNewsMapper.updateById(enterpriseNews); sendEnterpriseNewsNotice(instance.getBusinessId()); return; } if ("REJECTED".equals(status)) { enterpriseNews.setStatus(ENTERPRISE_NEWS_STATUS_REJECTED); enterpriseNewsMapper.updateById(enterpriseNews); } } private void handleHolidayApplicationApprovalFinished(ApprovalInstance instance, String status) { if (instance == null || instance.getBusinessId() == null) { return; } HolidayApplication holidayApplication = new HolidayApplication(); holidayApplication.setId(instance.getBusinessId()); if ("APPROVED".equals(status)) { holidayApplication.setStatus("APPROVED"); } else if ("REJECTED".equals(status)) { holidayApplication.setStatus("REJECTED"); } else if ("PENDING".equals(status)) { holidayApplication.setStatus("PENDING"); } else { return; } holidayApplicationMapper.updateById(holidayApplication); } private void handlePurchaseApprovalFinished(ApprovalInstance instance, String status) { PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne( new LambdaQueryWrapper<PurchaseLedger>() .eq(PurchaseLedger::getPurchaseContractNumber, instance.getTitle()) .last("limit 1") ); if (purchaseLedger == null) { return; } if ("APPROVED".equals(status)) { purchaseLedger.setApprovalStatus(ApprovalStatusEnum.APPROVED.getCode()); List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList( new QueryWrapper<SalesLedgerProduct>().lambda() .eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()) .eq(SalesLedgerProduct::getType, 2) ); for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) { if (salesLedgerProduct.getIsChecked()) { qualityInspectHelper.addQualityInspect(purchaseLedger, salesLedgerProduct); } else { stockUtils.addStockWithBatchNo( salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId(), purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId() ); } } } else if ("REJECTED".equals(status)) { purchaseLedger.setApprovalStatus(ApprovalStatusEnum.REJECTED.getCode()); } else if ("PENDING".equals(status)) { purchaseLedger.setApprovalStatus(ApprovalStatusEnum.IN_PROGRESS.getCode()); } purchaseLedgerMapper.updateById(purchaseLedger); } private void handleSalesQuotationApprovalFinished(ApprovalInstance instance, String status) { SalesQuotation salesQuote = salesQuotationMapper.selectOne( new LambdaQueryWrapper<SalesQuotation>() .eq(SalesQuotation::getQuotationNo, instance.getTitle()) .last("limit 1") ); if (salesQuote == null) { return; } if ("APPROVED".equals(status)) { salesQuote.setStatus(SalesQuotationStatusEnum.APPROVED.getCode()); } else if ("REJECTED".equals(status)) { salesQuote.setStatus(SalesQuotationStatusEnum.REJECTED.getCode()); } else if ("PENDING".equals(status)) { salesQuote.setStatus(SalesQuotationStatusEnum.IN_PROGRESS.getCode()); } salesQuotationMapper.updateById(salesQuote); } private void handleShippingApprovalFinished(ApprovalInstance instance, String status) { ShippingInfo shippingInfo = shippingInfoMapper.selectOne( new LambdaQueryWrapper<ShippingInfo>() .eq(ShippingInfo::getShippingNo, instance.getTitle()) .orderByDesc(ShippingInfo::getCreateTime) .last("limit 1") ); if (shippingInfo == null) { return; } if ("APPROVED".equals(status)) { shippingInfo.setStatus(ShippingStatusEnum.APPROVED.getCode()); shippingInfo.setShippingDate(new Date()); stockUtils.shipmentStatus(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), shippingInfo.getId()); } else if ("REJECTED".equals(status)) { stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode()); shippingInfo.setStatus(ShippingStatusEnum.REJECTED.getCode()); } else if ("PENDING".equals(status)) { shippingInfo.setStatus(ShippingStatusEnum.IN_PROGRESS.getCode()); } shippingInfoMapper.updateById(shippingInfo); } private List<ApprovalTask> createNodeAndTasks(ApprovalInstance instance, ApprovalTemplateNode templateNode) { List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverMapper.selectList( new LambdaQueryWrapper<ApprovalTemplateNodeApprover>() .eq(ApprovalTemplateNodeApprover::getTemplateId, instance.getTemplateId()) .eq(ApprovalTemplateNodeApprover::getNodeId, templateNode.getId()) .eq(ApprovalTemplateNodeApprover::getDeleted, 0L) .orderByAsc(ApprovalTemplateNodeApprover::getSortNo) ); if (approvers == null || approvers.isEmpty()) { throw new RuntimeException("ä¸ä¸å®¡æ¹èç¹æªé 置审æ¹äºº"); } ApprovalInstanceNode instanceNode = new ApprovalInstanceNode(); instanceNode.setInstanceId(instance.getId()); instanceNode.setLevelNo(templateNode.getLevelNo()); instanceNode.setApproveType(templateNode.getApproveType()); instanceNode.setStatus("PENDING"); instanceNode.setStartTime(LocalDateTime.now()); instanceNode.setDeleted((byte) 0); approvalInstanceNodeService.save(instanceNode); List<ApprovalTask> taskList = new ArrayList<>(approvers.size()); for (ApprovalTemplateNodeApprover approver : approvers) { ApprovalTask task = new ApprovalTask(); task.setInstanceId(instance.getId()); task.setNodeId(instanceNode.getId()); task.setLevelNo(instanceNode.getLevelNo()); task.setApproverId(approver.getApproverId()); task.setApproverName(approver.getApproverName()); task.setTaskStatus("PENDING"); task.setIsRead((byte) 0); task.setDeleted((byte) 0); taskList.add(task); } approvalTaskService.saveBatch(taskList); return taskList; } private void sendApproveNotice(ApprovalInstance instance, List<ApprovalTask> tasks) { if (instance == null || tasks == null || tasks.isEmpty()) { return; } List<Long> approverIds = tasks.stream() .map(ApprovalTask::getApproverId) .filter(id -> id != null && id > 0) .distinct() .collect(Collectors.toList()); if (approverIds.isEmpty()) { return; } String title = StringUtils.hasText(instance.getTemplateName()) ? instance.getTemplateName() : "å®¡æ¹æé"; String message = "审æ¹åå· " + instance.getInstanceNo() + " éè¦æ¨å®¡æ¹"; String jumpPath = "/officeProcessAutomation/ApproveManage/approve-list?id=" + instance.getId(); sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath); } private void sendEnterpriseNewsNotice(Long newsId) { EnterpriseNews enterpriseNews = enterpriseNewsMapper.selectById(newsId); if (enterpriseNews == null) { return; } List<Long> userIds = getEnterpriseNewsNoticeUserIds(enterpriseNews); if (userIds == null || userIds.isEmpty()) { return; } String title = "ä¼ä¸æ°é»"; String message = "æ¨ææ°çä¼ä¸æ°é»ã" + enterpriseNews.getTitle() + "ãè¯·åæ¶æ¥é "; String jumpPath = "/officeProcessAutomation/EnterpriseNews?id=" + newsId; sysNoticeService.simpleNoticeByUser(title, message, userIds, jumpPath); } private List<Long> getEnterpriseNewsNoticeUserIds(EnterpriseNews enterpriseNews) { if (enterpriseNews == null || !org.springframework.util.StringUtils.hasText(enterpriseNews.getReadScope())) { return Collections.emptyList(); } String readScope = enterpriseNews.getReadScope().trim(); if ("all".equals(readScope)) { return sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>() .select(SysUser::getUserId) .eq(SysUser::getDelFlag, "0")) .stream() .map(SysUser::getUserId) .filter(id -> id != null && id > 0) .distinct() .collect(Collectors.toList()); } if ("dept".equals(readScope)) { List<Long> deptIds = enterpriseNewsScopeDeptMapper.selectList( new LambdaQueryWrapper<EnterpriseNewsScopeDept>() .eq(EnterpriseNewsScopeDept::getNewsId, enterpriseNews.getId())) .stream() .map(EnterpriseNewsScopeDept::getDeptId) .filter(id -> id != null && id > 0) .distinct() .collect(Collectors.toList()); if (deptIds.isEmpty()) { return Collections.emptyList(); } return sysUserDeptMapper.selectDistinctUserIdsByDeptIds(collectDeptIdsWithChildren(deptIds)); } if ("custom".equals(readScope)) { return enterpriseNewsScopeUserMapper.selectList( new LambdaQueryWrapper<EnterpriseNewsScopeUser>() .eq(EnterpriseNewsScopeUser::getNewsId, enterpriseNews.getId())) .stream() .map(EnterpriseNewsScopeUser::getUserId) .filter(id -> id != null && id > 0) .distinct() .collect(Collectors.toList()); } return Collections.emptyList(); } private List<Long> collectDeptIdsWithChildren(List<Long> deptIds) { Set<Long> allDeptIds = new LinkedHashSet<>(); for (Long deptId : deptIds) { if (deptId == null) { continue; } allDeptIds.add(deptId); List<SysDept> children = sysDeptMapper.selectChildrenDeptById(deptId); if (children != null && !children.isEmpty()) { for (SysDept child : children) { if (child != null && child.getDeptId() != null) { allDeptIds.add(child.getDeptId()); } } } } return new ArrayList<>(allDeptIds); } private void closePendingTasks(Long instanceId, Long nodeId) { LambdaUpdateWrapper<ApprovalTask> updateWrapper = Wrappers.lambdaUpdate(); updateWrapper.eq(ApprovalTask::getInstanceId, instanceId) .eq(ApprovalTask::getNodeId, nodeId) .eq(ApprovalTask::getTaskStatus, "PENDING") .eq(ApprovalTask::getDeleted, 0) .set(ApprovalTask::getDeleted, (byte) 1); approvalTaskService.update(updateWrapper); } private void saveApprovalRecord(Long instanceId, Long nodeId, Long taskId, Long operatorId, String operatorName, String action, String comment) { ApprovalRecord record = new ApprovalRecord(); record.setInstanceId(instanceId); record.setNodeId(nodeId); record.setTaskId(taskId); record.setOperatorId(operatorId); record.setOperatorName(operatorName); record.setAction(action); record.setComment(comment); record.setDeleted((byte) 0); approvalRecordService.save(record); } } src/main/java/com/ruoyi/approve/service/impl/ApprovalRecordServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ package com.ruoyi.approve.service.impl; import com.ruoyi.approve.pojo.ApprovalRecord; import com.ruoyi.approve.mapper.ApprovalRecordMapper; import com.ruoyi.approve.service.ApprovalRecordService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * <p> * 审æ¹è®°å½è¡¨ æå¡å®ç°ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:28:21 */ @Service public class ApprovalRecordServiceImpl extends ServiceImpl<ApprovalRecordMapper, ApprovalRecord> implements ApprovalRecordService { } src/main/java/com/ruoyi/approve/service/impl/ApprovalTaskServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ package com.ruoyi.approve.service.impl; import com.ruoyi.approve.pojo.ApprovalTask; import com.ruoyi.approve.mapper.ApprovalTaskMapper; import com.ruoyi.approve.service.ApprovalTaskService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * <p> * 审æ¹ä»»å¡è¡¨ æå¡å®ç°ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 03:32:37 */ @Service public class ApprovalTaskServiceImpl extends ServiceImpl<ApprovalTaskMapper, ApprovalTask> implements ApprovalTaskService { } src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateNodeApproverServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ package com.ruoyi.approve.service.impl; import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover; import com.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper; import com.ruoyi.approve.service.ApprovalTemplateNodeApproverService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * <p> * å®¡æ¹æ¨¡æ¿èç¹å®¡æ¹äººè¡¨ æå¡å®ç°ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:30 */ @Service public class ApprovalTemplateNodeApproverServiceImpl extends ServiceImpl<ApprovalTemplateNodeApproverMapper, ApprovalTemplateNodeApprover> implements ApprovalTemplateNodeApproverService { } src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateNodeServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,62 @@ package com.ruoyi.approve.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeApproverDto; import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeDto; import com.ruoyi.approve.mapper.ApprovalTemplateNodeMapper; import com.ruoyi.approve.pojo.ApprovalTemplateNode; import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover; import com.ruoyi.approve.service.ApprovalTemplateNodeApproverService; import com.ruoyi.approve.service.ApprovalTemplateNodeService; import lombok.RequiredArgsConstructor; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; /** * <p> * å®¡æ¹æ¨¡æ¿èç¹è¡¨ æå¡å®ç°ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-18 11:20:19 */ @Service @RequiredArgsConstructor public class ApprovalTemplateNodeServiceImpl extends ServiceImpl<ApprovalTemplateNodeMapper, ApprovalTemplateNode> implements ApprovalTemplateNodeService { private final ApprovalTemplateNodeMapper approvalTemplateNodeMapper; private final ApprovalTemplateNodeApproverService approvalTemplateNodeApproverService; @Override public Boolean saveApprovalTemplateNode(Long templateId, List<ApprovalTemplateNodeDto> nodes) { if (nodes == null || nodes.isEmpty()) { throw new RuntimeException("èç¹å表ä¸è½ä¸ºç©º"); } List<ApprovalTemplateNodeApprover> approverList = new ArrayList<>(); for (ApprovalTemplateNodeDto nodeDto : nodes) { ApprovalTemplateNode node = new ApprovalTemplateNode(); BeanUtils.copyProperties(nodeDto, node); node.setTemplateId(templateId); approvalTemplateNodeMapper.insert(node); List<ApprovalTemplateNodeApproverDto> approvers = nodeDto.getApprovers(); if (approvers == null || approvers.isEmpty()) { throw new RuntimeException("èç¹å®¡æ¹äººä¸è½ä¸ºç©º"); } for (ApprovalTemplateNodeApproverDto approverDto : approvers) { ApprovalTemplateNodeApprover approver = new ApprovalTemplateNodeApprover(); BeanUtils.copyProperties(approverDto, approver); approver.setNodeId(node.getId()); approver.setTemplateId(templateId); approver.setDeleted(0L); approverList.add(approver); } } approvalTemplateNodeApproverService.saveBatch(approverList); return true; } } src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,250 @@ package com.ruoyi.approve.service.impl; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.approve.bean.dto.ApprovalTemplateDto; import com.ruoyi.approve.bean.vo.ApprovalTemplateNodeApproverVo; import com.ruoyi.approve.bean.vo.ApprovalTemplateNodeVo; import com.ruoyi.approve.bean.vo.ApprovalTemplateVo; import com.ruoyi.approve.mapper.ApprovalTemplateMapper; import com.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper; import com.ruoyi.approve.pojo.ApprovalTemplate; import com.ruoyi.approve.pojo.ApprovalTemplateNode; import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover; import com.ruoyi.approve.service.ApprovalTemplateNodeService; import com.ruoyi.approve.service.ApprovalTemplateService; import lombok.RequiredArgsConstructor; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * <p> * å®¡æ¹æ¨¡æ¿æå¡å®ç°ç±» * </p> * * @since 2026-05-18 11:20:08 */ @Service @RequiredArgsConstructor public class ApprovalTemplateServiceImpl extends ServiceImpl<ApprovalTemplateMapper, ApprovalTemplate> implements ApprovalTemplateService { private final ApprovalTemplateMapper approvalTemplateMapper; private final ApprovalTemplateNodeService approvalTemplateNodeService; private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper; @Override public IPage<ApprovalTemplateVo> listPage(Page<ApprovalTemplateVo> page, ApprovalTemplateDto approvalTemplateDto) { IPage<ApprovalTemplateVo> approvalTemplateVoIPage = approvalTemplateMapper.listPage(page, approvalTemplateDto); fillTemplateVoNodes(approvalTemplateVoIPage.getRecords()); return approvalTemplateVoIPage; } @Override @Transactional(rollbackFor = Exception.class) public Boolean saveApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto) { approvalTemplateMapper.insert(approvalTemplateDto); approvalTemplateNodeService.remove( new LambdaQueryWrapper<ApprovalTemplateNode>() .eq(ApprovalTemplateNode::getTemplateId, approvalTemplateDto.getId()) ); approvalTemplateNodeApproverMapper.delete( new LambdaQueryWrapper<ApprovalTemplateNodeApprover>() .eq(ApprovalTemplateNodeApprover::getTemplateId, approvalTemplateDto.getId()) ); return approvalTemplateNodeService.saveApprovalTemplateNode( approvalTemplateDto.getId(), approvalTemplateDto.getNodes() ); } @Override public Boolean updateApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto) { approvalTemplateMapper.updateById(approvalTemplateDto); approvalTemplateNodeService.remove( new LambdaQueryWrapper<ApprovalTemplateNode>() .eq(ApprovalTemplateNode::getTemplateId, approvalTemplateDto.getId()) ); approvalTemplateNodeApproverMapper.delete( new LambdaQueryWrapper<ApprovalTemplateNodeApprover>() .eq(ApprovalTemplateNodeApprover::getTemplateId, approvalTemplateDto.getId()) ); return approvalTemplateNodeService.saveApprovalTemplateNode( approvalTemplateDto.getId(), approvalTemplateDto.getNodes() ); } @Transactional(rollbackFor = Exception.class) public Boolean delete(List<Long> ids) { if (ids == null || ids.isEmpty()) { return false; } ApprovalTemplate updateEntity = new ApprovalTemplate(); updateEntity.setDeleted(1); LambdaUpdateWrapper<ApprovalTemplate> updateWrapper = Wrappers.lambdaUpdate(); updateWrapper.in(ApprovalTemplate::getId, ids) .eq(ApprovalTemplate::getDeleted, 0); int rows = approvalTemplateMapper.update(updateEntity, updateWrapper); return rows == ids.size(); } @Override public List<ApprovalTemplateVo> listApprovalTemplateVo(Integer type) { List<ApprovalTemplate> templateList = this.list( new LambdaQueryWrapper<ApprovalTemplate>() .eq(ApprovalTemplate::getDeleted, 0) .eq(ApprovalTemplate::getEnabled, 1) .orderByDesc(ApprovalTemplate::getTemplateType) .orderByDesc(ApprovalTemplate::getId) ); if (CollUtil.isEmpty(templateList)) { return Collections.emptyList(); } List<ApprovalTemplateVo> templateVos = templateList.stream() .map(template -> { ApprovalTemplateVo templateVo = new ApprovalTemplateVo(); BeanUtils.copyProperties(template, templateVo); return templateVo; }) .collect(Collectors.toList()); fillTemplateVoNodes(templateVos); return templateVos; } @Override public ApprovalTemplateVo getApprovalTemplateVoById(Long id) { if (id == null) { throw new IllegalArgumentException("åæ° id ä¸è½ä¸ºç©º"); } ApprovalTemplate template = this.getOne( new LambdaQueryWrapper<ApprovalTemplate>() .eq(ApprovalTemplate::getId, id) .eq(ApprovalTemplate::getDeleted, 0) ); if (template == null) { throw new IllegalArgumentException("模æ¿ä¸åå¨"); } List<ApprovalTemplateNode> nodeList = approvalTemplateNodeService.list( new LambdaQueryWrapper<ApprovalTemplateNode>() .eq(ApprovalTemplateNode::getTemplateId, id) .orderByAsc(ApprovalTemplateNode::getLevelNo) ); List<ApprovalTemplateNodeApprover> approverList = approvalTemplateNodeApproverMapper.selectList( new LambdaQueryWrapper<ApprovalTemplateNodeApprover>() .eq(ApprovalTemplateNodeApprover::getTemplateId, id) .eq(ApprovalTemplateNodeApprover::getDeleted, 0L) ); Map<Long, List<ApprovalTemplateNode>> nodeMap = nodeList.stream() .collect(Collectors.groupingBy(ApprovalTemplateNode::getTemplateId)); Map<Long, List<ApprovalTemplateNodeApprover>> approverMap = approverList.stream() .collect(Collectors.groupingBy(ApprovalTemplateNodeApprover::getNodeId)); return buildTemplateVo(template, nodeMap, approverMap); } /** * æ¹éå¡«å æ¨¡æ¿èç¹åèç¹å®¡æ¹äººï¼é¿å å¾ªç¯æ¥åºã */ private void fillTemplateVoNodes(List<ApprovalTemplateVo> templateVos) { if (CollUtil.isEmpty(templateVos)) { return; } List<Long> templateIds = templateVos.stream() .map(ApprovalTemplateVo::getId) .collect(Collectors.toList()); List<ApprovalTemplateNode> nodeList = approvalTemplateNodeService.list( new LambdaQueryWrapper<ApprovalTemplateNode>() .in(ApprovalTemplateNode::getTemplateId, templateIds) .orderByAsc(ApprovalTemplateNode::getLevelNo) ); List<ApprovalTemplateNodeApprover> approverList = approvalTemplateNodeApproverMapper.selectList( new LambdaQueryWrapper<ApprovalTemplateNodeApprover>() .in(ApprovalTemplateNodeApprover::getTemplateId, templateIds) .eq(ApprovalTemplateNodeApprover::getDeleted, 0L) ); Map<Long, List<ApprovalTemplateNode>> nodeMap = nodeList.stream() .collect(Collectors.groupingBy(ApprovalTemplateNode::getTemplateId)); Map<Long, List<ApprovalTemplateNodeApprover>> approverMap = approverList.stream() .collect(Collectors.groupingBy(ApprovalTemplateNodeApprover::getNodeId)); templateVos.forEach(templateVo -> templateVo.setNodes( nodeMap.getOrDefault(templateVo.getId(), Collections.emptyList()) .stream() .sorted(Comparator.comparing( ApprovalTemplateNode::getLevelNo, Comparator.nullsLast(Integer::compareTo) )) .map(node -> buildNodeVo(node, approverMap)) .collect(Collectors.toList()) )); } private ApprovalTemplateVo buildTemplateVo(ApprovalTemplate template, Map<Long, List<ApprovalTemplateNode>> nodeMap, Map<Long, List<ApprovalTemplateNodeApprover>> approverMap) { ApprovalTemplateVo templateVo = new ApprovalTemplateVo(); BeanUtils.copyProperties(template, templateVo); List<ApprovalTemplateNodeVo> nodeVos = nodeMap .getOrDefault(template.getId(), Collections.emptyList()) .stream() .sorted(Comparator.comparing( ApprovalTemplateNode::getLevelNo, Comparator.nullsLast(Integer::compareTo) )) .map(node -> buildNodeVo(node, approverMap)) .collect(Collectors.toList()); templateVo.setNodes(nodeVos); return templateVo; } private ApprovalTemplateNodeVo buildNodeVo(ApprovalTemplateNode node, Map<Long, List<ApprovalTemplateNodeApprover>> approverMap) { ApprovalTemplateNodeVo nodeVo = new ApprovalTemplateNodeVo(); BeanUtils.copyProperties(node, nodeVo); List<ApprovalTemplateNodeApproverVo> approverVos = approverMap .getOrDefault(node.getId(), Collections.emptyList()) .stream() .sorted(Comparator.comparing( ApprovalTemplateNodeApprover::getSortNo, Comparator.nullsLast(Integer::compareTo) )) .map(this::buildApproverVo) .collect(Collectors.toList()); nodeVo.setApprovers(approverVos); return nodeVo; } private ApprovalTemplateNodeApproverVo buildApproverVo(ApprovalTemplateNodeApprover approver) { ApprovalTemplateNodeApproverVo approverVo = new ApprovalTemplateNodeApproverVo(); BeanUtils.copyProperties(approver, approverVo); return approverVo; } } src/main/java/com/ruoyi/approve/service/impl/FinReimbursementDetailServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ package com.ruoyi.approve.service.impl; import com.ruoyi.approve.pojo.FinReimbursementDetail; import com.ruoyi.approve.mapper.FinReimbursementDetailMapper; import com.ruoyi.approve.service.FinReimbursementDetailService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * <p> * æ¥éåæç»è¡¨ æå¡å®ç°ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:38 */ @Service public class FinReimbursementDetailServiceImpl extends ServiceImpl<FinReimbursementDetailMapper, FinReimbursementDetail> implements FinReimbursementDetailService { } src/main/java/com/ruoyi/approve/service/impl/FinReimbursementServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,544 @@ package com.ruoyi.approve.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.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.approve.bean.dto.ApprovalInstanceDto; import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeApproverDto; import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeDto; import com.ruoyi.approve.bean.dto.FinReimbursementDto; import com.ruoyi.approve.bean.vo.FinReimbursementVo; import com.ruoyi.approve.mapper.ApprovalInstanceMapper; import com.ruoyi.approve.mapper.FinReimbursementDetailMapper; import com.ruoyi.approve.mapper.FinReimbursementMapper; import com.ruoyi.approve.mapper.FinReimbursementTravelMapper; import com.ruoyi.approve.pojo.*; import com.ruoyi.basic.enums.ApplicationTypeEnum; import com.ruoyi.basic.enums.RecordTypeEnum; import com.ruoyi.basic.utils.FileUtil; import com.ruoyi.approve.service.*; import com.ruoyi.common.enums.TypeEnums; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.OrderUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.project.system.service.ISysNoticeService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; /** * <p> * æ¥éå主表 æå¡å®ç°ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:15 */ @Service @RequiredArgsConstructor public class FinReimbursementServiceImpl extends ServiceImpl<FinReimbursementMapper, FinReimbursement> implements FinReimbursementService { private static final String BILL_STATUS_DRAFT = "DRAFT"; private static final String BILL_STATUS_IN_APPROVAL = "IN_APPROVAL"; private static final String NODE_STATUS_WAITING = "WAITING"; private final ApprovalInstanceMapper approvalInstanceMapper; private final ApprovalInstanceService approvalInstanceService; private final ApprovalInstanceNodeService approvalInstanceNodeService; private final ApprovalTaskService approvalTaskService; private final ApprovalRecordService approvalRecordService; private final FinReimbursementMapper finReimbursementMapper; private final FinReimbursementTravelMapper finReimbursementTravelMapper; private final FinReimbursementDetailMapper finReimbursementDetailMapper; private final FileUtil fileUtil; private final ISysNoticeService sysNoticeService; @Override public IPage<FinReimbursementVo> listPage(FinReimbursementDto finReimbursementDto, Page<FinReimbursementVo> page) { IPage<FinReimbursementVo> finReimbursementVoIPage = finReimbursementMapper.listPage(finReimbursementDto, page); finReimbursementVoIPage.getRecords().forEach(vo -> { vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.FIN_REIMBURSEMENT, vo.getId())); }); return finReimbursementVoIPage; } @Override @Transactional(rollbackFor = Exception.class) public Boolean add(FinReimbursementDto finReimbursementDto) { String billStatus = validateAddParam(finReimbursementDto); // çææ¥éåå· String billNo = OrderUtils.countTodayByCreateTime(finReimbursementMapper, "BXD", "bill_no"); List<FinReimbursementDetail> details = finReimbursementDto.getDetails(); BigDecimal totalAmount = details.stream() .map(FinReimbursementDetail::getAmount) .filter(Objects::nonNull) .reduce(BigDecimal.ZERO, BigDecimal::add); FinReimbursement reimbursement = buildReimbursement(finReimbursementDto, billNo, totalAmount, billStatus); // ä¿åæ¥éå主表 boolean saved = this.save(reimbursement); if (!saved || reimbursement.getId() == null) { throw new ServiceException("æ°å¢æ¥éå失败"); } Long reimbursementId = reimbursement.getId(); // ä¿åå·®æ æ¥éæ©å±ä¿¡æ¯ï¼æ¥éç±»åä¸ºå·®æ æ¥éæ¶ï¼ FinReimbursementTravel travel = finReimbursementDto.getTravel(); if (isTravelReimbursement(finReimbursementDto.getReimbursementType())) { travel.setReimbursementId(reimbursementId); int travelRows = finReimbursementTravelMapper.insert(travel); if (travelRows != 1) { throw new ServiceException("æ°å¢å·®æ æ¥éæ©å±ä¿¡æ¯å¤±è´¥"); } } // ä¿åæ¥éåæç» for (int i = 0; i < details.size(); i++) { FinReimbursementDetail detail = details.get(i); detail.setId(null); detail.setReimbursementId(reimbursementId); detail.setRowNo(i + 1); int detailRows = finReimbursementDetailMapper.insert(detail); if (detailRows != 1) { throw new ServiceException("æ°å¢æ¥éåæç»å¤±è´¥"); } } if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) { startApproval(reimbursement, finReimbursementDto); } fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.FIN_REIMBURSEMENT, reimbursementId, finReimbursementDto.getStorageBlobDTOs()); return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean update(FinReimbursementDto finReimbursementDto) { String billStatus = validateUpdateParam(finReimbursementDto); Long reimbursementId = finReimbursementDto.getId(); FinReimbursement existing = finReimbursementMapper.selectById(reimbursementId); if (existing == null) { throw new ServiceException("æ¥éåä¸åå¨"); } // è®¡ç®æç»æ±æ»éé¢ List<FinReimbursementDetail> details = finReimbursementDto.getDetails(); BigDecimal totalAmount = details.stream() .map(FinReimbursementDetail::getAmount) .filter(Objects::nonNull) .reduce(BigDecimal.ZERO, BigDecimal::add); // æ´æ°ä¸»è¡¨ FinReimbursement reimbursement = buildReimbursement( finReimbursementDto, existing.getBillNo(), totalAmount, billStatus ); reimbursement.setId(reimbursementId); int mainRows = finReimbursementMapper.updateById(reimbursement); if (mainRows != 1) { throw new ServiceException("æ´æ°æ¥éå主表失败"); } // æ¥è¯¢æ°æ®åºä¸å·²æçæç» List<FinReimbursementDetail> existingDetails = finReimbursementDetailMapper.selectList( new LambdaQueryWrapper<FinReimbursementDetail>() .eq(FinReimbursementDetail::getReimbursementId, reimbursementId)); Set<Long> existingDetailIds = existingDetails.stream() .map(FinReimbursementDetail::getId) .filter(Objects::nonNull) .collect(Collectors.toSet()); // æ°æç»ä¸æIDç â æ´æ°ï¼æ IDç â æ°å¢ Set<Long> submittedDetailIds = new HashSet<>(); for (int i = 0; i < details.size(); i++) { FinReimbursementDetail detail = details.get(i); detail.setReimbursementId(reimbursementId); detail.setRowNo(i + 1); if (detail.getId() != null && existingDetailIds.contains(detail.getId())) { finReimbursementDetailMapper.updateById(detail); submittedDetailIds.add(detail.getId()); } else { detail.setId(null); finReimbursementDetailMapper.insert(detail); } } // æ°æ®åºä¸å·²æä½æ°æç»ä¸æ²¡æç â å é¤ for (Long existingId : existingDetailIds) { if (!submittedDetailIds.contains(existingId)) { finReimbursementDetailMapper.deleteById(existingId); } } // å·®æ æ©å±ï¼æåæ´æ°ï¼æ åæ°å¢ FinReimbursementTravel existingTravel = finReimbursementTravelMapper.selectOne( new LambdaQueryWrapper<FinReimbursementTravel>() .eq(FinReimbursementTravel::getReimbursementId, reimbursementId) .last("LIMIT 1")); FinReimbursementTravel travel = finReimbursementDto.getTravel(); if (isTravelReimbursement(finReimbursementDto.getReimbursementType()) && travel != null) { travel.setReimbursementId(reimbursementId); if (existingTravel != null) { travel.setId(existingTravel.getId()); finReimbursementTravelMapper.updateById(travel); } else { travel.setId(null); finReimbursementTravelMapper.insert(travel); } } resetApprovalFlow(existing, reimbursementId); if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) { reimbursement.setApprovalInstanceId(null); startApproval(reimbursement, finReimbursementDto); } fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.FIN_REIMBURSEMENT, reimbursementId, finReimbursementDto.getStorageBlobDTOs()); return true; } @Override public FinReimbursementVo detail(Long id) { if (id == null ) { throw new ServiceException("æ¥éåIDä¸è½ä¸ºç©º"); } FinReimbursement reimbursement = finReimbursementMapper.selectById(id); if (reimbursement == null) { throw new ServiceException("æ¥éåä¸åå¨"); } FinReimbursementVo vo = new FinReimbursementVo(); vo.setId(reimbursement.getId()); vo.setBillNo(reimbursement.getBillNo()); vo.setReimbursementType(reimbursement.getReimbursementType()); vo.setExpenseType(reimbursement.getExpenseType()); vo.setApplicantId(reimbursement.getApplicantId()); vo.setApplicantCode(reimbursement.getApplicantCode()); vo.setApplicantName(reimbursement.getApplicantName()); vo.setApplicantDeptId(reimbursement.getApplicantDeptId()); vo.setApplicantDeptName(reimbursement.getApplicantDeptName()); vo.setReason(reimbursement.getReason()); vo.setApplyAmount(reimbursement.getApplyAmount()); vo.setDetailTotalAmount(reimbursement.getDetailTotalAmount()); vo.setPayeeName(reimbursement.getPayeeName()); vo.setPayeeAccount(reimbursement.getPayeeAccount()); vo.setPayeeBank(reimbursement.getPayeeBank()); vo.setApprovalInstanceId(reimbursement.getApprovalInstanceId()); vo.setApproveProcessId(reimbursement.getApproveProcessId()); vo.setBillStatus(reimbursement.getBillStatus()); vo.setApprovedTime(reimbursement.getApprovedTime()); vo.setPaidTime(reimbursement.getPaidTime()); vo.setAccountExpenseId(reimbursement.getAccountExpenseId()); vo.setRemark(reimbursement.getRemark()); vo.setTenantId(reimbursement.getTenantId()); vo.setCreateUser(reimbursement.getCreateUser()); vo.setCreateTime(reimbursement.getCreateTime()); vo.setUpdateUser(reimbursement.getUpdateUser()); vo.setUpdateTime(reimbursement.getUpdateTime()); vo.setDeptId(reimbursement.getDeptId()); vo.setDeleted(reimbursement.getDeleted()); vo.setDetails(finReimbursementDetailMapper.selectList( new LambdaQueryWrapper<FinReimbursementDetail>() .eq(FinReimbursementDetail::getReimbursementId, reimbursement.getId()) .orderByAsc(FinReimbursementDetail::getRowNo) )); if (isTravelReimbursement(reimbursement.getReimbursementType())) { vo.setTravel(finReimbursementTravelMapper.selectOne( new LambdaQueryWrapper<FinReimbursementTravel>() .eq(FinReimbursementTravel::getReimbursementId, reimbursement.getId()) .last("LIMIT 1") )); } vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.FIN_REIMBURSEMENT, reimbursement.getId())); //审æ¹è®°å½è¿å vo.setTasks(approvalTaskService.list(new LambdaQueryWrapper<ApprovalTask>().eq(ApprovalTask::getInstanceId, reimbursement.getApprovalInstanceId()))); vo.setRecords(approvalRecordService.list(new LambdaQueryWrapper<ApprovalRecord>().eq(ApprovalRecord::getInstanceId, reimbursement.getApprovalInstanceId()))); return vo; } @Override @Transactional(rollbackFor = Exception.class) public Boolean delete(List<Long> ids) { fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.FILE, RecordTypeEnum.FIN_REIMBURSEMENT, ids); //å å é¤æç» finReimbursementDetailMapper.delete(new LambdaQueryWrapper<FinReimbursementDetail>().in(FinReimbursementDetail::getReimbursementId, ids)); //å é¤å·®æ finReimbursementTravelMapper.delete(new LambdaQueryWrapper<FinReimbursementTravel>().in(FinReimbursementTravel::getReimbursementId, ids)); //å é¤ä¸»è¡¨ int rows = finReimbursementMapper.delete(new LambdaQueryWrapper<FinReimbursement>().in(FinReimbursement::getId, ids)); return rows == ids.size(); } private String validateUpdateParam(FinReimbursementDto finReimbursementDto) { if (finReimbursementDto == null || finReimbursementDto.getId() == null) { throw new ServiceException("æ¥éåIDä¸è½ä¸ºç©º"); } if (finReimbursementDto.getReimbursementType() == null) { throw new ServiceException("æ¥éç±»åä¸è½ä¸ºç©º"); } String billStatus = normalizeBillStatus(finReimbursementDto.getBillStatus()); if (billStatus == null) { throw new ServiceException("åæ®ç¶æåªæ¯æ DRAFT æ IN_APPROVAL"); } if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) { validateApprovalNodes(finReimbursementDto.getNodes()); } List<FinReimbursementDetail> details = finReimbursementDto.getDetails(); if (details == null || details.isEmpty()) { throw new ServiceException("æ¥éåæç»ä¸è½ä¸ºç©º"); } for (FinReimbursementDetail detail : details) { if (detail == null) { throw new ServiceException("æ¥éåæç»ä¸è½ä¸ºç©º"); } if (detail.getAmount() == null || detail.getAmount().compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("æ¥éåæç»éé¢å¿ 须大äº0"); } } if (isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() == null) { throw new ServiceException("å·®æ æ¥éå¿ é¡»å¡«åå·®æ æ©å±ä¿¡æ¯"); } if (!isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() != null) { throw new ServiceException("éå·®æ æ¥éä¸å 许填åå·®æ æ©å±ä¿¡æ¯"); } return billStatus; } private String validateAddParam(FinReimbursementDto finReimbursementDto) { if (finReimbursementDto == null) { throw new ServiceException("æ¥éåæ°æ®ä¸è½ä¸ºç©º"); } if (finReimbursementDto.getReimbursementType() == null) { throw new ServiceException("æ¥éç±»åä¸è½ä¸ºç©º"); } String billStatus = normalizeBillStatus(finReimbursementDto.getBillStatus()); if (billStatus == null) { throw new ServiceException("åæ®ç¶æåªæ¯æ DRAFT æ IN_APPROVAL"); } if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) { validateApprovalNodes(finReimbursementDto.getNodes()); } List<FinReimbursementDetail> details = finReimbursementDto.getDetails(); if (details == null || details.isEmpty()) { throw new ServiceException("æ¥éåæç»ä¸è½ä¸ºç©º"); } for (FinReimbursementDetail detail : details) { if (detail == null) { throw new ServiceException("æ¥éåæç»ä¸è½ä¸ºç©º"); } if (detail.getAmount() == null || detail.getAmount().compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("æ¥éåæç»éé¢å¿ 须大äº0"); } } if (isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() == null) { throw new ServiceException("å·®æ æ¥éå¿ é¡»å¡«åå·®æ æ©å±ä¿¡æ¯"); } if (!isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() != null) { throw new ServiceException("éå·®æ æ¥éä¸å 许填åå·®æ æ©å±ä¿¡æ¯"); } return billStatus; } private FinReimbursement buildReimbursement(FinReimbursementDto finReimbursementDto, String billNo, BigDecimal totalAmount, String billStatus) { FinReimbursement reimbursement = new FinReimbursement(); reimbursement.setId(null); reimbursement.setBillNo(billNo); reimbursement.setReimbursementType(finReimbursementDto.getReimbursementType()); reimbursement.setExpenseType(finReimbursementDto.getExpenseType()); reimbursement.setApplicantId(finReimbursementDto.getApplicantId()); reimbursement.setApplicantCode(finReimbursementDto.getApplicantCode()); reimbursement.setApplicantName(finReimbursementDto.getApplicantName()); reimbursement.setApplicantDeptId(finReimbursementDto.getApplicantDeptId()); reimbursement.setApplicantDeptName(finReimbursementDto.getApplicantDeptName()); reimbursement.setReason(finReimbursementDto.getReason()); reimbursement.setApplyAmount(finReimbursementDto.getApplyAmount()); reimbursement.setDetailTotalAmount(totalAmount); reimbursement.setPayeeName(finReimbursementDto.getPayeeName()); reimbursement.setPayeeAccount(finReimbursementDto.getPayeeAccount()); reimbursement.setPayeeBank(finReimbursementDto.getPayeeBank()); reimbursement.setRemark(finReimbursementDto.getRemark()); reimbursement.setTenantId(finReimbursementDto.getTenantId()); reimbursement.setApproveProcessId(null); reimbursement.setBillStatus(billStatus); return reimbursement; } private void startApproval(FinReimbursement reimbursement, FinReimbursementDto finReimbursementDto) { Long businessType = resolveBusinessType(finReimbursementDto.getReimbursementType()); ApprovalInstanceDto approvalInstanceDto = new ApprovalInstanceDto(); approvalInstanceDto.setInstanceNo(OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no")); approvalInstanceDto.setBusinessId(reimbursement.getId()); approvalInstanceDto.setTemplateId(null); approvalInstanceDto.setTemplateName(TypeEnums.getLabelByValue(businessType) + "审æ¹"); approvalInstanceDto.setBusinessType(businessType); approvalInstanceDto.setTitle("æ¥éåå·ï¼" + reimbursement.getBillNo()); approvalInstanceDto.setApplicantId(reimbursement.getApplicantId() != null ? reimbursement.getApplicantId() : SecurityUtils.getUserId()); approvalInstanceDto.setApplicantName(reimbursement.getApplicantName() != null ? reimbursement.getApplicantName() : SecurityUtils.getLoginUser().getNickName()); approvalInstanceDto.setApplyTime(LocalDateTime.now()); approvalInstanceDto.setStatus("PENDING"); approvalInstanceDto.setCurrentLevel(1); boolean approvalSaved = approvalInstanceService.save(approvalInstanceDto); if (!approvalSaved || approvalInstanceDto.getId() == null) { throw new ServiceException("å起审æ¹å¤±è´¥"); } List<ApprovalTask> firstTasks = createApprovalNodes(approvalInstanceDto, finReimbursementDto.getNodes()); sendApproveNotice(approvalInstanceDto, firstTasks); FinReimbursement update = new FinReimbursement(); update.setId(reimbursement.getId()); update.setApprovalInstanceId(approvalInstanceDto.getId()); update.setBillStatus(BILL_STATUS_IN_APPROVAL); int rows = finReimbursementMapper.updateById(update); if (rows != 1) { throw new ServiceException("å填审æ¹å®ä¾å¤±è´¥"); } } private List<ApprovalTask> createApprovalNodes(ApprovalInstanceDto approvalInstanceDto, List<ApprovalTemplateNodeDto> nodes) { List<ApprovalTask> firstTasks = Collections.emptyList(); for (int i = 0; i < nodes.size(); i++) { ApprovalTemplateNodeDto nodeDto = nodes.get(i); ApprovalInstanceNode instanceNode = new ApprovalInstanceNode(); instanceNode.setInstanceId(approvalInstanceDto.getId()); instanceNode.setLevelNo(nodeDto.getLevelNo()); instanceNode.setApproveType(nodeDto.getApproveType()); instanceNode.setStatus(i == 0 ? "PENDING" : NODE_STATUS_WAITING); instanceNode.setStartTime(i == 0 ? LocalDateTime.now() : null); instanceNode.setDeleted((byte) 0); approvalInstanceNodeService.save(instanceNode); List<ApprovalTask> tasks = nodeDto.getApprovers().stream().map(approver -> { ApprovalTask task = new ApprovalTask(); task.setInstanceId(approvalInstanceDto.getId()); task.setNodeId(instanceNode.getId()); task.setLevelNo(instanceNode.getLevelNo()); task.setApproverId(approver.getApproverId()); task.setApproverName(approver.getApproverName()); task.setTaskStatus("PENDING"); task.setIsRead((byte) 0); task.setDeleted((byte) 0); return task; }).collect(Collectors.toList()); approvalTaskService.saveBatch(tasks); if (i == 0) { firstTasks = tasks; ApprovalRecord record = new ApprovalRecord(); record.setInstanceId(approvalInstanceDto.getId()); record.setNodeId(instanceNode.getId()); record.setOperatorId(approvalInstanceDto.getApplicantId()); record.setOperatorName(approvalInstanceDto.getApplicantName()); record.setAction("SUBMIT"); record.setComment("å起审æ¹"); record.setDeleted((byte) 0); approvalRecordService.save(record); } } return firstTasks; } private void validateApprovalNodes(List<ApprovalTemplateNodeDto> nodes) { if (nodes == null || nodes.isEmpty()) { throw new ServiceException("æäº¤å®¡æ¹æ¶å®¡æ¹èç¹ä¸è½ä¸ºç©º"); } for (int i = 0; i < nodes.size(); i++) { ApprovalTemplateNodeDto node = nodes.get(i); if (node == null) { throw new ServiceException("审æ¹èç¹ä¸è½ä¸ºç©º"); } if (node.getLevelNo() == null) { node.setLevelNo(i + 1); } if (!StringUtils.hasText(node.getApproveType())) { throw new ServiceException("审æ¹èç¹å®¡æ¹æ¹å¼ä¸è½ä¸ºç©º"); } List<ApprovalTemplateNodeApproverDto> approvers = node.getApprovers(); if (approvers == null || approvers.isEmpty()) { throw new ServiceException("审æ¹èç¹å®¡æ¹äººä¸è½ä¸ºç©º"); } for (ApprovalTemplateNodeApproverDto approver : approvers) { if (approver == null || approver.getApproverId() == null) { throw new ServiceException("审æ¹äººä¸è½ä¸ºç©º"); } } } } private void sendApproveNotice(ApprovalInstanceDto instance, List<ApprovalTask> tasks) { if (instance == null || tasks == null || tasks.isEmpty()) { return; } List<Long> approverIds = tasks.stream() .map(ApprovalTask::getApproverId) .filter(id -> id != null && id > 0) .distinct() .collect(Collectors.toList()); if (approverIds.isEmpty()) { return; } String title = "æ¥é审æ¹"; String message = "审æ¹åå· " + instance.getInstanceNo() + " éè¦æ¨å®¡æ¹"; String jumpPath = "/approvalInstance?id=" + instance.getId(); sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath); } private void resetApprovalFlow(FinReimbursement existing, Long reimbursementId) { if (existing == null || existing.getApprovalInstanceId() == null) { return; } Long approvalInstanceId = existing.getApprovalInstanceId(); if (!"REJECTED".equals(existing.getBillStatus())) { approvalInstanceService.delete(Collections.singletonList(approvalInstanceId)); } clearApprovalBinding(reimbursementId); } private void clearApprovalBinding(Long reimbursementId) { int rows = finReimbursementMapper.update( null, Wrappers.<FinReimbursement>lambdaUpdate() .eq(FinReimbursement::getId, reimbursementId) .set(FinReimbursement::getApprovalInstanceId, null) ); if (rows != 1) { throw new ServiceException("éç½®å®¡æ¹æµç¨å¤±è´¥"); } } private Long resolveBusinessType(Byte reimbursementType) { return isTravelReimbursement(reimbursementType) ? TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode() : TypeEnums.EXPENSE_APPROVAL.getCode(); } private String normalizeBillStatus(String billStatus) { if (billStatus == null) { return BILL_STATUS_DRAFT; } String normalized = billStatus.trim().toUpperCase(); if (BILL_STATUS_DRAFT.equals(normalized) || BILL_STATUS_IN_APPROVAL.equals(normalized)) { return normalized; } return null; } private boolean isTravelReimbursement(Byte reimbursementType) { return Byte.valueOf((byte) 1).equals(reimbursementType); } } src/main/java/com/ruoyi/approve/service/impl/FinReimbursementTravelServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ package com.ruoyi.approve.service.impl; import com.ruoyi.approve.pojo.FinReimbursementTravel; import com.ruoyi.approve.mapper.FinReimbursementTravelMapper; import com.ruoyi.approve.service.FinReimbursementTravelService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * <p> * å·®æ æ¥éæ©å±è¡¨ æå¡å®ç°ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-21 09:56:47 */ @Service public class FinReimbursementTravelServiceImpl extends ServiceImpl<FinReimbursementTravelMapper, FinReimbursementTravel> implements FinReimbursementTravelService { } src/main/java/com/ruoyi/approve/utils/ApproveProcessConfigNodeUtils.java
@@ -1,9 +1,370 @@ package com.ruoyi.approve.utils; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.approve.pojo.ApprovalInstance; import com.ruoyi.approve.pojo.ApprovalInstanceNode; import com.ruoyi.approve.pojo.ApprovalRecord; import com.ruoyi.approve.pojo.ApprovalTask; import com.ruoyi.approve.pojo.ApprovalTemplateNode; import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover; import com.ruoyi.approve.service.ApprovalInstanceNodeService; import com.ruoyi.approve.service.ApprovalRecordService; import com.ruoyi.approve.service.ApprovalTaskService; import com.ruoyi.approve.service.ApprovalTemplateNodeApproverService; import com.ruoyi.approve.service.ApprovalTemplateNodeService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * å®¡æ¹æµç¨èç¹å·¥å ·ç±» */ @Component @RequiredArgsConstructor public class ApproveProcessConfigNodeUtils { private final ApprovalInstanceNodeService instanceNodeService; private final ApprovalTaskService approvalTaskService; private final ApprovalRecordService approvalRecordService; private final ApprovalTemplateNodeService approvalTemplateNodeService; private final ApprovalTemplateNodeApproverService approvalTemplateNodeApproverService; } /** * æå½åå±çº§å建审æ¹èç¹å审æ¹ä»»å¡ã * 该éè½½ä¼åæ¶åå ¥ä¸æ¡å起审æ¹è®°å½ã */ @Transactional(rollbackFor = Exception.class) public ApprovalInstanceNode createCurrentNodeAndTasks(ApprovalInstance instance) { return createCurrentNodeAndTasks(instance, true); } /** * æå½åå±çº§å建审æ¹èç¹å审æ¹ä»»å¡ã * * @param instance 审æ¹å®ä¾ * @param createSubmitRecord æ¯å¦å建å起审æ¹è®°å½ * @return å建åºçå½åèç¹å®ä¾ */ @Transactional(rollbackFor = Exception.class) public ApprovalInstanceNode createCurrentNodeAndTasks(ApprovalInstance instance, boolean createSubmitRecord) { if (instance == null || instance.getId() == null) { throw new RuntimeException("审æ¹å®ä¾ä¸è½ä¸ºç©º"); } if (instance.getTemplateId() == null) { throw new RuntimeException("å®¡æ¹æ¨¡æ¿ä¸è½ä¸ºç©º"); } Integer currentLevel = instance.getCurrentLevel() == null ? 1 : instance.getCurrentLevel(); ApprovalInstanceNode existsNode = instanceNodeService.getOne( new LambdaQueryWrapper<ApprovalInstanceNode>() .eq(ApprovalInstanceNode::getInstanceId, instance.getId()) .eq(ApprovalInstanceNode::getLevelNo, currentLevel) .eq(ApprovalInstanceNode::getDeleted, 0) .last("LIMIT 1") ); if (existsNode != null) { return existsNode; } ApprovalTemplateNode templateNode = approvalTemplateNodeService.getOne( new LambdaQueryWrapper<ApprovalTemplateNode>() .eq(ApprovalTemplateNode::getTemplateId, instance.getTemplateId()) .eq(ApprovalTemplateNode::getLevelNo, currentLevel) .orderByAsc(ApprovalTemplateNode::getId) .last("LIMIT 1") ); if (templateNode == null) { throw new RuntimeException("æªæ¾å°å½åå±çº§å¯¹åºçå®¡æ¹æ¨¡æ¿èç¹"); } List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverService.list( new LambdaQueryWrapper<ApprovalTemplateNodeApprover>() .eq(ApprovalTemplateNodeApprover::getTemplateId, instance.getTemplateId()) .eq(ApprovalTemplateNodeApprover::getNodeId, templateNode.getId()) .eq(ApprovalTemplateNodeApprover::getDeleted, 0L) .orderByAsc(ApprovalTemplateNodeApprover::getSortNo) ); if (approvers == null || approvers.isEmpty()) { throw new RuntimeException("å½å审æ¹èç¹æªé 置审æ¹äºº"); } ApprovalInstanceNode instanceNode = new ApprovalInstanceNode(); instanceNode.setInstanceId(instance.getId()); instanceNode.setLevelNo(templateNode.getLevelNo()); instanceNode.setApproveType(templateNode.getApproveType()); instanceNode.setStatus("PENDING"); instanceNode.setStartTime(LocalDateTime.now()); instanceNode.setDeleted((byte) 0); instanceNodeService.save(instanceNode); List<ApprovalTask> taskList = new ArrayList<>(approvers.size()); for (ApprovalTemplateNodeApprover approver : approvers) { ApprovalTask task = new ApprovalTask(); task.setInstanceId(instance.getId()); task.setNodeId(instanceNode.getId()); task.setLevelNo(instanceNode.getLevelNo()); task.setApproverId(approver.getApproverId()); task.setApproverName(approver.getApproverName()); task.setTaskStatus("PENDING"); task.setIsRead((byte) 0); task.setDeleted((byte) 0); taskList.add(task); } approvalTaskService.saveBatch(taskList); if (createSubmitRecord) { ApprovalRecord record = new ApprovalRecord(); record.setInstanceId(instance.getId()); record.setNodeId(instanceNode.getId()); record.setOperatorId(instance.getApplicantId()); record.setOperatorName(instance.getApplicantName()); record.setAction("SUBMIT"); record.setComment("å起审æ¹"); record.setDeleted((byte) 0); approvalRecordService.save(record); } return instanceNode; } /** * æ¥è¯¢å½åå¾ å¤çèç¹ã */ public ApprovalInstanceNode getCurrentNode(Long instanceId) { if (instanceId == null) { return null; } return instanceNodeService.getOne( new LambdaQueryWrapper<ApprovalInstanceNode>() .eq(ApprovalInstanceNode::getInstanceId, instanceId) .eq(ApprovalInstanceNode::getStatus, "PENDING") .eq(ApprovalInstanceNode::getDeleted, 0) .orderByAsc(ApprovalInstanceNode::getLevelNo) .last("LIMIT 1") ); } /** * æ¥è¯¢å½å审æ¹å±çº§ã */ public Integer getCurrentLevel(Long instanceId) { ApprovalInstanceNode currentNode = getCurrentNode(instanceId); return currentNode != null ? currentNode.getLevelNo() : null; } /** * æ¥è¯¢å½åèç¹ä¸çå¾ å®¡æ¹ä»»å¡ã */ public List<ApprovalTask> getCurrentPendingTasks(Long instanceId) { if (instanceId == null) { return List.of(); } ApprovalInstanceNode currentNode = getCurrentNode(instanceId); if (currentNode == null) { return List.of(); } return approvalTaskService.list( new LambdaQueryWrapper<ApprovalTask>() .eq(ApprovalTask::getInstanceId, instanceId) .eq(ApprovalTask::getNodeId, currentNode.getId()) .eq(ApprovalTask::getTaskStatus, "PENDING") .eq(ApprovalTask::getDeleted, 0) .orderByAsc(ApprovalTask::getLevelNo) ); } /** * æ¥è¯¢å½åç¨æ·å¨å½åèç¹ä¸çå¾ å®¡æ¹ä»»å¡ã */ public ApprovalTask getCurrentUserTask(Long instanceId, Long userId) { if (instanceId == null || userId == null) { return null; } ApprovalInstanceNode currentNode = getCurrentNode(instanceId); if (currentNode == null) { return null; } return approvalTaskService.getOne( new LambdaQueryWrapper<ApprovalTask>() .eq(ApprovalTask::getInstanceId, instanceId) .eq(ApprovalTask::getNodeId, currentNode.getId()) .eq(ApprovalTask::getApproverId, userId) .eq(ApprovalTask::getTaskStatus, "PENDING") .eq(ApprovalTask::getDeleted, 0) .last("LIMIT 1") ); } /** * 夿å½åç¨æ·æ¯å¦æ¯å½å审æ¹äººã */ public boolean isCurrentApprover(Long instanceId, Long userId) { return getCurrentUserTask(instanceId, userId) != null; } /** * æ¥è¯¢å½åèç¹ç审æ¹äºº ID å表ã */ public List<Long> getCurrentNodeApproverIds(Long instanceId) { return getCurrentPendingTasks(instanceId).stream() .map(ApprovalTask::getApproverId) .distinct() .collect(Collectors.toList()); } /** * æ¥è¯¢å½åèç¹å©ä½å¾ 审æ¹äººæ°ã */ public int getRemainingApproverCount(Long instanceId) { return getCurrentPendingTasks(instanceId).size(); } /** * æ¥è¯¢å½åèç¹å·²åæäººæ°ã */ public int getApprovedCount(Long instanceId) { if (instanceId == null) { return 0; } ApprovalInstanceNode currentNode = getCurrentNode(instanceId); if (currentNode == null) { return 0; } return Math.toIntExact(approvalTaskService.count( new LambdaQueryWrapper<ApprovalTask>() .eq(ApprovalTask::getInstanceId, instanceId) .eq(ApprovalTask::getNodeId, currentNode.getId()) .eq(ApprovalTask::getTaskStatus, "APPROVED") .eq(ApprovalTask::getDeleted, 0) )); } /** * æ¥è¯¢å½åèç¹å·²æç»äººæ°ã */ public int getRejectedCount(Long instanceId) { if (instanceId == null) { return 0; } ApprovalInstanceNode currentNode = getCurrentNode(instanceId); if (currentNode == null) { return 0; } return Math.toIntExact(approvalTaskService.count( new LambdaQueryWrapper<ApprovalTask>() .eq(ApprovalTask::getInstanceId, instanceId) .eq(ApprovalTask::getNodeId, currentNode.getId()) .eq(ApprovalTask::getTaskStatus, "REJECTED") .eq(ApprovalTask::getDeleted, 0) )); } /** * 夿å½åèç¹æ¯å¦å¯ä»¥æµè½¬å°ä¸ä¸å±ã */ public boolean canProceedToNextLevel(Long instanceId, String approveType) { if (instanceId == null || approveType == null) { return false; } if (getRejectedCount(instanceId) > 0) { return false; } int totalApproverCount = getCurrentPendingTasks(instanceId).size() + getApprovedCount(instanceId); int approvedCount = getApprovedCount(instanceId); if ("AND".equalsIgnoreCase(approveType)) { return approvedCount > 0 && approvedCount == totalApproverCount; } if ("OR".equalsIgnoreCase(approveType)) { return approvedCount > 0; } return false; } /** * æ¥è¯¢å½åç¨æ·å¨å½åèç¹ä¸çä»»å¡ç¶æã */ public String getUserTaskStatus(Long instanceId, Long userId) { if (instanceId == null || userId == null) { return null; } ApprovalInstanceNode currentNode = getCurrentNode(instanceId); if (currentNode == null) { return null; } ApprovalTask task = approvalTaskService.getOne( new LambdaQueryWrapper<ApprovalTask>() .eq(ApprovalTask::getInstanceId, instanceId) .eq(ApprovalTask::getNodeId, currentNode.getId()) .eq(ApprovalTask::getApproverId, userId) .eq(ApprovalTask::getDeleted, 0) .last("LIMIT 1") ); return task != null ? task.getTaskStatus() : null; } /** * æ¥è¯¢æå®ç¨æ·çå ¨é¨å¾ 审æ¹ä»»å¡ã */ public List<ApprovalTask> getUserAllPendingTasks(Long userId) { if (userId == null) { return List.of(); } return approvalTaskService.list( new LambdaQueryWrapper<ApprovalTask>() .eq(ApprovalTask::getApproverId, userId) .eq(ApprovalTask::getTaskStatus, "PENDING") .eq(ApprovalTask::getDeleted, 0) .orderByDesc(ApprovalTask::getCreateTime) ); } /** * æ¥è¯¢å®¡æ¹å®ä¾çè¿åº¦æè¦ã */ public String getApprovalProgress(Long instanceId) { if (instanceId == null) { return "æ æç审æ¹å®ä¾"; } ApprovalInstanceNode currentNode = getCurrentNode(instanceId); if (currentNode == null) { return "审æ¹å·²å®ææå°æªå¼å§"; } int approvedCount = getApprovedCount(instanceId); int rejectedCount = getRejectedCount(instanceId); int pendingCount = getRemainingApproverCount(instanceId); int totalCount = approvedCount + rejectedCount + pendingCount; return String.format( "第%d级审æ¹ï¼æ»äººæ°=%dï¼å·²åæ=%dï¼å·²æç»=%dï¼å¾ 审æ¹=%d", currentNode.getLevelNo(), totalCount, approvedCount, rejectedCount, pendingCount ); } } src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java
@@ -194,7 +194,12 @@ // Account SALES_REFUND_AMOUNT_ORDER("sales_refund_amount_order"), SALES_RECEIPT_RETURN("sales_receipt_return"), ACCOUNT_EXPENSE("account_expense"), FIN_REIMBURSEMENT("fin_reimbursement"), FIN_VOUCHER("fin_voucher"), ACCOUNT_FILE("account_file"), ENTERPRISE_NEWS("enterprise_news"), APPROVAL_INSTANCE("approval_instance"), ACCOUNT_INVOICE_APPLICATION("account_invoice_application"), ACCOUNT_PURCHASE_INVOICE("account_purchase_invoice"); src/main/java/com/ruoyi/collaborativeApproval/controller/EnterpriseNewsController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,61 @@ package com.ruoyi.collaborativeApproval.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.collaborativeApproval.dto.EnterpriseNewsDto; import com.ruoyi.collaborativeApproval.service.EnterpriseNewsService; import com.ruoyi.collaborativeApproval.vo.EnterpriseNewsVo; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; import com.ruoyi.framework.web.domain.R; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.*; import java.util.List; /** * <p> * ä¼ä¸æ°é»è¡¨ å端æ§å¶å¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:50:59 */ @RestController @RequestMapping("/enterpriseNews") @Tag(name = "ä¼ä¸æ°é»è¡¨") @AllArgsConstructor public class EnterpriseNewsController { private final EnterpriseNewsService enterpriseNewsService; @Operation(summary = "å页æ¥è¯¢") @GetMapping("/listPage") @Log(title = "ä¼ä¸æ°é»å页æ¥è¯¢", businessType = BusinessType.OTHER) public R listPage(Page<EnterpriseNewsVo> page , EnterpriseNewsDto enterpriseNewsDto) { return R.ok(enterpriseNewsService.listPage(page, enterpriseNewsDto)); } @PostMapping("/save") @Operation(summary = "ä¿å") @Log(title = "ä¿åä¼ä¸æ°é»", businessType = BusinessType.INSERT) public R save(@RequestBody EnterpriseNewsDto enterpriseNewsDto) { return R.ok(enterpriseNewsService.add(enterpriseNewsDto)); } @PutMapping("/update") @Operation(summary = "æ´æ°") @Log(title = "æ´æ°ä¼ä¸æ°é»", businessType = BusinessType.UPDATE) public R update(@RequestBody EnterpriseNewsDto enterpriseNewsDto) { return R.ok(enterpriseNewsService.updateEnterpriseNewsDto(enterpriseNewsDto)); } @DeleteMapping("/delete") @Operation(summary = "å é¤") @Log(title = "å é¤ä¼ä¸æ°é»", businessType = BusinessType.DELETE) public R delete(@RequestBody List<Long> ids) { return R.ok(enterpriseNewsService.delete(ids)); } } src/main/java/com/ruoyi/collaborativeApproval/controller/EnterpriseNewsScopeDeptController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.collaborativeApproval.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * ä¼ä¸æ°é»é 读èå´é¨é¨è¡¨ å端æ§å¶å¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:51:12 */ @RestController @RequestMapping("/enterpriseNewsScopeDept") public class EnterpriseNewsScopeDeptController { } src/main/java/com/ruoyi/collaborativeApproval/controller/EnterpriseNewsScopeUserController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.collaborativeApproval.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * ä¼ä¸æ°é»é 读èå´ç¨æ·è¡¨ å端æ§å¶å¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:51:23 */ @RestController @RequestMapping("/enterpriseNewsScopeUser") public class EnterpriseNewsScopeUserController { } src/main/java/com/ruoyi/collaborativeApproval/dto/EnterpriseNewsDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,26 @@ package com.ruoyi.collaborativeApproval.dto; import com.ruoyi.basic.dto.StorageBlobDTO; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews; import lombok.Data; import java.util.List; @Data public class EnterpriseNewsDto extends EnterpriseNews { private String createUserName; private List<Long> deptIds; private List<Long> userIds; private Long templateId; private String templateName; private String createTimeStart; private String createTimeEnd; private List<StorageBlobDTO> storageBlobDTOs; } src/main/java/com/ruoyi/collaborativeApproval/mapper/EnterpriseNewsMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,24 @@ package com.ruoyi.collaborativeApproval.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.collaborativeApproval.dto.EnterpriseNewsDto; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews; import com.ruoyi.collaborativeApproval.vo.EnterpriseNewsVo; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * <p> * ä¼ä¸æ°é»è¡¨ Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:50:59 */ @Mapper public interface EnterpriseNewsMapper extends BaseMapper<EnterpriseNews> { IPage<EnterpriseNewsVo> listPage(Page<EnterpriseNewsVo> page,@Param("enterpriseNewsDto") EnterpriseNewsDto enterpriseNewsDto); } src/main/java/com/ruoyi/collaborativeApproval/mapper/EnterpriseNewsScopeDeptMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.collaborativeApproval.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept; import org.apache.ibatis.annotations.Mapper; /** * <p> * ä¼ä¸æ°é»é 读èå´é¨é¨è¡¨ Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:51:12 */ @Mapper public interface EnterpriseNewsScopeDeptMapper extends BaseMapper<EnterpriseNewsScopeDept> { } src/main/java/com/ruoyi/collaborativeApproval/mapper/EnterpriseNewsScopeUserMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.ruoyi.collaborativeApproval.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser; import org.apache.ibatis.annotations.Mapper; /** * <p> * ä¼ä¸æ°é»é 读èå´ç¨æ·è¡¨ Mapper æ¥å£ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:51:23 */ @Mapper public interface EnterpriseNewsScopeUserMapper extends BaseMapper<EnterpriseNewsScopeUser> { } src/main/java/com/ruoyi/collaborativeApproval/pojo/EnterpriseNews.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,88 @@ package com.ruoyi.collaborativeApproval.pojo; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serializable; import java.time.LocalDateTime; /** * ä¼ä¸æ°é»è¡¨ * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:50:59 */ @Getter @Setter @ToString @TableName("enterprise_news") @ApiModel(value = "EnterpriseNews对象", description = "ä¼ä¸æ°é»è¡¨") public class EnterpriseNews implements Serializable { private static final long serialVersionUID = 1L; @Schema(description = "ç¼å· ID") @TableId(value = "id", type = IdType.AUTO) private Long id; @Schema(description = "æ é¢ Title") private String title; @Schema(description = "æè¦ Summary") private String summary; @Schema(description = "æ£æ Content") private String content; @Schema(description = "åç±» Category") private String category; @Schema(description = "é 读èå´ Read scope: all å ¨å, dept é¨é¨, custom èªå®ä¹") private String readScope; @Schema(description = "æ¯å¦å¿ 读 Required flag: 0 å¦, 1 æ¯") private Byte isRequired; @Schema(description = "ç¶æ Status: DRAFT è稿, PENDING å¾ å®¡æ¹, PUBLISHED å·²åå¸, REJECTED 驳å, OFFLINE å·²ä¸çº¿") private String status; @Schema(description = "åºè¯»äººæ° Required read count") private Integer requiredReadCount; @Schema(description = "å·²è¯»äººæ° Read count") private Integer readCount; @Schema(description = "å建人 Create user") @TableField(fill = FieldFill.INSERT) private Long createUser; @Schema(description = "å建æ¶é´ Create time") @TableField(fill = FieldFill.INSERT) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss", iso = DateTimeFormat.ISO.DATE_TIME) private LocalDateTime createTime; @Schema(description = "æ´æ°äºº Update user") @TableField(fill = FieldFill.INSERT_UPDATE) private Long updateUser; @Schema(description = "æ´æ°æ¶é´ Update time") @TableField(fill = FieldFill.INSERT_UPDATE) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss", iso = DateTimeFormat.ISO.DATE_TIME) private LocalDateTime updateTime; @Schema(description = "é¨é¨ID Dept ID") @TableField(fill = FieldFill.INSERT) private Long deptId; } src/main/java/com/ruoyi/collaborativeApproval/pojo/EnterpriseNewsScopeDept.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,59 @@ package com.ruoyi.collaborativeApproval.pojo; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.Setter; import lombok.ToString; import java.io.Serializable; import java.time.LocalDateTime; /** * <p> * ä¼ä¸æ°é»é 读èå´é¨é¨è¡¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:51:12 */ @Getter @Setter @ToString @TableName("enterprise_news_scope_dept") @ApiModel(value = "EnterpriseNewsScopeDept对象", description = "ä¼ä¸æ°é»é 读èå´é¨é¨è¡¨") public class EnterpriseNewsScopeDept implements Serializable { private static final long serialVersionUID = 1L; /** * ç¼å· */ @ApiModelProperty("ç¼å·") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * ä¼ä¸æ°é»ID */ @ApiModelProperty("ä¼ä¸æ°é»ID") private Long newsId; /** * é¨é¨ID */ @ApiModelProperty("é¨é¨ID") private Long deptId; /** * å建æ¶é´ */ @ApiModelProperty("å建æ¶é´") @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; } src/main/java/com/ruoyi/collaborativeApproval/pojo/EnterpriseNewsScopeUser.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,59 @@ package com.ruoyi.collaborativeApproval.pojo; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.Setter; import lombok.ToString; import java.io.Serializable; import java.time.LocalDateTime; /** * <p> * ä¼ä¸æ°é»é 读èå´ç¨æ·è¡¨ * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:51:23 */ @Getter @Setter @ToString @TableName("enterprise_news_scope_user") @ApiModel(value = "EnterpriseNewsScopeUser对象", description = "ä¼ä¸æ°é»é 读èå´ç¨æ·è¡¨") public class EnterpriseNewsScopeUser implements Serializable { private static final long serialVersionUID = 1L; /** * ç¼å· */ @ApiModelProperty("ç¼å·") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * ä¼ä¸æ°é»ID */ @ApiModelProperty("ä¼ä¸æ°é»ID") private Long newsId; /** * ç¨æ·ID */ @ApiModelProperty("ç¨æ·ID") private Long userId; /** * å建æ¶é´ */ @ApiModelProperty("å建æ¶é´") @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; } src/main/java/com/ruoyi/collaborativeApproval/service/EnterpriseNewsScopeDeptService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ package com.ruoyi.collaborativeApproval.service; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept; import com.baomidou.mybatisplus.extension.service.IService; /** * <p> * ä¼ä¸æ°é»é 读èå´é¨é¨è¡¨ æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:51:12 */ public interface EnterpriseNewsScopeDeptService extends IService<EnterpriseNewsScopeDept> { } src/main/java/com/ruoyi/collaborativeApproval/service/EnterpriseNewsScopeUserService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ package com.ruoyi.collaborativeApproval.service; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser; import com.baomidou.mybatisplus.extension.service.IService; /** * <p> * ä¼ä¸æ°é»é 读èå´ç¨æ·è¡¨ æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:51:23 */ public interface EnterpriseNewsScopeUserService extends IService<EnterpriseNewsScopeUser> { } src/main/java/com/ruoyi/collaborativeApproval/service/EnterpriseNewsService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,29 @@ package com.ruoyi.collaborativeApproval.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.collaborativeApproval.dto.EnterpriseNewsDto; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.collaborativeApproval.vo.EnterpriseNewsVo; import java.util.List; /** * <p> * ä¼ä¸æ°é»è¡¨ æå¡ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:50:59 */ public interface EnterpriseNewsService extends IService<EnterpriseNews> { IPage<EnterpriseNewsVo> listPage(Page<EnterpriseNewsVo> page, EnterpriseNewsDto enterpriseNewsDto); Boolean add(EnterpriseNewsDto enterpriseNewsDto); Boolean updateEnterpriseNewsDto(EnterpriseNewsDto enterpriseNewsDto); Boolean delete(List<Long> ids); } src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsScopeDeptServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ package com.ruoyi.collaborativeApproval.service.impl; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept; import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeDeptMapper; import com.ruoyi.collaborativeApproval.service.EnterpriseNewsScopeDeptService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * <p> * ä¼ä¸æ°é»é 读èå´é¨é¨è¡¨ æå¡å®ç°ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:51:12 */ @Service public class EnterpriseNewsScopeDeptServiceImpl extends ServiceImpl<EnterpriseNewsScopeDeptMapper, EnterpriseNewsScopeDept> implements EnterpriseNewsScopeDeptService { } src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsScopeUserServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ package com.ruoyi.collaborativeApproval.service.impl; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser; import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeUserMapper; import com.ruoyi.collaborativeApproval.service.EnterpriseNewsScopeUserService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * <p> * ä¼ä¸æ°é»é 读èå´ç¨æ·è¡¨ æå¡å®ç°ç±» * </p> * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:51:23 */ @Service public class EnterpriseNewsScopeUserServiceImpl extends ServiceImpl<EnterpriseNewsScopeUserMapper, EnterpriseNewsScopeUser> implements EnterpriseNewsScopeUserService { } src/main/java/com/ruoyi/collaborativeApproval/service/impl/EnterpriseNewsServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,409 @@ package com.ruoyi.collaborativeApproval.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.approve.mapper.ApprovalInstanceMapper; import com.ruoyi.approve.mapper.ApprovalTemplateMapper; import com.ruoyi.approve.pojo.ApprovalInstance; import com.ruoyi.approve.pojo.ApprovalTask; import com.ruoyi.approve.pojo.ApprovalTemplate; import com.ruoyi.approve.service.ApprovalInstanceService; import com.ruoyi.approve.utils.ApproveProcessConfigNodeUtils; import com.ruoyi.basic.enums.ApplicationTypeEnum; import com.ruoyi.basic.enums.RecordTypeEnum; import com.ruoyi.basic.utils.FileUtil; import com.ruoyi.collaborativeApproval.dto.EnterpriseNewsDto; import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsMapper; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser; import com.ruoyi.collaborativeApproval.service.EnterpriseNewsScopeDeptService; import com.ruoyi.collaborativeApproval.service.EnterpriseNewsScopeUserService; import com.ruoyi.collaborativeApproval.service.EnterpriseNewsService; import com.ruoyi.collaborativeApproval.vo.EnterpriseNewsVo; import com.ruoyi.common.enums.TypeEnums; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.OrderUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.project.system.domain.SysDept; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysDeptMapper; import com.ruoyi.project.system.mapper.SysUserDeptMapper; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.project.system.service.ISysNoticeService; import lombok.RequiredArgsConstructor; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; /** * ä¼ä¸æ°é»è¡¨æå¡å®ç°ç±» * * @author è¯å¯¼è½¯ä»¶ï¼æ±èï¼æéå ¬å¸ * @since 2026-05-20 11:50:59 */ @Service @RequiredArgsConstructor public class EnterpriseNewsServiceImpl extends ServiceImpl<EnterpriseNewsMapper, EnterpriseNews> implements EnterpriseNewsService { private static final String READ_SCOPE_ALL = "all"; private static final String READ_SCOPE_DEPT = "dept"; private static final String READ_SCOPE_CUSTOM = "custom"; private static final String STATUS_DRAFT = "DRAFT"; private static final String STATUS_PENDING = "PENDING"; private static final String STATUS_PUBLISHED = "PUBLISHED"; private static final String STATUS_REJECTED = "REJECTED"; private static final String STATUS_OFFLINE = "OFFLINE"; private final EnterpriseNewsMapper enterpriseNewsMapper; private final EnterpriseNewsScopeDeptService enterpriseNewsScopeDeptService; private final EnterpriseNewsScopeUserService enterpriseNewsScopeUserService; private final SysUserMapper sysUserMapper; private final SysDeptMapper sysDeptMapper; private final SysUserDeptMapper sysUserDeptMapper; private final ApprovalInstanceMapper approvalInstanceMapper; private final ApprovalInstanceService approvalInstanceService; private final ApprovalTemplateMapper approvalTemplateMapper; private final ApproveProcessConfigNodeUtils approveProcessConfigNodeUtils; private final ISysNoticeService sysNoticeService; private final FileUtil fileUtil; @Override public IPage<EnterpriseNewsVo> listPage(Page<EnterpriseNewsVo> page, EnterpriseNewsDto enterpriseNewsDto) { IPage<EnterpriseNewsVo> enterpriseNewsVoIPage = enterpriseNewsMapper.listPage(page, enterpriseNewsDto); enterpriseNewsVoIPage.getRecords().forEach(enterpriseNewsVo -> { enterpriseNewsVo.setStorageBlobDTOs(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.ENTERPRISE_NEWS, enterpriseNewsVo.getId())); }); return enterpriseNewsVoIPage; } @Override @Transactional(rollbackFor = Exception.class) public Boolean add(EnterpriseNewsDto enterpriseNewsDto) { validateForSave(enterpriseNewsDto); String readScope = normalizeReadScope(enterpriseNewsDto.getReadScope()); List<Long> deptIds = distinctIds(enterpriseNewsDto.getDeptIds()); List<Long> userIds = distinctIds(enterpriseNewsDto.getUserIds()); EnterpriseNews enterpriseNews = new EnterpriseNews(); BeanUtils.copyProperties(enterpriseNewsDto, enterpriseNews); enterpriseNews.setReadScope(readScope); enterpriseNews.setIsRequired(enterpriseNewsDto.getIsRequired() == null ? (byte) 0 : enterpriseNewsDto.getIsRequired()); enterpriseNews.setStatus(normalizeStatus(enterpriseNewsDto.getStatus(), STATUS_DRAFT)); enterpriseNews.setReadCount(0); enterpriseNews.setRequiredReadCount(calculateRequiredReadCount(readScope, deptIds, userIds)); Long[] loginDeptIds = SecurityUtils.getDeptId(); if (StringUtils.isNotEmpty(loginDeptIds)) { enterpriseNews.setDeptId(loginDeptIds[0]); } if (!save(enterpriseNews) || enterpriseNews.getId() == null) { throw new ServiceException("æ°å¢ä¼ä¸æ°é»å¤±è´¥"); } saveReadScopeRelations(enterpriseNews.getId(), readScope, deptIds, userIds); if (STATUS_PENDING.equals(enterpriseNews.getStatus())) { startEnterpriseNewsApproval(enterpriseNews, enterpriseNewsDto); } //æ·»å éä»¶ fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.ENTERPRISE_NEWS, enterpriseNews.getId(), enterpriseNewsDto.getStorageBlobDTOs()); return true; } @Override @Transactional(rollbackFor = Exception.class) public Boolean updateEnterpriseNewsDto(EnterpriseNewsDto enterpriseNewsDto) { if (enterpriseNewsDto == null || enterpriseNewsDto.getId() == null) { throw new ServiceException("ä¼ä¸æ°é»IDä¸è½ä¸ºç©º"); } EnterpriseNews oldEnterpriseNews = getById(enterpriseNewsDto.getId()); if (oldEnterpriseNews == null) { throw new ServiceException("ä¼ä¸æ°é»ä¸åå¨"); } if (!STATUS_DRAFT.equals(oldEnterpriseNews.getStatus()) && !STATUS_REJECTED.equals(oldEnterpriseNews.getStatus())) { throw new ServiceException("å¾ å®¡æ¹æå·²åå¸çä¼ä¸æ°é»ä¸å 许修æ¹"); } validateForSave(enterpriseNewsDto); String readScope = normalizeReadScope(enterpriseNewsDto.getReadScope()); List<Long> deptIds = distinctIds(enterpriseNewsDto.getDeptIds()); List<Long> userIds = distinctIds(enterpriseNewsDto.getUserIds()); EnterpriseNews enterpriseNews = new EnterpriseNews(); BeanUtils.copyProperties(enterpriseNewsDto, enterpriseNews); enterpriseNews.setReadScope(readScope); enterpriseNews.setIsRequired(enterpriseNewsDto.getIsRequired() == null ? oldEnterpriseNews.getIsRequired() : enterpriseNewsDto.getIsRequired()); enterpriseNews.setStatus(normalizeStatus(enterpriseNewsDto.getStatus(), oldEnterpriseNews.getStatus())); enterpriseNews.setReadCount(oldEnterpriseNews.getReadCount()); enterpriseNews.setRequiredReadCount(calculateRequiredReadCount(readScope, deptIds, userIds)); enterpriseNews.setCreateUser(oldEnterpriseNews.getCreateUser()); enterpriseNews.setCreateTime(oldEnterpriseNews.getCreateTime()); enterpriseNews.setDeptId(oldEnterpriseNews.getDeptId()); if (!updateById(enterpriseNews)) { throw new ServiceException("ä¿®æ¹ä¼ä¸æ°é»å¤±è´¥"); } clearReadScopeRelations(enterpriseNews.getId()); saveReadScopeRelations(enterpriseNews.getId(), readScope, deptIds, userIds); fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.ENTERPRISE_NEWS, enterpriseNews.getId(), enterpriseNewsDto.getStorageBlobDTOs()); if (STATUS_PENDING.equals(enterpriseNews.getStatus())) { resetEnterpriseNewsApprovalFlow(oldEnterpriseNews); startEnterpriseNewsApproval(enterpriseNews, enterpriseNewsDto); } return true; } @Override public Boolean delete(List<Long> ids) { if (ids == null || ids.isEmpty()) { return false; } if (!removeByIds(ids)) { throw new ServiceException("å é¤ä¼ä¸æ°é»å¤±è´¥"); } ids.forEach(this::clearReadScopeRelations); return true; } private void validateForSave(EnterpriseNewsDto enterpriseNewsDto) { if (enterpriseNewsDto == null) { throw new ServiceException("ä¼ä¸æ°é»æ°æ®ä¸è½ä¸ºç©º"); } if (StringUtils.isEmpty(enterpriseNewsDto.getTitle())) { throw new ServiceException("æ é¢ä¸è½ä¸ºç©º"); } if (StringUtils.isEmpty(enterpriseNewsDto.getContent())) { throw new ServiceException("æ£æä¸è½ä¸ºç©º"); } normalizeStatus(enterpriseNewsDto.getStatus(), STATUS_DRAFT); String readScope = normalizeReadScope(enterpriseNewsDto.getReadScope()); List<Long> deptIds = distinctIds(enterpriseNewsDto.getDeptIds()); List<Long> userIds = distinctIds(enterpriseNewsDto.getUserIds()); if (READ_SCOPE_DEPT.equals(readScope) && StringUtils.isEmpty(deptIds)) { throw new ServiceException("è¯·éæ©é 读èå´é¨é¨"); } if (READ_SCOPE_CUSTOM.equals(readScope) && StringUtils.isEmpty(userIds)) { throw new ServiceException("è¯·éæ©èªå®ä¹é 读人å"); } validateDeptIds(deptIds); validateUserIds(userIds); } private String normalizeReadScope(String readScope) { String normalized = StringUtils.isEmpty(readScope) ? READ_SCOPE_ALL : readScope.trim(); if (!READ_SCOPE_ALL.equals(normalized) && !READ_SCOPE_DEPT.equals(normalized) && !READ_SCOPE_CUSTOM.equals(normalized)) { throw new ServiceException("é 读èå´ä¸åæ³"); } return normalized; } private String normalizeStatus(String status, String defaultStatus) { String normalized = StringUtils.isEmpty(status) ? defaultStatus : status.trim().toUpperCase(); if (!STATUS_DRAFT.equals(normalized) && !STATUS_PENDING.equals(normalized) && !STATUS_PUBLISHED.equals(normalized) && !STATUS_REJECTED.equals(normalized) && !STATUS_OFFLINE.equals(normalized)) { throw new ServiceException("ä¼ä¸æ°é»ç¶æä¸åæ³"); } return normalized; } private void validateDeptIds(List<Long> deptIds) { if (StringUtils.isEmpty(deptIds)) { return; } for (Long deptId : deptIds) { SysDept sysDept = sysDeptMapper.selectDeptById(deptId); if (deptId == null || sysDept == null) { throw new ServiceException("é 读èå´é¨é¨ä¸åå¨"); } } } private void validateUserIds(List<Long> userIds) { if (StringUtils.isEmpty(userIds)) { return; } List<SysUser> users = sysUserMapper.selectUsersByIds(userIds); if (users.size() != userIds.size()) { throw new ServiceException("èªå®ä¹é 读人åå 嫿 æç¨æ·"); } } private Integer calculateRequiredReadCount(String readScope, List<Long> deptIds, List<Long> userIds) { if (READ_SCOPE_ALL.equals(readScope)) { Long count = sysUserMapper.selectCount(new LambdaQueryWrapper<SysUser>() .eq(SysUser::getDelFlag, "0")); return count == null ? 0 : count.intValue(); } if (READ_SCOPE_DEPT.equals(readScope)) { List<Long> allDeptIds = collectDeptIdsWithChildren(deptIds); if (StringUtils.isEmpty(allDeptIds)) { return 0; } Long count = sysUserDeptMapper.countDistinctUserIdsByDeptIds(allDeptIds); return count == null ? 0 : count.intValue(); } return userIds.size(); } private List<Long> collectDeptIdsWithChildren(List<Long> deptIds) { Set<Long> allDeptIds = new LinkedHashSet<>(); for (Long deptId : deptIds) { if (deptId == null) { continue; } allDeptIds.add(deptId); List<SysDept> children = sysDeptMapper.selectChildrenDeptById(deptId); if (StringUtils.isNotEmpty(children)) { for (SysDept child : children) { allDeptIds.add(child.getDeptId()); } } } return new ArrayList<>(allDeptIds); } private void saveReadScopeRelations(Long newsId, String readScope, List<Long> deptIds, List<Long> userIds) { if (READ_SCOPE_DEPT.equals(readScope)) { List<EnterpriseNewsScopeDept> scopeDeptList = new ArrayList<>(); for (Long deptId : deptIds) { EnterpriseNewsScopeDept scopeDept = new EnterpriseNewsScopeDept(); scopeDept.setNewsId(newsId); scopeDept.setDeptId(deptId); scopeDeptList.add(scopeDept); } if (StringUtils.isNotEmpty(scopeDeptList)) { enterpriseNewsScopeDeptService.saveBatch(scopeDeptList); } return; } if (READ_SCOPE_CUSTOM.equals(readScope)) { List<EnterpriseNewsScopeUser> scopeUserList = new ArrayList<>(); for (Long userId : userIds) { EnterpriseNewsScopeUser scopeUser = new EnterpriseNewsScopeUser(); scopeUser.setNewsId(newsId); scopeUser.setUserId(userId); scopeUserList.add(scopeUser); } if (StringUtils.isNotEmpty(scopeUserList)) { enterpriseNewsScopeUserService.saveBatch(scopeUserList); } } } private void clearReadScopeRelations(Long newsId) { enterpriseNewsScopeDeptService.remove(new LambdaQueryWrapper<EnterpriseNewsScopeDept>() .eq(EnterpriseNewsScopeDept::getNewsId, newsId)); enterpriseNewsScopeUserService.remove(new LambdaQueryWrapper<EnterpriseNewsScopeUser>() .eq(EnterpriseNewsScopeUser::getNewsId, newsId)); } private void resetEnterpriseNewsApprovalFlow(EnterpriseNews oldEnterpriseNews) { if (oldEnterpriseNews == null || !STATUS_DRAFT.equals(oldEnterpriseNews.getStatus())) { return; } List<Long> approvalInstanceIds = approvalInstanceMapper.selectList(new LambdaQueryWrapper<ApprovalInstance>() .eq(ApprovalInstance::getBusinessId, oldEnterpriseNews.getId()) .eq(ApprovalInstance::getBusinessType, TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode()) .eq(ApprovalInstance::getDeleted, (byte) 0)) .stream() .map(ApprovalInstance::getId) .filter(id -> id != null && id > 0) .collect(Collectors.toList()); if (StringUtils.isEmpty(approvalInstanceIds)) { return; } approvalInstanceService.delete(approvalInstanceIds); } private List<Long> distinctIds(List<Long> ids) { if (StringUtils.isEmpty(ids)) { return new ArrayList<>(); } Set<Long> distinctSet = new LinkedHashSet<>(); for (Long id : ids) { if (id != null) { distinctSet.add(id); } } return new ArrayList<>(distinctSet); } private void startEnterpriseNewsApproval(EnterpriseNews enterpriseNews, EnterpriseNewsDto enterpriseNewsDto) { if (enterpriseNewsDto.getTemplateId() == null) { throw new ServiceException("å®¡æ¹æ¨¡æ¿ä¸è½ä¸ºç©º"); } String templateName = enterpriseNewsDto.getTemplateName(); if (StringUtils.isEmpty(templateName)) { ApprovalTemplate approvalTemplate = approvalTemplateMapper.selectById(enterpriseNewsDto.getTemplateId()); if (approvalTemplate == null) { throw new ServiceException("å®¡æ¹æ¨¡æ¿ä¸åå¨"); } templateName = approvalTemplate.getTemplateName(); } ApprovalInstance approvalInstance = new ApprovalInstance(); approvalInstance.setInstanceNo(OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no")); approvalInstance.setTemplateId(enterpriseNewsDto.getTemplateId()); approvalInstance.setTemplateName(templateName); approvalInstance.setBusinessId(enterpriseNews.getId()); approvalInstance.setBusinessType(TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode()); approvalInstance.setTitle(enterpriseNews.getTitle()); approvalInstance.setStatus("PENDING"); approvalInstance.setCurrentLevel(1); approvalInstance.setApplicantId(SecurityUtils.getUserId()); approvalInstance.setApplicantName(SecurityUtils.getLoginUser().getNickName()); approvalInstance.setApplyTime(LocalDateTime.now()); approvalInstance.setDeleted((byte) 0); approvalInstance.setCreateUser(SecurityUtils.getUserId()); approvalInstance.setUpdateUser(SecurityUtils.getUserId()); approvalInstance.setDeptId(enterpriseNews.getDeptId()); approvalInstanceMapper.insert(approvalInstance); approveProcessConfigNodeUtils.createCurrentNodeAndTasks(approvalInstance); sendApproveNotice(approvalInstance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstance.getId())); } private void sendApproveNotice(ApprovalInstance instance, List<ApprovalTask> tasks) { if (instance == null || tasks == null || tasks.isEmpty()) { return; } List<Long> approverIds = tasks.stream() .map(ApprovalTask::getApproverId) .filter(id -> id != null && id > 0) .distinct() .collect(Collectors.toList()); if (approverIds.isEmpty()) { return; } String title = StringUtils.isNotEmpty(instance.getTemplateName()) ? instance.getTemplateName() : "å®¡æ¹æé"; String message = "审æ¹åå· " + instance.getInstanceNo() + " éè¦æ¨å®¡æ¹"; String jumpPath = "/officeProcessAutomation/ApproveManage/approve-list/?id=" + instance.getId(); sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath); } } src/main/java/com/ruoyi/collaborativeApproval/vo/EnterpriseNewsVo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,15 @@ package com.ruoyi.collaborativeApproval.vo; import com.ruoyi.basic.dto.StorageBlobVO; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews; import lombok.Data; import java.util.List; @Data public class EnterpriseNewsVo extends EnterpriseNews { private String createUserName; private List<StorageBlobVO> storageBlobDTOs; } src/main/java/com/ruoyi/common/enums/ApprovalStatusEnum.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,49 @@ package com.ruoyi.common.enums; import lombok.AllArgsConstructor; import lombok.Getter; /** * 审æ¹ç¶ææä¸¾ */ @Getter @AllArgsConstructor public enum ApprovalStatusEnum implements BaseEnum<Integer> { DRAFT(0, "è稿"), PENDING(1, "å¾ å®¡æ¹"), IN_PROGRESS(2, "审æ¹ä¸"), APPROVED(3, "å·²éè¿"), REJECTED(4, "已驳å"); private final Integer value; private final String label; @Override public Integer getCode() { return value; } @Override public String getValue() { return label; } public static ApprovalStatusEnum fromValue(Integer value) { if (value == null) { return null; } for (ApprovalStatusEnum status : values()) { if (status.getCode().equals(value)) { return status; } } return null; } public static String getLabelByValue(Integer value) { ApprovalStatusEnum statusEnum = fromValue(value); return statusEnum != null ? statusEnum.getValue() : "æªç¥ç¶æ"; } } src/main/java/com/ruoyi/common/enums/EnterpriseNewsStatusEnum.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,143 @@ package com.ruoyi.common.enums; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; /** * ä¼ä¸æ°é»ç¶ææä¸¾ç±» * * @author ruoyi * @date 2026-05-20 */ @Schema(description = "ä¼ä¸æ°é»ç¶ææä¸¾") public enum EnterpriseNewsStatusEnum implements BaseEnum<String> { /** * è稿 */ @Schema(description = "è稿") DRAFT("DRAFT", "è稿"), /** * å¾ å®¡æ¹ */ @Schema(description = "å¾ å®¡æ¹") PENDING("PENDING", "å¾ å®¡æ¹"), /** * å·²åå¸ */ @Schema(description = "å·²åå¸") PUBLISHED("PUBLISHED", "å·²åå¸"), /** * 驳å */ @Schema(description = "驳å") REJECTED("REJECTED", "驳å"), /** * å·²ä¸çº¿ */ @Schema(description = "å·²ä¸çº¿") OFFLINE("OFFLINE", "å·²ä¸çº¿"); /** * ç¶æç */ private final String code; /** * ç¶ææè¿° * -- GETTER -- * è·åç¶ææè¿° * * @return ç¶ææè¿° */ @Getter private final String description; EnterpriseNewsStatusEnum(String code, String description) { this.code = code; this.description = description; } /** * è·åç¶æç * * @return ç¶æç */ @JsonValue public String getCode() { return code; } @Override public String getValue() { return ""; } /** * æ ¹æ®ç¶æç è·åæä¸¾ * * @param code ç¶æç * @return æä¸¾å¼ */ @JsonCreator public static EnterpriseNewsStatusEnum getByCode(String code) { for (EnterpriseNewsStatusEnum status : values()) { if (status.code.equals(code)) { return status; } } throw new IllegalArgumentException("Invalid enterprise news status code: " + code); } /** * 夿æ¯å¦ä¸ºèç¨¿ç¶æ * * @return æ¯å¦ä¸ºèç¨¿ç¶æ */ public boolean isDraft() { return DRAFT.equals(this); } /** * 夿æ¯å¦ä¸ºå¾ 审æ¹ç¶æ * * @return æ¯å¦ä¸ºå¾ 审æ¹ç¶æ */ public boolean isPending() { return PENDING.equals(this); } /** * 夿æ¯å¦ä¸ºå·²åå¸ç¶æ * * @return æ¯å¦ä¸ºå·²åå¸ç¶æ */ public boolean isPublished() { return PUBLISHED.equals(this); } /** * 夿æ¯å¦ä¸ºé©³åç¶æ * * @return æ¯å¦ä¸ºé©³åç¶æ */ public boolean isRejected() { return REJECTED.equals(this); } /** * 夿æ¯å¦ä¸ºå·²ä¸çº¿ç¶æ * * @return æ¯å¦ä¸ºå·²ä¸çº¿ç¶æ */ public boolean isOffline() { return OFFLINE.equals(this); } } src/main/java/com/ruoyi/common/enums/SalesQuotationStatusEnum.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,43 @@ package com.ruoyi.common.enums; import lombok.AllArgsConstructor; import lombok.Getter; /** * é宿¥ä»·ç¶ææä¸¾ */ @Getter @AllArgsConstructor public enum SalesQuotationStatusEnum implements BaseEnum<String> { DRAFT("è稿", "è稿"), PENDING("å¾ å®¡æ¹", "å¾ å®¡æ¹"), IN_PROGRESS("å®¡æ ¸ä¸", "å®¡æ ¸ä¸"), APPROVED("éè¿", "éè¿"), REJECTED("æç»", "æç»"); private final String value; private final String label; @Override public String getCode() { return value; } @Override public String getValue() { return label; } public static SalesQuotationStatusEnum fromValue(String value) { if (value == null) { return null; } for (SalesQuotationStatusEnum status : values()) { if (status.getCode().equals(value)) { return status; } } return null; } } src/main/java/com/ruoyi/common/enums/ShippingStatusEnum.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,42 @@ package com.ruoyi.common.enums; import lombok.AllArgsConstructor; import lombok.Getter; /** * å货审æ¹ç¶ææä¸¾ */ @Getter @AllArgsConstructor public enum ShippingStatusEnum implements BaseEnum<String> { PENDING("å¾ ç¡®è®¤", "å¾ ç¡®è®¤"), IN_PROGRESS("å®¡æ ¸ä¸", "å®¡æ ¸ä¸"), APPROVED("å®¡æ ¸éè¿", "å®¡æ ¸éè¿"), REJECTED("å®¡æ ¸æç»", "å®¡æ ¸æç»"); private final String value; private final String label; @Override public String getCode() { return value; } @Override public String getValue() { return label; } public static ShippingStatusEnum fromValue(String value) { if (value == null) { return null; } for (ShippingStatusEnum status : values()) { if (status.getCode().equals(value)) { return status; } } return null; } } src/main/java/com/ruoyi/common/enums/TypeEnums.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,70 @@ package com.ruoyi.common.enums; import lombok.AllArgsConstructor; import lombok.Getter; @Getter @AllArgsConstructor public enum TypeEnums implements BaseEnum<Long> { PUBLIC_OUT(1L, "å ¬åºç®¡ç"), LEAVE(2L, "请å管ç"), BUSINESS_TRIP(3L, "åºå·®ç®¡ç"), REIMBURSEMENT(4L, "æ¥é管ç"), PURCHASE_APPROVAL(5L, "éè´å®¡æ¹"), QUOTATION_APPROVAL(6L, "æ¥ä»·å®¡æ¹"), SHIPPING_APPROVAL(7L, "å货审æ¹"), DANGEROUS_OPERATION(8L, "å±é©ä½ä¸å®¡æ¹"), OFFICE_SUPPLIES(9L, "åå ¬ç¨å审æ¹"), REGULARIZATION_APPROVAL(10L, "转æ£å®¡æ¹"), TRANSFER_APPROVAL(11L, "è°å¨å®¡æ¹"), RESIGNATION_APPROVAL(12L, "离è审æ¹"), WORK_HANDOVER_APPROVAL(13L, "å·¥ä½äº¤æ¥å®¡æ¹"), LEAVE_APPROVAL(14L, "请å审æ¹"), OVERTIME_APPROVAL(15L, "å ç审æ¹"), TRAVEL_REIMBURSEMENT_APPROVAL(16L, "åºå·®æ¥é审æ¹"), EXPENSE_APPROVAL(17L, "è´¹ç¨å®¡æ¹"), ENTERPRISE_NEWS_APPROVAL(18L, "ä¼ä¸æ°é»å®¡æ¹"); private final Long value; private final String label; @Override public Long getCode() { return value; } @Override public String getValue() { return label; } /** * æ ¹æ®å¼è·å对åºçæä¸¾ * @param value ä¸å¡ç±»åå¼ * @return 对åºçæä¸¾ï¼æªå¹é è¿ånull */ public static TypeEnums fromValue(Long value) { if (value == null) { return null; } for (TypeEnums type : values()) { if (type.getCode().equals(value)) { return type; } } return null; } /** * æ ¹æ®å¼è·åæè¿° * @param value ä¸å¡ç±»åå¼ * @return ä¸å¡ç±»åæè¿°ï¼æªå¹é è¿å"èªå®ä¹å®¡æ¹" */ public static String getLabelByValue(Long value) { TypeEnums typeEnum = fromValue(value); return typeEnum != null ? typeEnum.getValue() : "èªå®ä¹å®¡æ¹"; } } src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java
@@ -39,7 +39,7 @@ @PostMapping("/updateRouteItem") @Operation(summary = "ä¿®æ¹ç产订åçå·¥èºè·¯çº¿è¯¦æ ") public R updateRouteItem(@RequestBody ProductionOrderRoutingOperation productionOrderRoutingOperation) { return R.ok(productionOrderRoutingOperationService.updateRouteItem(productionOrderRoutingOperation)); return productionOrderRoutingOperationService.updateRouteItem(productionOrderRoutingOperation); } @DeleteMapping("/deleteRouteItem/{id}") src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java
@@ -13,4 +13,5 @@ R deleteRouteItem(Long id); int sortRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation); } src/main/java/com/ruoyi/project/system/mapper/SysUserDeptMapper.java
@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.project.system.domain.SysUserDept; import com.ruoyi.project.system.domain.vo.SysUserDeptVo; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -15,4 +16,28 @@ List<SysUserDeptVo> userLoginFacotryList(@Param("userDeptVo") SysUserDeptVo userDeptVo); List<Map<String, Object>> setSchemeApplicableStaffUserInfo(@Param("ids") List<Long> ids); @Select("<script>" + "select count(distinct sud.user_id) " + "from sys_user_dept sud " + "inner join sys_user su on su.user_id = sud.user_id " + "where su.del_flag = '0' " + "and sud.dept_id in " + "<foreach collection='deptIds' item='deptId' open='(' separator=',' close=')'>" + "#{deptId}" + "</foreach>" + "</script>") Long countDistinctUserIdsByDeptIds(@Param("deptIds") List<Long> deptIds); @Select("<script>" + "select distinct sud.user_id " + "from sys_user_dept sud " + "inner join sys_user su on su.user_id = sud.user_id " + "where su.del_flag = '0' " + "and sud.dept_id in " + "<foreach collection='deptIds' item='deptId' open='(' separator=',' close=')'>" + "#{deptId}" + "</foreach>" + "</script>") List<Long> selectDistinctUserIdsByDeptIds(@Param("deptIds") List<Long> deptIds); } src/main/java/com/ruoyi/project/system/service/impl/SysNoticeServiceImpl.java
@@ -1,12 +1,14 @@ package com.ruoyi.project.system.service.impl; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.project.system.domain.SysDept; import com.ruoyi.project.system.domain.SysNotice; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsMapper; import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.project.system.domain.SysDept; import com.ruoyi.project.system.domain.SysNotice; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.domain.SysUserDept; import com.ruoyi.project.system.mapper.SysDeptMapper; @@ -15,11 +17,15 @@ import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.project.system.service.ISysNoticeService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.stream.Collectors; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * å ¬å æå¡å±å®ç° @@ -28,13 +34,16 @@ */ @Service @RequiredArgsConstructor public class SysNoticeServiceImpl extends ServiceImpl<SysNoticeMapper, SysNotice> implements ISysNoticeService { private final SysNoticeMapper noticeMapper; private final SysUserMapper userMapper; private final SysDeptMapper deptMapper; private final SysUserDeptMapper userDeptMapper; private final UnipushService unipushService; public class SysNoticeServiceImpl extends ServiceImpl<SysNoticeMapper, SysNotice> implements ISysNoticeService { private static final Pattern ENTERPRISE_NEWS_ID_PATTERN = Pattern.compile("[?&]id=(\\d+)"); private final SysNoticeMapper noticeMapper; private final SysUserMapper userMapper; private final SysDeptMapper deptMapper; private final SysUserDeptMapper userDeptMapper; private final UnipushService unipushService; private final EnterpriseNewsMapper enterpriseNewsMapper; /** * æ¥è¯¢å ¬åä¿¡æ¯ @@ -77,11 +86,26 @@ * @param notice å ¬åä¿¡æ¯ * @return ç»æ */ @Override public int updateNotice(SysNotice notice) { return noticeMapper.updateNotice(notice); } @Override @Transactional(rollbackFor = Exception.class) public int updateNotice(SysNotice notice) { if (notice == null || notice.getNoticeId() == null) { return 0; } SysNotice dbNotice = noticeMapper.selectNoticeById(notice.getNoticeId()); if (dbNotice == null) { return 0; } boolean needSyncNewsReadCount = isEnterpriseNewsNotice(dbNotice) && notice.getStatus() != null && !notice.getStatus().equals(dbNotice.getStatus()); int rows = noticeMapper.updateNotice(notice); if (rows > 0 && needSyncNewsReadCount) { syncEnterpriseNewsReadCount(dbNotice.getJumpPath()); } return rows; } /** * å é¤å ¬å对象 @@ -115,13 +139,20 @@ } @Override public int readAll() { Long userId = SecurityUtils.getUserId(); return noticeMapper.update(null, Wrappers.<SysNotice>lambdaUpdate() .eq(SysNotice::getConsigneeId, userId) .eq(SysNotice::getStatus, "0") .set(SysNotice::getStatus, "1")); } public int readAll() { Long userId = SecurityUtils.getUserId(); List<SysNotice> unreadNotices = noticeMapper.selectList(Wrappers.<SysNotice>lambdaQuery() .eq(SysNotice::getConsigneeId, userId) .eq(SysNotice::getStatus, "0")); int rows = noticeMapper.update(null, Wrappers.<SysNotice>lambdaUpdate() .eq(SysNotice::getConsigneeId, userId) .eq(SysNotice::getStatus, "0") .set(SysNotice::getStatus, "1")); if (rows > 0) { syncEnterpriseNewsReadCount(unreadNotices); } return rows; } @Override public void simpleNoticeByUser(String title, String message, List<Long> consigneeId, String jumpPath) { @@ -211,18 +242,72 @@ @Override @Transactional(rollbackFor = Exception.class) public boolean appReadNotice(Long noticeId) { if (noticeId == null) { return false; public boolean appReadNotice(Long noticeId) { if (noticeId == null) { return false; } SysNotice sysNotice = noticeMapper.selectNoticeById(noticeId); if (sysNotice == null) { return false; } sysNotice.setStatus("1"); return noticeMapper.update(null, Wrappers.<SysNotice>lambdaUpdate() .eq(SysNotice::getNoticeId, noticeId) .eq(SysNotice::getStatus, "0") .set(SysNotice::getStatus, "1")) > 0; } } } sysNotice.setStatus("1"); boolean updated = noticeMapper.update(null, Wrappers.<SysNotice>lambdaUpdate() .eq(SysNotice::getNoticeId, noticeId) .eq(SysNotice::getStatus, "0") .set(SysNotice::getStatus, "1")) > 0; if (updated) { syncEnterpriseNewsReadCount(sysNotice.getJumpPath()); } return updated; } private boolean isEnterpriseNewsNotice(SysNotice sysNotice) { return sysNotice != null && sysNotice.getJumpPath() != null && sysNotice.getJumpPath().startsWith("/enterpriseNews?id="); } private void syncEnterpriseNewsReadCount(List<SysNotice> notices) { if (notices == null || notices.isEmpty()) { return; } Set<String> jumpPaths = new HashSet<>(); for (SysNotice notice : notices) { if (isEnterpriseNewsNotice(notice)) { jumpPaths.add(notice.getJumpPath()); } } for (String jumpPath : jumpPaths) { syncEnterpriseNewsReadCount(jumpPath); } } private void syncEnterpriseNewsReadCount(String jumpPath) { Long newsId = parseEnterpriseNewsId(jumpPath); if (newsId == null) { return; } long readCount = noticeMapper.selectCount(Wrappers.<SysNotice>lambdaQuery() .eq(SysNotice::getStatus, "1") .eq(SysNotice::getJumpPath, jumpPath)); EnterpriseNews enterpriseNews = new EnterpriseNews(); enterpriseNews.setId(newsId); enterpriseNews.setReadCount((int) readCount); enterpriseNewsMapper.updateById(enterpriseNews); } private Long parseEnterpriseNewsId(String jumpPath) { if (jumpPath == null || !jumpPath.startsWith("/enterpriseNews")) { return null; } Matcher matcher = ENTERPRISE_NEWS_ID_PATTERN.matcher(jumpPath); if (!matcher.find()) { return null; } try { return Long.parseLong(matcher.group(1)); } catch (NumberFormatException e) { return null; } } } src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java
@@ -158,4 +158,7 @@ @TableField(fill = FieldFill.INSERT) private Long deptId; @Schema(description = "模æ¿id") private Long templateId; } src/main/java/com/ruoyi/quality/utils/QualityInspectHelper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,73 @@ package com.ruoyi.quality.utils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.purchase.pojo.PurchaseLedger; import com.ruoyi.quality.mapper.QualityInspectMapper; import com.ruoyi.quality.mapper.QualityInspectParamMapper; import com.ruoyi.quality.mapper.QualityTestStandardMapper; import com.ruoyi.quality.mapper.QualityTestStandardParamMapper; import com.ruoyi.quality.pojo.QualityInspect; import com.ruoyi.quality.pojo.QualityInspectParam; import com.ruoyi.quality.pojo.QualityTestStandard; import com.ruoyi.quality.pojo.QualityTestStandardParam; import com.ruoyi.sales.pojo.SalesLedgerProduct; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.util.List; /** * è´¨æ£ååå»ºå·¥å ·ç±» */ @Component @RequiredArgsConstructor public class QualityInspectHelper { private final QualityInspectMapper qualityInspectMapper; private final QualityTestStandardMapper qualityTestStandardMapper; private final QualityTestStandardParamMapper qualityTestStandardParamMapper; private final QualityInspectParamMapper qualityInspectParamMapper; /** * å建质æ£å * @param purchaseLedger éè´å°è´¦ * @param saleProduct éè´äº§å */ public void addQualityInspect(PurchaseLedger purchaseLedger, SalesLedgerProduct saleProduct) { QualityInspect qualityInspect = new QualityInspect(); qualityInspect.setInspectType(0); qualityInspect.setSupplier(purchaseLedger.getSupplierName()); qualityInspect.setPurchaseLedgerId(purchaseLedger.getId()); qualityInspect.setProductId(saleProduct.getProductId()); qualityInspect.setProductName(saleProduct.getProductCategory()); qualityInspect.setModel(saleProduct.getSpecificationModel()); qualityInspect.setProductModelId(saleProduct.getProductModelId()); qualityInspect.setUnit(saleProduct.getUnit()); qualityInspect.setQuantity(saleProduct.getQuantity()); qualityInspectMapper.insert(qualityInspect); List<QualityTestStandard> qualityTestStandardList = qualityTestStandardMapper .getQualityTestStandardByProductId(saleProduct.getProductId(), 0, null); if (qualityTestStandardList.isEmpty()) { return; } QualityTestStandard firstStandard = qualityTestStandardList.get(0); qualityInspect.setTestStandardId(firstStandard.getId()); qualityInspectMapper.updateById(qualityInspect); List<QualityTestStandardParam> standardParams = qualityTestStandardParamMapper.selectList( Wrappers.<QualityTestStandardParam>lambdaQuery() .eq(QualityTestStandardParam::getTestStandardId, firstStandard.getId())); for (QualityTestStandardParam standardParam : standardParams) { QualityInspectParam param = new QualityInspectParam(); BeanUtils.copyProperties(standardParam, param); param.setId(null); param.setInspectId(qualityInspect.getId()); qualityInspectParamMapper.insert(param); } } } src/main/java/com/ruoyi/sales/dto/SalesQuotationDto.java
@@ -17,4 +17,6 @@ */ // 审æ¹äºº private String approveUserIds; private Long templateId; } src/main/java/com/ruoyi/sales/dto/ShippingInfoDto.java
@@ -47,5 +47,9 @@ //åè´§æ°é private BigDecimal totalQuantity; private Long templateId; private String templateName; } src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java
@@ -7,10 +7,13 @@ import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.approve.pojo.ApproveProcess; import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl; import com.ruoyi.approve.bean.dto.ApprovalInstanceDto; import com.ruoyi.approve.bean.vo.ApproveGetAndUpdateVo; import com.ruoyi.approve.bean.vo.ApproveProcessVO; import com.ruoyi.approve.mapper.ApprovalTemplateMapper; import com.ruoyi.approve.pojo.ApproveProcess; import com.ruoyi.approve.service.ApprovalInstanceService; import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl; import com.ruoyi.basic.mapper.CustomerMapper; import com.ruoyi.basic.pojo.Customer; import com.ruoyi.common.enums.IsDeleteEnum; @@ -30,8 +33,8 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; import java.util.Collections; import java.util.List; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; @Service @@ -44,6 +47,8 @@ private final ApproveProcessServiceImpl approveProcessService; private final CustomerMapper customerMapper; private final ApprovalTemplateMapper approvalTemplateMapper; private final ApprovalInstanceService approvalInstanceService; @Override public IPage<SalesQuotationDto> listPage(Page page, SalesQuotationDto salesQuotationDto) { @@ -51,10 +56,26 @@ if(CollectionUtils.isEmpty(salesQuotationDtoIPage.getRecords())){ return salesQuotationDtoIPage; } salesQuotationDtoIPage.getRecords().forEach(record -> { List<SalesQuotationProduct> products = salesQuotationProductMapper.selectBySalesQuotationId(record.getId()); record.setProducts(products); }); // æ¹éæ¥è¯¢äº§åï¼é¿å N+1 é®é¢ List<Long> quotationIds = salesQuotationDtoIPage.getRecords().stream() .map(SalesQuotationDto::getId) .filter(Objects::nonNull) .collect(Collectors.toList()); if (!quotationIds.isEmpty()) { List<SalesQuotationProduct> allProducts = salesQuotationProductMapper.selectList( new LambdaQueryWrapper<SalesQuotationProduct>() .in(SalesQuotationProduct::getSalesQuotationId, quotationIds) ); Map<Long, List<SalesQuotationProduct>> productMap = allProducts.stream() .collect(Collectors.groupingBy(SalesQuotationProduct::getSalesQuotationId)); salesQuotationDtoIPage.getRecords().forEach(record -> record.setProducts(productMap.getOrDefault(record.getId(), new ArrayList<>())) ); } return salesQuotationDtoIPage; } @@ -93,10 +114,21 @@ approveProcessVO.setPrice(salesQuotationDto.getTotalAmount()); try { approveProcessService.addApprove(approveProcessVO); }catch (Exception e){ log.error("SalesQuotationServiceImpl error:{}", e); throw new RuntimeException("审æ¹å¤±è´¥"); } catch (Exception e) { log.error("SalesQuotationServiceImpl approve error for quotationNo: {}", e); throw new RuntimeException("审æ¹å¤±è´¥: " + e.getMessage(), e); } // æ¥ä»·å®¡æ¹ ApprovalInstanceDto approvalInstanceDto = new ApprovalInstanceDto(); approvalInstanceDto.setTemplateId(salesQuotationDto.getTemplateId()); approvalInstanceDto.setBusinessId(salesQuotationDto.getId()); approvalInstanceDto.setBusinessType(7L); approvalInstanceDto.setTitle("æ¥ä»·ç¼å·ï¼" + quotationNo); approvalInstanceDto.setApplicantId(SecurityUtils.getUserId()); approvalInstanceDto.setTemplateName(approvalTemplateMapper.selectById(salesQuotationDto.getTemplateId()).getTemplateName()); approvalInstanceDto.setApplicantName(SecurityUtils.getLoginUser().getNickName()); approvalInstanceDto.setApplyTime(LocalDateTime.now()); approvalInstanceService.add(approvalInstanceDto); return true; } @Override src/main/java/com/ruoyi/staff/controller/StaffOnJobController.java
@@ -39,7 +39,7 @@ * @return */ @GetMapping("/listPage") public AjaxResult staffOnJobListPage(Page page, StaffOnJob staffOnJob) { public AjaxResult staffOnJobListPage(Page page, StaffOnJobDto staffOnJob) { return AjaxResult.success(staffOnJobService.staffOnJobListPage(page, staffOnJob)); } src/main/java/com/ruoyi/staff/dto/StaffOnJobDto.java
@@ -25,4 +25,6 @@ @JsonFormat(pattern = "yyyy-MM-dd") @DateTimeFormat(pattern = "yyyy-MM-dd") private Date contractEndTime; private Long sysDeptId; } src/main/java/com/ruoyi/staff/mapper/StaffOnJobMapper.java
@@ -14,7 +14,7 @@ @Mapper public interface StaffOnJobMapper extends BaseMapper<StaffOnJob> { IPage<StaffOnJobDto> staffOnJobListPage(Page page, @Param("staffOnJob") StaffOnJob staffOnJob); IPage<StaffOnJobDto> staffOnJobListPage(Page page, @Param("staffOnJob") StaffOnJobDto staffOnJob); List<StaffOnJobDto> staffOnJobList(@Param("staffOnJob") StaffOnJob staffOnJob); @@ -42,4 +42,4 @@ * @return åå·¥æ°æ® */ StaffOnJob selectStaffByNickName(String staffName); } } src/main/java/com/ruoyi/staff/service/IStaffOnJobService.java
@@ -14,7 +14,7 @@ public interface IStaffOnJobService extends IService<StaffOnJob> { IPage<StaffOnJobDto> staffOnJobListPage(Page page, StaffOnJob staffOnJob); IPage<StaffOnJobDto> staffOnJobListPage(Page page, StaffOnJobDto staffOnJob); StaffOnJobDto staffOnJobDetail(Long id); src/main/java/com/ruoyi/staff/service/impl/StaffLeaveServiceImpl.java
@@ -59,6 +59,7 @@ StaffLeave staffLeave = new StaffLeave(); staffLeave.setStaffOnJobId(staffLeaveDto.getStaffOnJobId()); staffLeave.setReason(staffLeaveDto.getReason()); staffLeave.setLeaveDate(staffLeaveDto.getLeaveDate()); String reason = staffLeaveDto.getReason(); if (StaffLeaveReasonOther.getCode().equals(reason)){ staffLeave.setRemark(staffLeaveDto.getRemark()); src/main/java/com/ruoyi/staff/service/impl/StaffOnJobServiceImpl.java
@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.dto.WordDateDto; import com.ruoyi.project.system.domain.SysDept; @@ -67,8 +68,9 @@ //å¨èåå·¥å°è´¦å页æ¥è¯¢ @Override public IPage<StaffOnJobDto> staffOnJobListPage(Page page, StaffOnJob staffOnJob) { return staffOnJobMapper.staffOnJobListPage(page,staffOnJob); public IPage<StaffOnJobDto> staffOnJobListPage(Page page, StaffOnJobDto staffOnJob) { IPage<StaffOnJobDto> staffOnJobDtoIPage = staffOnJobMapper.staffOnJobListPage(page, staffOnJob); return staffOnJobDtoIPage; } //æ°å¢å ¥è @@ -83,6 +85,7 @@ } // åå»ºå ¥èæ°æ® syncStudyInfoFromEducation(staffOnJobPrams); staffOnJobPrams.setContractExpireTime(staffOnJobPrams.getContractEndTime()); staffOnJobPrams.setStaffState(1); staffOnJobMapper.insert(staffOnJobPrams); @@ -141,6 +144,7 @@ // ç»å®åè¡¨æ°æ® bingingStaffOnJobExtra(id,staffOnJobParams); // æ´æ°åå·¥æ°æ® syncStudyInfoFromEducation(staffOnJobParams); staffOnJobParams.setContractExpireTime(staffOnJobParams.getContractEndTime()); return staffOnJobMapper.updateById(staffOnJobParams); } @@ -158,6 +162,7 @@ .forEach(staff -> staff.setStaffOnJobId(id)); // èµå¼ staffEducationService.saveBatch(staffOnJobPrams.getStaffEducationList()); } // æ°å¢å·¥ä½ç»å if(CollectionUtils.isNotEmpty(staffOnJobPrams.getStaffWorkExperienceList())){ staffOnJobPrams.getStaffWorkExperienceList().stream() @@ -174,6 +179,28 @@ } } private void syncStudyInfoFromEducation(StaffOnJob staffOnJobPrams) { if (staffOnJobPrams == null || CollectionUtils.isEmpty(staffOnJobPrams.getStaffEducationList())) { if (staffOnJobPrams != null) { staffOnJobPrams.setFirstStudy("/"); staffOnJobPrams.setProfession("/"); } return; } Optional<StaffEducation> matchedEducation = staffOnJobPrams.getStaffEducationList().stream() .filter(Objects::nonNull) .filter(education -> StringUtils.isNotEmpty(education.getMajor())) .findFirst(); if (matchedEducation.isPresent()) { StaffEducation education = matchedEducation.get(); staffOnJobPrams.setFirstStudy(education.getEducation()); staffOnJobPrams.setProfession(education.getMajor()); return; } staffOnJobPrams.setFirstStudy("/"); staffOnJobPrams.setProfession("/"); } /** * éè¿åå·¥idå 餿è²ç»åï¼å·¥ä½ç»åï¼ç´§æ¥è系人 src/main/java/com/ruoyi/technology/controller/TechnologyOperationController.java
@@ -24,28 +24,28 @@ private final TechnologyOperationService technologyOperationService; @GetMapping("/listPage") @Log(title = "Technology operation page", businessType = BusinessType.OTHER) @Log(title = "å·¥åºå页æ¥è¯¢", businessType = BusinessType.OTHER) @Operation(summary = "å·¥åºå页æ¥è¯¢") public R<IPage<TechnologyOperationVo>> listPage(Page<TechnologyOperationDto> page, TechnologyOperationDto technologyOperationDto) { return R.ok(technologyOperationService.listPage(page, technologyOperationDto)); } @PostMapping("/add") @Log(title = "Add technology operation", businessType = BusinessType.INSERT) @Log(title = "å·¥åºæ°å¢", businessType = BusinessType.INSERT) @Operation(summary = "æ°å¢å·¥åº") public R add(@RequestBody TechnologyOperationDto technologyOperationDto) { return technologyOperationService.add(technologyOperationDto); } @PutMapping("/update") @Log(title = "Update technology operation", businessType = BusinessType.UPDATE) @Log(title = "å·¥åºæ´æ°", businessType = BusinessType.UPDATE) @Operation(summary = "ä¿®æ¹å·¥åº") public R update(@RequestBody com.ruoyi.technology.pojo.TechnologyOperation technologyOperation) { return R.ok(technologyOperationService.updateById(technologyOperation)); } @DeleteMapping("/batchDelete") @Log(title = "Delete technology operation", businessType = BusinessType.DELETE) @Log(title = "å é¤å·¥åº", businessType = BusinessType.DELETE) @Operation(summary = "æ¹éå é¤å·¥åº") public R batchDelete(@RequestBody List<Long> ids) { return R.ok(technologyOperationService.batchDelete(ids)); src/main/java/com/ruoyi/technology/controller/TechnologyOperationParamController.java
@@ -36,7 +36,7 @@ } @DeleteMapping("/batchDelete/{id}") @Log(title = "Delete technology operation param", businessType = BusinessType.DELETE) @Log(title = "å é¤å·¥åºåæ°", businessType = BusinessType.DELETE) @Operation(summary = "å é¤å·¥åºåæ°") public AjaxResult batchDelete(@PathVariable("id") Long id) { return AjaxResult.success(technologyOperationParamService.batchDelete(id)); src/main/resources/mapper/approve/ApprovalInstanceMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,58 @@ <?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.ruoyi.approve.mapper.ApprovalInstanceMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalInstance"> <id column="id" property="id" /> <result column="instance_no" property="instanceNo" /> <result column="template_id" property="templateId" /> <result column="template_name" property="templateName" /> <result column="business_id" property="businessId" /> <result column="business_type" property="businessType" /> <result column="title" property="title" /> <result column="status" property="status" /> <result column="current_level" property="currentLevel" /> <result column="applicant_id" property="applicantId" /> <result column="applicant_name" property="applicantName" /> <result column="apply_time" property="applyTime" /> <result column="finish_time" property="finishTime" /> <result column="create_user" property="createUser" /> <result column="create_time" property="createTime" /> <result column="update_user" property="updateUser" /> <result column="update_time" property="updateTime" /> <result column="deleted" property="deleted" /> </resultMap> <select id="listPage" resultType="com.ruoyi.approve.bean.vo.ApprovalInstanceVo"> select ai.*,su.nick_name as create_user_name from approval_instance ai left join sys_user su on ai.create_user = su.user_id <where> deleted = 0 <if test="ew.instanceNo != null"> and ai.instance_no like concat('%',#{ew.instanceNo},'%') </if> <if test="ew.templateName != null"> and ai.template_name like concat('%',#{ew.templateName},'%') </if> <if test="ew.templateId != null "> and ai. template_id = #{ew.templateId} </if> <if test="ew.businessType != null "> and ai.business_type = #{ew.businessType} </if> <if test="ew.createTimeStart != null and ew.createTimeEnd != null"> and ai.apply_time >= #{ew.createTimeStart} and ai.apply_time <= #{ew.createTimeEnd} </if> <if test="ew.status != null"> and ai.status = #{ew.status} </if> <if test="ew.applicantName != null and ew.applicantName !=''"> and ai.applicant_name = #{ew.applicantName} </if> </where> order by ai.id desc </select> </mapper> src/main/resources/mapper/approve/ApprovalInstanceNodeMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,21 @@ <?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.ruoyi.approve.mapper.ApprovalInstanceNodeMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalInstanceNode"> <id column="id" property="id" /> <result column="instance_id" property="instanceId" /> <result column="level_no" property="levelNo" /> <result column="approve_type" property="approveType" /> <result column="status" property="status" /> <result column="start_time" property="startTime" /> <result column="finish_time" property="finishTime" /> <result column="create_user" property="createUser" /> <result column="create_time" property="createTime" /> <result column="update_user" property="updateUser" /> <result column="update_time" property="updateTime" /> <result column="deleted" property="deleted" /> </resultMap> </mapper> src/main/resources/mapper/approve/ApprovalRecordMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ <?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.ruoyi.approve.mapper.ApprovalRecordMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalRecord"> <id column="id" property="id" /> <result column="instance_id" property="instanceId" /> <result column="node_id" property="nodeId" /> <result column="task_id" property="taskId" /> <result column="operator_id" property="operatorId" /> <result column="operator_name" property="operatorName" /> <result column="action" property="action" /> <result column="comment" property="comment" /> <result column="create_user" property="createUser" /> <result column="create_time" property="createTime" /> <result column="deleted" property="deleted" /> </resultMap> </mapper> src/main/resources/mapper/approve/ApprovalTaskMapper.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.ruoyi.approve.mapper.ApprovalTaskMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalTask"> <id column="id" property="id" /> <result column="instance_id" property="instanceId" /> <result column="node_id" property="nodeId" /> <result column="level_no" property="levelNo" /> <result column="approver_id" property="approverId" /> <result column="approver_name" property="approverName" /> <result column="task_status" property="taskStatus" /> <result column="approve_time" property="approveTime" /> <result column="comment" property="comment" /> <result column="is_read" property="isRead" /> <result column="create_user" property="createUser" /> <result column="create_time" property="createTime" /> <result column="update_user" property="updateUser" /> <result column="update_time" property="updateTime" /> <result column="deleted" property="deleted" /> </resultMap> </mapper> src/main/resources/mapper/approve/ApprovalTemplateMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,33 @@ <?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.ruoyi.approve.mapper.ApprovalTemplateMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalTemplate"> <id column="id" property="id" /> <result column="template_name" property="templateName" /> <result column="enabled" property="enabled" /> <result column="description" property="description" /> <result column="deleted" property="deleted" /> <result column="dept_id" property="deptId" /> </resultMap> <select id="listPage" resultType="com.ruoyi.approve.bean.vo.ApprovalTemplateVo"> select at.*,su.nick_name as create_user_name from approval_template at left join sys_user su on at.create_user = su.user_id <where> deleted = 0 <if test="ew.templateName != null"> and template_name like concat('%',#{ew.templateName},'%') </if> <if test="ew.templateType != null"> and template_type = #{ew.templateType} </if> <if test="ew.enabled != null"> and enabled = #{ew.enabled} </if> </where> order by at.id desc </select> </mapper> src/main/resources/mapper/approve/ApprovalTemplateNodeApproverMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ <?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.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover"> <id column="id" property="id" /> <result column="node_id" property="nodeId" /> <result column="template_id" property="templateId" /> <result column="approver_id" property="approverId" /> <result column="approver_name" property="approverName" /> <result column="sort_no" property="sortNo" /> <result column="created_time" property="createdTime" /> </resultMap> </mapper> src/main/resources/mapper/approve/ApprovalTemplateNodeMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,15 @@ <?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.ruoyi.approve.mapper.ApprovalTemplateNodeMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.ApprovalTemplateNode"> <id column="id" property="id" /> <result column="template_id" property="templateId" /> <result column="level_no" property="levelNo" /> <result column="approve_type" property="approveType" /> <result column="created_time" property="createdTime" /> <result column="updated_time" property="updatedTime" /> </resultMap> </mapper> src/main/resources/mapper/approve/FinReimbursementDetailMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,29 @@ <?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.ruoyi.approve.mapper.FinReimbursementDetailMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.FinReimbursementDetail"> <id column="id" property="id" /> <result column="reimbursement_id" property="reimbursementId" /> <result column="row_no" property="rowNo" /> <result column="invoice_date" property="invoiceDate" /> <result column="expense_category" property="expenseCategory" /> <result column="amount" property="amount" /> <result column="description" property="description" /> <result column="invoice_no" property="invoiceNo" /> <result column="invoice_type" property="invoiceType" /> <result column="invoice_amount" property="invoiceAmount" /> <result column="tax_rate" property="taxRate" /> <result column="tax_amount" property="taxAmount" /> <result column="remark" property="remark" /> <result column="tenant_id" property="tenantId" /> <result column="create_user" property="createUser" /> <result column="create_time" property="createTime" /> <result column="update_user" property="updateUser" /> <result column="update_time" property="updateTime" /> <result column="dept_id" property="deptId" /> <result column="deleted" property="deleted" /> </resultMap> </mapper> src/main/resources/mapper/approve/FinReimbursementMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,61 @@ <?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.ruoyi.approve.mapper.FinReimbursementMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.FinReimbursement"> <id column="id" property="id" /> <result column="bill_no" property="billNo" /> <result column="reimbursement_type" property="reimbursementType" /> <result column="expense_type" property="expenseType" /> <result column="applicant_id" property="applicantId" /> <result column="applicant_code" property="applicantCode" /> <result column="applicant_name" property="applicantName" /> <result column="applicant_dept_id" property="applicantDeptId" /> <result column="applicant_dept_name" property="applicantDeptName" /> <result column="reason" property="reason" /> <result column="apply_amount" property="applyAmount" /> <result column="detail_total_amount" property="detailTotalAmount" /> <result column="payee_name" property="payeeName" /> <result column="payee_account" property="payeeAccount" /> <result column="payee_bank" property="payeeBank" /> <result column="approval_instance_id" property="approvalInstanceId" /> <result column="approve_process_id" property="approveProcessId" /> <result column="bill_status" property="billStatus" /> <result column="approved_time" property="approvedTime" /> <result column="paid_time" property="paidTime" /> <result column="account_expense_id" property="accountExpenseId" /> <result column="remark" property="remark" /> <result column="tenant_id" property="tenantId" /> <result column="create_user" property="createUser" /> <result column="create_time" property="createTime" /> <result column="update_user" property="updateUser" /> <result column="update_time" property="updateTime" /> <result column="dept_id" property="deptId" /> <result column="deleted" property="deleted" /> </resultMap> <select id="listPage" resultType="com.ruoyi.approve.bean.vo.FinReimbursementVo"> select fin_reimbursement.*, fin_reimbursement_travel.start_time , fin_reimbursement_travel.end_time from fin_reimbursement left join fin_reimbursement_travel on fin_reimbursement.id = fin_reimbursement_travel.reimbursement_id <where> <if test="ew.billNo != null and ew.billNo != ''"> bill_no like concat('%',#{ew.billNo},'%') </if> <if test="ew.applicantName != null and ew.applicantName != ''"> and applicant_name like concat('%',#{ew.applicantName},'%') </if> <if test="ew.applicantCode != null and ew.applicantCode != ''"> and applicant_code like concat('%',#{ew.applicantCode},'%') </if> <if test="ew.createTimeStart != null and ew.createTimeStart !='' and ew.createTimeEnd != null and ew.createTimeEnd != ''"> and create_time >= #{ew.createTimeStart} and create_time <= #{ew.createTimeEnd} </if> </where> </select> </mapper> src/main/resources/mapper/approve/FinReimbursementTravelMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,29 @@ <?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.ruoyi.approve.mapper.FinReimbursementTravelMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.approve.pojo.FinReimbursementTravel"> <id column="id" property="id" /> <result column="reimbursement_id" property="reimbursementId" /> <result column="start_time" property="startTime" /> <result column="end_time" property="endTime" /> <result column="travel_days" property="travelDays" /> <result column="departure_city" property="departureCity" /> <result column="destination_city" property="destinationCity" /> <result column="hotel_standard" property="hotelStandard" /> <result column="lodging_days" property="lodgingDays" /> <result column="meal_allowance" property="mealAllowance" /> <result column="transport_allowance" property="transportAllowance" /> <result column="lodging_limit" property="lodgingLimit" /> <result column="standard_tag" property="standardTag" /> <result column="within_standard" property="withinStandard" /> <result column="tenant_id" property="tenantId" /> <result column="create_user" property="createUser" /> <result column="create_time" property="createTime" /> <result column="update_user" property="updateUser" /> <result column="update_time" property="updateTime" /> <result column="dept_id" property="deptId" /> </resultMap> </mapper> src/main/resources/mapper/collaborativeApproval/EnterpriseNewsMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,46 @@ <?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.ruoyi.collaborativeApproval.mapper.EnterpriseNewsMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.collaborativeApproval.pojo.EnterpriseNews"> <id column="id" property="id" /> <result column="title" property="title" /> <result column="summary" property="summary" /> <result column="content" property="content" /> <result column="category" property="category" /> <result column="read_scope" property="readScope" /> <result column="is_required" property="isRequired" /> <result column="status" property="status" /> <result column="required_read_count" property="requiredReadCount" /> <result column="read_count" property="readCount" /> <result column="create_user" property="createUser" /> <result column="create_time" property="createTime" /> <result column="update_user" property="updateUser" /> <result column="update_time" property="updateTime" /> <result column="dept_id" property="deptId" /> </resultMap> <select id="listPage" resultType="com.ruoyi.collaborativeApproval.vo.EnterpriseNewsVo"> select en.*, u.nick_name as create_user_name from enterprise_news en left join sys_user u on en.create_user = u.user_id <where> <if test="enterpriseNewsDto.title != null and enterpriseNewsDto.title != ''"> and en.title like concat('%',#{enterpriseNewsDto.title},'%') </if> <if test="enterpriseNewsDto.category != null and enterpriseNewsDto.category != ''"> and en.category = #{enterpriseNewsDto.category} </if> <if test="enterpriseNewsDto.status != null "> and en.status = #{enterpriseNewsDto.status} </if> <if test="enterpriseNewsDto.createUser != null and enterpriseNewsDto.createUser != ''"> and en.create_user = #{enterpriseNewsDto.createUser} </if> <if test="enterpriseNewsDto.createTimeStart != null and enterpriseNewsDto.createTimeEnd != null"> and en.create_time between #{enterpriseNewsDto.createTimeStart} and #{enterpriseNewsDto.createTimeEnd} </if> </where> </select> </mapper> src/main/resources/mapper/collaborativeApproval/EnterpriseNewsScopeDeptMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,13 @@ <?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.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeDeptMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept"> <id column="id" property="id" /> <result column="news_id" property="newsId" /> <result column="dept_id" property="deptId" /> <result column="create_time" property="createTime" /> </resultMap> </mapper> src/main/resources/mapper/collaborativeApproval/EnterpriseNewsScopeUserMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,13 @@ <?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.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeUserMapper"> <!-- éç¨æ¥è¯¢æ å°ç»æ --> <resultMap id="BaseResultMap" type="com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser"> <id column="id" property="id" /> <result column="news_id" property="newsId" /> <result column="user_id" property="userId" /> <result column="create_time" property="createTime" /> </resultMap> </mapper> src/main/resources/mapper/staff/StaffLeaveMapper.xml
@@ -18,15 +18,20 @@ soj.emergency_contact as emergencyContact, soj.emergency_contact_phone as emergencyContactPhone, sp.post_name as postName, sd.dept_name as deptName sd.dept_name as deptName, se.education as first_study, se.major as profession FROM staff_leave LEFT JOIN staff_on_job soj ON soj.id = staff_leave.staff_on_job_id LEFT JOIN sys_post sp ON sp.post_id = soj.sys_post_id LEFT JOIN sys_dept sd ON sd.dept_id = soj.sys_dept_id where 1=1 LEFT JOIN staff_on_job soj ON soj.id = staff_leave.staff_on_job_id LEFT JOIN sys_post sp ON sp.post_id = soj.sys_post_id LEFT JOIN sys_dept sd ON sd.dept_id = soj.sys_dept_id LEFT JOIN staff_education se ON se.staff_on_job_id = staff_leave.staff_on_job_id AND se.id = ( SELECT MAX(se2.id) FROM staff_education se2 WHERE se2.staff_on_job_id = staff_leave.staff_on_job_id ) WHERE 1=1 <if test="c.staffName != null and c.staffName != '' "> AND soj.staff_name LIKE CONCAT('%',#{c.staffName},'%') </if> src/main/resources/mapper/staff/StaffOnJobMapper.xml
@@ -3,29 +3,82 @@ <mapper namespace="com.ruoyi.staff.mapper.StaffOnJobMapper"> <select id="staffOnJobListPage" resultType="com.ruoyi.staff.dto.StaffOnJobDto"> SELECT staff_on_job.*, sp.post_name as postName, sd.dept_name as deptName, MIN(t1.contract_start_time) as contract_start_time, -- åææ©ååå¼å§æ¶é´ MAX(t1.contract_end_time) as contract_end_time staff_on_job.id, staff_on_job.staff_state, staff_on_job.staff_no, staff_on_job.staff_name, staff_on_job.sex, staff_on_job.native_place, staff_on_job.sys_post_id, staff_on_job.sys_dept_id, staff_on_job.role_id, staff_on_job.adress, staff_on_job.first_study, staff_on_job.profession, staff_on_job.identity_card, staff_on_job.age, staff_on_job.phone, staff_on_job.contract_term, staff_on_job.contract_expire_time, staff_on_job.trial_end_date, staff_on_job.trial_start_date, staff_on_job.sign_date, staff_on_job.salary_select, staff_on_job.pro_salary, staff_on_job.date_select, staff_on_job.remark, staff_on_job.create_time, staff_on_job.create_user, staff_on_job.update_time, staff_on_job.update_user, staff_on_job.tenant_id, staff_on_job.alias, staff_on_job.birth_date, staff_on_job.nation, staff_on_job.marital_status, staff_on_job.pro_term, staff_on_job.positive_date, staff_on_job.basic_salary, staff_on_job.dept_id, sp.post_name AS post_name, sd.dept_name AS dept_name, MIN(t1.contract_start_time) AS contract_start_time, MAX(t1.contract_end_time) AS contract_end_time, ( SELECT GROUP_CONCAT(sec.contact_name SEPARATOR ',') FROM staff_emergency_contact sec WHERE sec.staff_on_job_id = staff_on_job.id ) AS emergency_contact, ( SELECT GROUP_CONCAT(sec.contact_phone SEPARATOR ',') FROM staff_emergency_contact sec WHERE sec.staff_on_job_id = staff_on_job.id ) AS emergency_contact_phone FROM staff_on_job LEFT JOIN sys_post sp ON sp.post_id = staff_on_job.sys_post_id LEFT JOIN sys_dept sd ON sd.dept_id = staff_on_job.sys_dept_id LEFT JOIN staff_contract as t1 ON t1.staff_on_job_id = staff_on_job.id WHERE 1=1 <if test="staffOnJob.staffState != null"> AND staff_state = #{staffOnJob.staffState} </if> <if test="staffOnJob.staffName != null and staffOnJob.staffName != '' "> AND staff_name LIKE CONCAT('%',#{staffOnJob.staffName},'%') </if> <if test="staffOnJob.entryDateStart != null and staffOnJob.entryDateStart != '' "> AND contract_expire_time >= DATE_FORMAT(#{staffOnJob.entryDateStart},'%Y-%m-%d') </if> <if test="staffOnJob.entryDateEnd != null and staffOnJob.entryDateEnd != '' "> AND contract_expire_time <= DATE_FORMAT(#{staffOnJob.entryDateEnd},'%Y-%m-%d') </if> LEFT JOIN staff_contract AS t1 ON t1.staff_on_job_id = staff_on_job.id <where> <if test="staffOnJob.staffState != null"> AND staff_on_job.staff_state = #{staffOnJob.staffState} </if> <if test="staffOnJob.staffName != null and staffOnJob.staffName != '' "> AND staff_on_job.staff_name LIKE CONCAT('%',#{staffOnJob.staffName},'%') </if> <if test="staffOnJob.entryDateStart != null and staffOnJob.entryDateStart != '' "> AND staff_on_job.contract_expire_time >= DATE_FORMAT(#{staffOnJob.entryDateStart},'%Y-%m-%d') </if> <if test="staffOnJob.entryDateEnd != null and staffOnJob.entryDateEnd != '' "> AND staff_on_job.contract_expire_time <= DATE_FORMAT(#{staffOnJob.entryDateEnd},'%Y-%m-%d') </if> <if test="staffOnJob.sysDeptId != null"> AND staff_on_job.sys_dept_id = #{staffOnJob.sysDeptId} </if> </where> GROUP BY staff_on_job.id <if test="staffOnJob.contractStartTime != null"> HAVING MIN(t1.contract_start_time) = #{staffOnJob.contractStartTime} </if> </select> <select id="staffOnJobList" resultType="com.ruoyi.staff.dto.StaffOnJobDto"> SELECT src/main/resources/mapper/system/SysNoticeMapper.xml
@@ -10,11 +10,16 @@ <result property="noticeType" column="notice_type" /> <result property="noticeContent" column="notice_content" /> <result property="status" column="status" /> <result property="senderId" column="sender_id" /> <result property="consigneeId" column="consignee_id" /> <result property="jumpPath" column="jump_path" /> <result property="appJumpPath" column="app_jump_path" /> <result property="createBy" column="create_by" /> <result property="createTime" column="create_time" /> <result property="updateBy" column="update_by" /> <result property="updateTime" column="update_time" /> <result property="remark" column="remark" /> <result property="tenantId" column="tenant_id" /> </resultMap> <sql id="selectNoticeVo">