buhuazhen
4 天以前 b36dfcb807af748dabdbc76a134b0667196563f6
feat(projectManagement): 完善项目信息管理功能

- 在多个实体类中新增创建人和更新人名称字段支持自动填充
- 扩展ContractInfoHandleService、ShippingAddressHandleService,新增根据infoId查询方法
- InfoController新增项目保存、状态更新、删除、分页查询和详情接口
- InfoService及实现类添加状态更新、删除、分页查询和详细信息获取功能
- 使用CompletableFuture优化项目详情数据异步加载
- InfoMapper及XML实现分页列表查询功能,支持多条件过滤
- 新增UpdateStateInfo、SearchInfoVo、ListInfoVo等数据传输对象
- 添加IsDeleteEnum,支持逻辑删除标识语义化
- MybatisHandler新增用户名称自动填充逻辑
- SalesLedgerService新增根据关联ID及类型获取销售产品列表功能
- DTO及VO中增强校验注解及属性定义,完善附件与团队相关字段管理
已添加5个文件
已修改21个文件
466 ■■■■■ 文件已修改
src/main/java/com/ruoyi/common/config/MybatisHandler.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/BaseEnum.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/IsDeleteEnum.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/PlanStageEnum.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/controller/InfoController.java 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/dto/SaveInfoDto.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/dto/UpdateStateInfo.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/mapper/InfoMapper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/pojo/ContractInfo.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/pojo/Info.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/pojo/Plan.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/pojo/PlanNode.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/pojo/ShippingAddress.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/service/InfoService.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/service/impl/InfoServiceImpl.java 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/service/impl/handle/ContractInfoHandleService.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoHandleService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/service/impl/handle/ShippingAddressHandleService.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/vo/InfoVo.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/vo/ListInfoVo.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/vo/SavePlanNodeVo.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/vo/SavePlanVo.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/projectManagement/vo/SearchInfoVo.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/projectManagement/InfoMapper.xml 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/config/MybatisHandler.java
@@ -14,9 +14,11 @@
    public void insertFill(MetaObject metaObject) {
        Integer userId = null;
        Long tenantId = null;
        String userName = null;
        try {
            userId = SecurityUtils.getUserId().intValue();
            tenantId = SecurityUtils.getLoginUser().getTenantId();
            userName = SecurityUtils.getUsername();
        } catch (Exception ignored) {
        }
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
@@ -25,6 +27,9 @@
        this.strictInsertFill(metaObject, "updateUser", Integer.class, userId);
        this.strictInsertFill(metaObject, "createUser", Long.class, userId == null ? 0 : userId.longValue());
        this.strictInsertFill(metaObject, "updateUser", Long.class, userId == null ? 0 : userId.longValue());
        this.strictInsertFill(metaObject, "createUserName", String.class, userName);
        this.strictInsertFill(metaObject, "updateUserName", String.class, userName);
        this.strictInsertFill(metaObject, "tenantId", Long.class, tenantId);
    }
src/main/java/com/ruoyi/common/enums/BaseEnum.java
@@ -1,6 +1,7 @@
package com.ruoyi.common.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
src/main/java/com/ruoyi/common/enums/IsDeleteEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.ruoyi.common.enums;
import lombok.Getter;
/**
 * @author buhuazhen
 * @date 2026/3/10
 * @email 3038525872@qq.com
 */
@Getter
public enum IsDeleteEnum implements BaseEnum<Integer> {
    NOT_DELETED(0, "未删除"),
    DELETED(1, "已删除");
    private final Integer code;
    private final String value;
    IsDeleteEnum(Integer code, String value) {
        this.code = code;
        this.value = value;
    }
}
src/main/java/com/ruoyi/common/enums/PlanStageEnum.java
@@ -1,5 +1,6 @@
package com.ruoyi.common.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.Getter;
@@ -15,12 +16,18 @@
    TO_BEGIN(1, "待开始"),
    ON_GOING(2, "进行中"),
    ENDED(3, "已结束");
    @EnumValue
    private final Integer code;
    private final String value;
    PlanStageEnum(Integer code, String value) {
        this.code = code;
        this.value = value;
    }
    @JsonCreator
    public static PlanStageEnum fromCode(Integer code) {
        return BaseEnum.fromCode(PlanStageEnum.class, code);
    }
}
src/main/java/com/ruoyi/projectManagement/controller/InfoController.java
@@ -1,14 +1,14 @@
package com.ruoyi.projectManagement.controller;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.projectManagement.dto.UpdateStateInfo;
import com.ruoyi.projectManagement.service.InfoService;
import com.ruoyi.projectManagement.vo.SaveInfoVo;
import com.ruoyi.projectManagement.vo.SearchInfoVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@@ -26,8 +26,38 @@
    private final InfoService infoService;
    @PostMapping("/save")
    @ApiOperation("保存")
    public AjaxResult save(@RequestBody @Valid SaveInfoVo saveInfoVo) {
        infoService.save(saveInfoVo);
        return AjaxResult.success();
    }
    @PostMapping("/updateStatus")
    @ApiOperation("修改状态")
    public AjaxResult updateStatus(@RequestBody @Valid UpdateStateInfo updateStateInfo){
        infoService.updateStatus(updateStateInfo);
        return AjaxResult.success();
    }
    @PostMapping("/delete/{id}")
    @ApiOperation("删除")
    public AjaxResult delete(@PathVariable Long id) {
        infoService.deleteInfo(id);
        return AjaxResult.success();
    }
    @PostMapping("/listPage")
    @ApiOperation("分页列表")
    public AjaxResult listPage(@RequestBody @Valid SearchInfoVo vo) {
        return AjaxResult.success(infoService.searchListInfo(vo));
    }
    @PostMapping("/{id}")
    @ApiOperation("详情")
    public AjaxResult getInfoById(@PathVariable Long id) {
        return AjaxResult.success(infoService.getInfoById(id));
    }
}
src/main/java/com/ruoyi/projectManagement/dto/SaveInfoDto.java
@@ -1,6 +1,8 @@
package com.ruoyi.projectManagement.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.ruoyi.common.vo.SimpleFileVo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -24,7 +26,7 @@
public class SaveInfoDto implements Serializable {
    private Long id;
    private String no;
    @NotBlank
    @NotBlank(message = "title为空")
    private String title;
    private Long clientId;
    private String clientName;
@@ -35,7 +37,7 @@
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate establishTime;
    // é¡¹ç›®ç±»åž‹ id
    @NotNull
    @NotNull(message = "projectManagementPlanId为空")
    private Long projectManagementPlanId;
    private String source;
@@ -43,7 +45,7 @@
    private Long managerId;
    private String managerName;
    private Long salesmanId;
        private String salesmanName;
    private String salesmanName;
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
@@ -61,6 +63,9 @@
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate actualEndTime;
    // å®¡æ ¸çŠ¶æ€
    private Integer reviewStatus;
    // é¡¹ç›®çŠ¶æ€
    private Integer status;
@@ -76,7 +81,14 @@
    private String remark;
    @JsonIgnore
    private String attachment;
    private List<SimpleFileVo> attachmentList;
    private List<String> attachmentIds; // é™„ä»¶ids
    private List<TeamDto> teamList;
    private List<PlanStageDto> planStage;
}
src/main/java/com/ruoyi/projectManagement/dto/UpdateStateInfo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.ruoyi.projectManagement.dto;
import com.ruoyi.common.enums.PlanStageEnum;
import com.ruoyi.common.enums.ReviewStatusEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
 * @author buhuazhen
 * @date 2026/3/10
 * @email 3038525872@qq.com
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UpdateStateInfo implements Serializable {
    @NotNull(message = "id不能为空")
    private Long id;
    // å®¡æ‰¹çŠ¶æ€
    private ReviewStatusEnum reviewStatus;
    // è¿›åº¦çŠ¶æ€
    private PlanStageEnum stage;
}
src/main/java/com/ruoyi/projectManagement/mapper/InfoMapper.java
@@ -1,7 +1,11 @@
package com.ruoyi.projectManagement.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.projectManagement.pojo.Info;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.projectManagement.vo.ListInfoVo;
import com.ruoyi.projectManagement.vo.SearchInfoVo;
import org.apache.ibatis.annotations.Param;
/**
* @author buhuazhen
@@ -11,6 +15,7 @@
*/
public interface InfoMapper extends BaseMapper<Info> {
    Page<ListInfoVo> searchListInfo(@Param("vo") SearchInfoVo vo);
}
src/main/java/com/ruoyi/projectManagement/pojo/ContractInfo.java
@@ -127,6 +127,12 @@
    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @TableField(value = "create_user_name", fill = FieldFill.INSERT)
    private String createUserName;
    @TableField(value = "update_user_name", fill = FieldFill.INSERT_UPDATE)
    private String updateUserName;
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}
src/main/java/com/ruoyi/projectManagement/pojo/Info.java
@@ -207,4 +207,10 @@
    @TableField(value = "team",typeHandler = JacksonTypeHandler.class)
    private List<TeamDto> team;
    @TableField(value = "create_user_name", fill = FieldFill.INSERT)
    private String createUserName;
    @TableField(value = "update_user_name", fill = FieldFill.INSERT_UPDATE)
    private String updateUserName;
}
src/main/java/com/ruoyi/projectManagement/pojo/Plan.java
@@ -81,4 +81,10 @@
    @TableField(value = "update_user",fill = FieldFill.INSERT_UPDATE)
    @ApiModelProperty(value="更新人")
    private Integer updateUser;
    @TableField(value = "create_user_name", fill = FieldFill.INSERT)
    private String createUserName;
    @TableField(value = "update_user_name", fill = FieldFill.INSERT_UPDATE)
    private String updateUserName;
}
src/main/java/com/ruoyi/projectManagement/pojo/PlanNode.java
@@ -99,6 +99,12 @@
    @TableField(value = "update_user",fill = FieldFill.INSERT_UPDATE)
    private Integer updateUser;
    @TableField(value = "create_user_name", fill = FieldFill.INSERT)
    private String createUserName;
    @TableField(value = "update_user_name", fill = FieldFill.INSERT_UPDATE)
    private String updateUserName;
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}
src/main/java/com/ruoyi/projectManagement/pojo/ShippingAddress.java
@@ -70,6 +70,13 @@
    @TableField(value = "project_management_info_id")
    private Long projectManagementInfoId;
    @TableField(value = "create_user_name", fill = FieldFill.INSERT)
    private String createUserName;
    @TableField(value = "update_user_name", fill = FieldFill.INSERT_UPDATE)
    private String updateUserName;
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}
src/main/java/com/ruoyi/projectManagement/service/InfoService.java
@@ -1,6 +1,11 @@
package com.ruoyi.projectManagement.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.projectManagement.dto.UpdateStateInfo;
import com.ruoyi.projectManagement.vo.InfoVo;
import com.ruoyi.projectManagement.vo.ListInfoVo;
import com.ruoyi.projectManagement.vo.SaveInfoVo;
import com.ruoyi.projectManagement.vo.SearchInfoVo;
import javax.validation.constraints.NotNull;
@@ -10,6 +15,35 @@
 * @email 3038525872@qq.com
 */
public interface InfoService {
    /**
     * ä¿å­˜é¡¹ç›®ä¿¡æ¯
     *
     * @param saveInfoVo ä¿å­˜é¡¹ç›®ä¿¡æ¯çš„DTO
     */
    void save(@NotNull SaveInfoVo saveInfoVo);
    /**
     * æ›´æ–°é¡¹ç›®ä¿¡æ¯çŠ¶æ€
     *
     * @param updateStateInfo æ›´æ–°é¡¹ç›®ä¿¡æ¯çŠ¶æ€çš„DTO
     */
    void updateStatus(@NotNull UpdateStateInfo updateStateInfo);
    /**
     * åˆ é™¤é¡¹ç›®ä¿¡æ¯
     *
     * @param id é¡¹ç›®ä¿¡æ¯ID
     */
    void deleteInfo(@NotNull Long id);
    /**
     * åˆ†é¡µæŸ¥è¯¢é¡¹ç›®ä¿¡æ¯åˆ—表
     *
     * @param vo æŸ¥è¯¢æ¡ä»¶
     * @return é¡¹ç›®ä¿¡æ¯åˆ—表
     */
    Page<ListInfoVo> searchListInfo(@NotNull SearchInfoVo vo);
    InfoVo getInfoById(@NotNull Long id);
}
src/main/java/com/ruoyi/projectManagement/service/impl/InfoServiceImpl.java
@@ -1,15 +1,32 @@
package com.ruoyi.projectManagement.service.impl;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.enums.IsDeleteEnum;
import com.ruoyi.common.enums.SaleEnum;
import com.ruoyi.projectManagement.dto.ContractInfoDto;
import com.ruoyi.projectManagement.dto.SaveInfoDto;
import com.ruoyi.projectManagement.dto.ShippingAddressDto;
import com.ruoyi.projectManagement.dto.UpdateStateInfo;
import com.ruoyi.projectManagement.mapper.InfoMapper;
import com.ruoyi.projectManagement.pojo.Info;
import com.ruoyi.projectManagement.service.InfoService;
import com.ruoyi.projectManagement.service.impl.handle.ContractInfoHandleService;
import com.ruoyi.projectManagement.service.impl.handle.InfoHandleService;
import com.ruoyi.projectManagement.service.impl.handle.ShippingAddressHandleService;
import com.ruoyi.projectManagement.vo.InfoVo;
import com.ruoyi.projectManagement.vo.ListInfoVo;
import com.ruoyi.projectManagement.vo.SaveInfoVo;
import com.ruoyi.projectManagement.vo.SearchInfoVo;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.service.ISalesLedgerService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
 * @author buhuazhen
@@ -21,17 +38,90 @@
@Transactional(readOnly = true)
public class InfoServiceImpl implements InfoService {
    private final InfoHandleService infoHandleService;
    private final InfoMapper infoMapper;
    private final ContractInfoHandleService contractInfoHandleService;
    private final ShippingAddressHandleService shippingAddressHandleService;
    private final ISalesLedgerService salesLedgerService;
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(SaveInfoVo saveInfoVo) {
        // ä¿å­˜ä¸»ä¿¡æ¯
        Long infoId = infoHandleService.save(saveInfoVo.getInfo());
        shippingAddressHandleService.save(infoId, saveInfoVo.getShippingAddress());
        contractInfoHandleService.save(infoId, saveInfoVo.getContractInfo());
        salesLedgerService.handleSalesLedgerProducts(infoId, saveInfoVo.getSalesLedgerProductList(), SaleEnum.MANAGEMENT);
        if(saveInfoVo.getShippingAddress() != null){
            shippingAddressHandleService.save(infoId, saveInfoVo.getShippingAddress());
        }
        if(saveInfoVo.getContractInfo() != null){
            contractInfoHandleService.save(infoId, saveInfoVo.getContractInfo());
        }
        if(saveInfoVo.getSalesLedgerProductList() != null){
            salesLedgerService.handleSalesLedgerProducts(infoId, saveInfoVo.getSalesLedgerProductList(), SaleEnum.MANAGEMENT);
        }
    }
    @Override
    @Transactional
    public void updateStatus(UpdateStateInfo updateStateInfo) {
        Info info = new Info();
        info.setId(updateStateInfo.getId());
        // å®¡æ‰¹çŠ¶æ€
        if(updateStateInfo.getReviewStatus() != null){
            info.setReviewStatus(updateStateInfo.getReviewStatus().getCode());
        }
        // è¿›åº¦çŠ¶æ€
        if(updateStateInfo.getStage() != null){
            info.setStatus(updateStateInfo.getStage().getCode());
        }
        infoMapper.updateById(info);
    }
    @Override
    @Transactional
    public void deleteInfo(Long id) {
        LambdaUpdateWrapper<Info> updateWrapper = new LambdaUpdateWrapper<Info>();
        updateWrapper.eq(Info::getId, id);
        updateWrapper.set(Info::getIsDelete, IsDeleteEnum.DELETED.getCode());
        // å¯¹åº”附表信息是否删除待确定(因为后续可能会进行引用所以先不删除
    }
    @Override
    public Page<ListInfoVo> searchListInfo(SearchInfoVo vo) {
        Page<ListInfoVo> listInfoVoPage = infoMapper.searchListInfo(vo);
        return listInfoVoPage;
    }
    @Override
    @SneakyThrows
    public InfoVo getInfoById(Long id) {
        CompletableFuture<SaveInfoDto> infoFuture = CompletableFuture.supplyAsync(() -> infoHandleService.getInfoById(id));
        CompletableFuture<ContractInfoDto> contractFuture = CompletableFuture.supplyAsync(() -> contractInfoHandleService.getByInfoId(id));
        CompletableFuture<ShippingAddressDto> shippingFuture = CompletableFuture.supplyAsync(() -> shippingAddressHandleService.getByInfoId(id));
        CompletableFuture<List<SalesLedgerProduct>> listCompletableFuture = CompletableFuture.supplyAsync(() -> salesLedgerService.getSalesLedgerProductListByRelateId(id,SaleEnum.MANAGEMENT));
        // å•†å“
        // ç­‰å¾…所有异步完成
        CompletableFuture.allOf(infoFuture, contractFuture, shippingFuture).join();
        SaveInfoDto info = infoFuture.get();
        ContractInfoDto contract = contractFuture.get();
        ShippingAddressDto shippingAddress = shippingFuture.get();
        List<SalesLedgerProduct> salesLedgerProductList = listCompletableFuture.get();
        InfoVo vo = new InfoVo();
        vo.setInfo(info);
        vo.setContractInfo(contract);
        vo.setShippingAddress(shippingAddress);
        vo.setSalesLedgerProductList(salesLedgerProductList);
        return vo;
    }
}
src/main/java/com/ruoyi/projectManagement/service/impl/handle/ContractInfoHandleService.java
@@ -1,6 +1,7 @@
package com.ruoyi.projectManagement.service.impl.handle;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.projectManagement.dto.ContractInfoDto;
import com.ruoyi.projectManagement.mapper.ContractInfoMapper;
import com.ruoyi.projectManagement.pojo.ContractInfo;
@@ -34,4 +35,14 @@
            contractInfoMapper.updateById(contractInfo);
        }
    }
    public ContractInfoDto getByInfoId(@NotNull Long id) {
        LambdaQueryWrapper<ContractInfo> queryWrapper = new LambdaQueryWrapper<ContractInfo>();
        queryWrapper.eq(ContractInfo::getProjectManagementInfoId, id);
        queryWrapper.eq(ContractInfo::getIsDelete, 0);
        queryWrapper.last("limit 1");
        ContractInfo contractInfo = contractInfoMapper.selectOne(queryWrapper);
        return BeanUtil.copyProperties(contractInfo, ContractInfoDto.class);
    }
}
src/main/java/com/ruoyi/projectManagement/service/impl/handle/InfoHandleService.java
@@ -4,6 +4,8 @@
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.ruoyi.basic.service.CustomerFollowUpFileService;
import com.ruoyi.common.enums.PlanStageEnum;
import com.ruoyi.common.enums.ReviewStatusEnum;
import com.ruoyi.common.utils.EnumUtil;
@@ -14,6 +16,7 @@
import com.ruoyi.projectManagement.pojo.PlanNode;
import com.ruoyi.projectManagement.service.PlanService;
import com.ruoyi.projectManagement.service.impl.PlanServiceImpl;
import com.ruoyi.projectManagement.vo.PlanVo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@@ -40,6 +43,8 @@
    private final PlanService planService;
    private final CustomerFollowUpFileService customerFollowUpFileService;
    @Transactional(rollbackFor = Exception.class)
    public Long save(@NotNull SaveInfoDto saveInfoDto){
        Info info = BeanUtil.copyProperties(saveInfoDto, Info.class);
@@ -66,6 +71,15 @@
        return info.getId();
    }
    public SaveInfoDto getInfoById(@NotNull Long id){
        Info info = infoMapper.selectById(id);
        SaveInfoDto saveInfoDto = BeanUtil.copyProperties(info, SaveInfoDto.class);
        // é™„件处理
        saveInfoDto.setTeamList(info.getTeam());
        customerFollowUpFileService.fillAttachment(Lists.newArrayList(saveInfoDto), SaveInfoDto::getAttachment, SaveInfoDto::setAttachmentList);
        return saveInfoDto;
    }
    private List<PlanStageDto> getPlanStageList(@NotNull Long planId) {
        List<PlanNode> planNodeByPlanId = planService.getPlanNodeByPlanId(planId);
src/main/java/com/ruoyi/projectManagement/service/impl/handle/ShippingAddressHandleService.java
@@ -1,6 +1,7 @@
package com.ruoyi.projectManagement.service.impl.handle;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.projectManagement.dto.ShippingAddressDto;
import com.ruoyi.projectManagement.mapper.ShippingAddressMapper;
import com.ruoyi.projectManagement.pojo.ShippingAddress;
@@ -33,4 +34,14 @@
            shippingAddressMapper.updateById(shippingAddress);
        }
    }
    public ShippingAddressDto getByInfoId(@NotNull Long id) {
        LambdaQueryWrapper<ShippingAddress> queryWrapper = new LambdaQueryWrapper<ShippingAddress>();
        queryWrapper.eq(ShippingAddress::getProjectManagementInfoId, id);
        queryWrapper.eq(ShippingAddress::getIsDelete, 0);
        queryWrapper.last("limit 1");
        ShippingAddress shippingAddress = shippingAddressMapper.selectOne(queryWrapper);
        return BeanUtil.copyProperties(shippingAddress, ShippingAddressDto.class);
    }
}
src/main/java/com/ruoyi/projectManagement/vo/InfoVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.projectManagement.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
 * @author buhuazhen
 * @date 2026/3/10
 * @email 3038525872@qq.com
 */
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class InfoVo extends SaveInfoVo implements Serializable {
    // é¡¹ç›®é˜¶æ®µ
    private String xxx;
}
src/main/java/com/ruoyi/projectManagement/vo/ListInfoVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
package com.ruoyi.projectManagement.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.projectManagement.dto.SaveInfoDto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * é¡µé¢åˆ—表信息
 *
 * @author buhuazhen
 * @date 2026/3/10
 * @email 3038525872@qq.com
 */
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ListInfoVo extends SaveInfoDto implements Serializable {
    // å¯¹åº”项目类型名称
    private String projectManagementPlanName;
    // å¯¹åº”父项目名称
    private String projectManagementInfoParentName;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime; // åˆ›å»ºæ—¶é—´
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime; // æ›´æ–°æ—¶é—´
    private String createUserName; // åˆ›å»ºäººåç§°
    private String updateUserName; // æ›´æ–°äººåç§°
}
src/main/java/com/ruoyi/projectManagement/vo/SavePlanNodeVo.java
@@ -23,13 +23,13 @@
    private Integer sort;
    @NotBlank
    @NotBlank(message = "name不能为空")
    private String name;
    @NotNull
    @NotNull(message = "leaderId不能为空")
    private Long leaderId;
    @NotBlank
    @NotBlank(message = "leaderName不能为空")
    private String leaderName;
    private Integer estimatedDuration;
src/main/java/com/ruoyi/projectManagement/vo/SavePlanVo.java
@@ -22,7 +22,7 @@
public class SavePlanVo implements Serializable {
    private Long id;
    @NotBlank
    @NotBlank(message = "name不能为空")
    private String name;
//    @NotBlank
    private String description;
src/main/java/com/ruoyi/projectManagement/vo/SearchInfoVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
package com.ruoyi.projectManagement.vo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.enums.PlanStageEnum;
import com.ruoyi.common.enums.ReviewStatusEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
 * @author buhuazhen
 * @date 2026/3/10
 * @email 3038525872@qq.com
 */
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SearchInfoVo extends Page implements Serializable {
    private String noOrName; // é¡¹ç›®ç¼–号或项目名称
    private String clientName; // å®¢æˆ·åç§°
    private String salesmanName; // ä¸šåŠ¡å‘˜
    // å®¡æ‰¹çŠ¶æ€
    private ReviewStatusEnum reviewStatus;
    // è¿›åº¦çŠ¶æ€
    private PlanStageEnum stage;
}
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
@@ -13,6 +13,7 @@
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.List;
@@ -30,6 +31,8 @@
    int addOrUpdateSalesLedger(SalesLedgerDto salesLedgerDto);
    List<SalesLedgerProduct> getSalesLedgerProductListByRelateId(@NotNull Long relateId,@NotNull SaleEnum type);
    void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, SaleEnum type);
    SalesLedgerDto getSalesLedgerWithProducts(SalesLedgerDto salesLedgerDto);
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -160,6 +160,14 @@
        return salesLedgerMapper.selectSalesLedgerList(salesLedgerDto);
    }
    public List<SalesLedgerProduct> getSalesLedgerProductListByRelateId(Long relateId, SaleEnum type){
        LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>();
        productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, relateId);
        productWrapper.eq(SalesLedgerProduct::getType, type.getCode());
        return salesLedgerProductMapper.selectList(productWrapper);
    }
    @Override
    public SalesLedgerDto getSalesLedgerWithProducts(SalesLedgerDto salesLedgerDto) {
        // 1. æŸ¥è¯¢ä¸»è¡¨
src/main/resources/mapper/projectManagement/InfoMapper.xml
@@ -48,4 +48,27 @@
        department_name,order_date,order_amount,
        remark,attachment
    </sql>
    <select id="searchListInfo" resultType="com.ruoyi.projectManagement.vo.ListInfoVo">
        select t1.*, t2.name as project_management_plan_name,t3.title as projectManagementInfoParentName
        from project_management_info as t1
        left join project_management_plan as t2 on t1.project_management_plan_id = t2.id
        left join project_management_info as t3 on t1.project_management_info_parent_id = t3.id
        where t1.is_delete = 0
        <if test="vo.noOrName != null and vo.noOrName != ''">
            and ( t1.no like concat('%', #{vo.noOrName}, '%') OR t1.title like concat('%', #{vo.noOrName}, '%') )
        </if>
        <if test="vo.clientName != null and vo.clientName != ''">
            and t1.client_name like concat('%', #{vo.clientName}, '%')
        </if>
        <if test="vo.salesmanName != null and vo.salesmanName != ''">
            and t1.salesman_name like concat('%', #{vo.salesmanName}, '%')
        </if>
        <if test="vo.reviewStatus != null">
            and t1.review_status = #{vo.reviewStatus.code}
        </if>
        <if test="vo.stage != null">
            and t1.stage = #{vo.stage.code}
        </if>
        order by t1.create_time desc
    </select>
</mapper>