diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaArrivalDetailController.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaArrivalDetailController.java new file mode 100644 index 0000000..cecd139 --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaArrivalDetailController.java @@ -0,0 +1,101 @@ +package com.ruoyi.oa.controller; + +import java.util.List; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import lombok.RequiredArgsConstructor; +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.*; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.PageQuery; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.core.validate.QueryGroup; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.oa.domain.vo.OaArrivalDetailVo; +import com.ruoyi.oa.domain.bo.OaArrivalDetailBo; +import com.ruoyi.oa.service.IOaArrivalDetailService; +import com.ruoyi.common.core.page.TableDataInfo; + +/** + * 到货明细 + * + * @author ruoyi + * @date 2026-06-12 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/oa/arrivalDetail") +public class OaArrivalDetailController extends BaseController { + + private final IOaArrivalDetailService iOaArrivalDetailService; + + /** + * 查询到货明细列表 + */ + @GetMapping("/list") + public TableDataInfo list(OaArrivalDetailBo bo, PageQuery pageQuery) { + return iOaArrivalDetailService.queryPageList(bo, pageQuery); + } + + /** + * 导出到货明细列表 + */ + @Log(title = "到货明细", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(OaArrivalDetailBo bo, HttpServletResponse response) { + List list = iOaArrivalDetailService.queryList(bo); + ExcelUtil.exportExcel(list, "到货明细", OaArrivalDetailVo.class, response); + } + + /** + * 获取到货明细详细信息 + * + * @param detailId 主键 + */ + @GetMapping("/{detailId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long detailId) { + return R.ok(iOaArrivalDetailService.queryById(detailId)); + } + + /** + * 新增到货明细 + */ + @Log(title = "到货明细", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody OaArrivalDetailBo bo) { + return toAjax(iOaArrivalDetailService.insertByBo(bo)); + } + + /** + * 修改到货明细 + */ + @Log(title = "到货明细", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody OaArrivalDetailBo bo) { + return toAjax(iOaArrivalDetailService.updateByBo(bo)); + } + + /** + * 删除到货明细 + * + * @param detailIds 主键串 + */ + @Log(title = "到货明细", businessType = BusinessType.DELETE) + @DeleteMapping("/{detailIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] detailIds) { + return toAjax(iOaArrivalDetailService.deleteWithValidByIds(Arrays.asList(detailIds), true)); + } +} diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/OaArrivalDetail.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/OaArrivalDetail.java new file mode 100644 index 0000000..0e29f52 --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/OaArrivalDetail.java @@ -0,0 +1,95 @@ +package com.ruoyi.oa.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.io.Serializable; +import java.util.Date; +import java.math.BigDecimal; + +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 到货明细对象 oa_arrival_detail + * + * @author ruoyi + * @date 2026-06-12 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("oa_arrival_detail") +public class OaArrivalDetail extends BaseEntity { + + private static final long serialVersionUID=1L; + + /** + * 明细主键 + */ + @TableId(value = "detail_id") + private Long detailId; + /** + * 关联采购需求ID + */ + private Long requirementId; + /** + * 关联项目ID + */ + private Long projectId; + /** + * 项目类型:0=内贸 1=外贸 + */ + private Integer tradeType; + /** + * 合同编号 + */ + private String contractNo; + /** + * 物料名称 + */ + private String goodsName; + /** + * 数量 + */ + private BigDecimal quantity; + /** + * 单价 + */ + private BigDecimal unitPrice; + /** + * 到货类型 (0 收,1 发) + */ + private Integer arrivalType; + /** + * 到货截止日期 + */ + private Date deadline; + /** + * 发货地点 + */ + private String sourceAddress; + /** + * 规划目的地 + */ + private String targetAddress; + /** + * 状态(0 = 待发货,1 = 运输中,2 = 已到货,3 = 异常 / 拒收,4 = 取消) + */ + private Integer detailStatus; + /** + * 描述 + */ + private String description; + /** + * 手动备注 + */ + private String remark; + /** + * 删除标志:0正常 1删除 + */ + @TableLogic + private Integer delFlag; + +} diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/bo/OaArrivalDetailBo.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/bo/OaArrivalDetailBo.java new file mode 100644 index 0000000..3b26b1e --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/bo/OaArrivalDetailBo.java @@ -0,0 +1,103 @@ +package com.ruoyi.oa.domain.bo; + +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; +import javax.validation.constraints.*; + +import java.util.Date; + +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 到货明细业务对象 oa_arrival_detail + * + * @author ruoyi + * @date 2026-06-12 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class OaArrivalDetailBo extends BaseEntity { + + /** + * 明细主键 + */ + private Long detailId; + + /** + * 关联采购需求ID + */ + private Long requirementId; + + /** + * 关联项目ID + */ + private Long projectId; + + /** + * 项目类型:0=内贸 1=外贸 + */ + private Integer tradeType; + + /** + * 合同编号 + */ + private String contractNo; + + /** + * 物料名称 + */ + private String goodsName; + + /** + * 数量 + */ + private BigDecimal quantity; + + /** + * 单价 + */ + private BigDecimal unitPrice; + + /** + * 到货类型 (0 收,1 发) + */ + private Integer arrivalType; + + /** + * 到货截止日期 + */ + private Date deadline; + + /** + * 发货地点 + */ + private String sourceAddress; + + /** + * 规划目的地 + */ + private String targetAddress; + + /** + * 状态(0 = 待发货,1 = 运输中,2 = 已到货,3 = 异常 / 拒收,4 = 取消) + */ + private Integer detailStatus; + + /** + * 描述 + */ + private String description; + + /** + * 手动备注 + */ + private String remark; + + +} diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/vo/OaArrivalDetailVo.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/vo/OaArrivalDetailVo.java new file mode 100644 index 0000000..892f4ab --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/vo/OaArrivalDetailVo.java @@ -0,0 +1,131 @@ +package com.ruoyi.oa.domain.vo; + +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.convert.ExcelDictConvert; +import com.ruoyi.common.core.domain.BaseEntity; +import com.alibaba.excel.annotation.ExcelIgnore; +import lombok.Data; +import java.util.Date; + + + +/** + * 到货明细视图对象 oa_arrival_detail + * + * @author ruoyi + * @date 2026-06-12 + */ +@Data +@ExcelIgnoreUnannotated +public class OaArrivalDetailVo extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 明细主键 + */ + @ExcelProperty(value = "明细主键") + private Long detailId; + + /** + * 关联采购需求ID + */ + @ExcelProperty(value = "关联采购需求ID") + private Long requirementId; + + /** + * 关联项目ID + */ + @ExcelProperty(value = "关联项目ID") + private Long projectId; + + /** + * 项目类型:0=内贸 1=外贸 + */ + @ExcelProperty(value = "项目类型:0=内贸 1=外贸") + private Integer tradeType; + + /** + * 合同编号 + */ + @ExcelProperty(value = "合同编号") + private String contractNo; + + /** + * 物料名称 + */ + @ExcelProperty(value = "物料名称") + private String goodsName; + + /** + * 数量 + */ + @ExcelProperty(value = "数量") + private BigDecimal quantity; + + /** + * 单价 + */ + @ExcelProperty(value = "单价") + private BigDecimal unitPrice; + + /** + * 到货类型 (0 收,1 发) + */ + @ExcelProperty(value = "到货类型 (0 收,1 发)") + private Integer arrivalType; + + /** + * 到货截止日期 + */ + @ExcelProperty(value = "到货截止日期") + private Date deadline; + + /** + * 发货地点 + */ + @ExcelProperty(value = "发货地点") + private String sourceAddress; + + /** + * 规划目的地 + */ + @ExcelProperty(value = "规划目的地") + private String targetAddress; + + /** + * 状态(0 = 待发货,1 = 运输中,2 = 已到货,3 = 异常 / 拒收,4 = 取消) + */ + @ExcelProperty(value = "状态(0 = 待发货,1 = 运输中,2 = 已到货,3 = 异常 / 拒收,4 = 取消)") + private Integer detailStatus; + + /** + * 描述 + */ + @ExcelProperty(value = "描述") + private String description; + + /** + * 手动备注 + */ + @ExcelProperty(value = "手动备注") + private String remark; + + /** + * 关联需求完整信息(列表展示用,非数据库字段) + */ + @ExcelIgnore + private OaRequirementsVo requirement; + + /** + * 关联项目完整信息(列表展示用,非数据库字段) + */ + @ExcelIgnore + private SysOaProjectVo project; + +} diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/mapper/OaArrivalDetailMapper.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/mapper/OaArrivalDetailMapper.java new file mode 100644 index 0000000..04c7b1a --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/mapper/OaArrivalDetailMapper.java @@ -0,0 +1,15 @@ +package com.ruoyi.oa.mapper; + +import com.ruoyi.oa.domain.OaArrivalDetail; +import com.ruoyi.oa.domain.vo.OaArrivalDetailVo; +import com.ruoyi.common.core.mapper.BaseMapperPlus; + +/** + * 到货明细Mapper接口 + * + * @author ruoyi + * @date 2026-06-12 + */ +public interface OaArrivalDetailMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/IOaArrivalDetailService.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/IOaArrivalDetailService.java new file mode 100644 index 0000000..a67b28d --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/IOaArrivalDetailService.java @@ -0,0 +1,49 @@ +package com.ruoyi.oa.service; + +import com.ruoyi.oa.domain.OaArrivalDetail; +import com.ruoyi.oa.domain.vo.OaArrivalDetailVo; +import com.ruoyi.oa.domain.bo.OaArrivalDetailBo; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.domain.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 到货明细Service接口 + * + * @author ruoyi + * @date 2026-06-12 + */ +public interface IOaArrivalDetailService { + + /** + * 查询到货明细 + */ + OaArrivalDetailVo queryById(Long detailId); + + /** + * 查询到货明细列表 + */ + TableDataInfo queryPageList(OaArrivalDetailBo bo, PageQuery pageQuery); + + /** + * 查询到货明细列表 + */ + List queryList(OaArrivalDetailBo bo); + + /** + * 新增到货明细 + */ + Boolean insertByBo(OaArrivalDetailBo bo); + + /** + * 修改到货明细 + */ + Boolean updateByBo(OaArrivalDetailBo bo); + + /** + * 校验并批量删除到货明细信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaArrivalDetailServiceImpl.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaArrivalDetailServiceImpl.java new file mode 100644 index 0000000..541b342 --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaArrivalDetailServiceImpl.java @@ -0,0 +1,239 @@ +package com.ruoyi.oa.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.domain.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import com.ruoyi.oa.domain.bo.OaArrivalDetailBo; +import com.ruoyi.oa.domain.vo.OaArrivalDetailVo; +import com.ruoyi.oa.domain.vo.OaRequirementsVo; +import com.ruoyi.oa.domain.vo.SysOaProjectVo; +import com.ruoyi.oa.domain.OaArrivalDetail; +import com.ruoyi.oa.domain.OaRequirements; +import com.ruoyi.oa.domain.SysOaProject; +import com.ruoyi.oa.mapper.OaArrivalDetailMapper; +import com.ruoyi.oa.mapper.OaRequirementsMapper; +import com.ruoyi.oa.mapper.SysOaProjectMapper; +import com.ruoyi.oa.service.IOaArrivalDetailService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; +import java.util.Set; +import java.util.Collections; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 到货明细Service业务层处理 + * + * @author ruoyi + * @date 2026-06-12 + */ +@RequiredArgsConstructor +@Service +public class OaArrivalDetailServiceImpl implements IOaArrivalDetailService { + + private final OaArrivalDetailMapper baseMapper; + + private final OaRequirementsMapper requirementsMapper; + + private final SysOaProjectMapper projectMapper; + + /** + * 查询到货明细 + */ + @Override + public OaArrivalDetailVo queryById(Long detailId){ + OaArrivalDetailVo vo = baseMapper.selectVoById(detailId); + if (vo != null) { + fillRelatedVo(vo); + } + return vo; + } + + /** + * 查询到货明细列表(分页) + */ + @Override + public TableDataInfo queryPageList(OaArrivalDetailBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + // 批量填充关联名称,避免 N+1 + batchFillRelatedVos(result.getRecords()); + return TableDataInfo.build(result); + } + + /** + * 查询到货明细列表(不分页) + */ + @Override + public List queryList(OaArrivalDetailBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List list = baseMapper.selectVoList(lqw); + // 批量填充关联名称 + batchFillRelatedVos(list); + return list; + } + + private LambdaQueryWrapper buildQueryWrapper(OaArrivalDetailBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getRequirementId() != null, OaArrivalDetail::getRequirementId, bo.getRequirementId()); + lqw.eq(bo.getProjectId() != null, OaArrivalDetail::getProjectId, bo.getProjectId()); + lqw.eq(bo.getTradeType() != null, OaArrivalDetail::getTradeType, bo.getTradeType()); + lqw.eq(StringUtils.isNotBlank(bo.getContractNo()), OaArrivalDetail::getContractNo, bo.getContractNo()); + lqw.like(StringUtils.isNotBlank(bo.getGoodsName()), OaArrivalDetail::getGoodsName, bo.getGoodsName()); + lqw.eq(bo.getQuantity() != null, OaArrivalDetail::getQuantity, bo.getQuantity()); + lqw.eq(bo.getUnitPrice() != null, OaArrivalDetail::getUnitPrice, bo.getUnitPrice()); + lqw.eq(bo.getArrivalType() != null, OaArrivalDetail::getArrivalType, bo.getArrivalType()); + lqw.eq(bo.getDeadline() != null, OaArrivalDetail::getDeadline, bo.getDeadline()); + lqw.eq(StringUtils.isNotBlank(bo.getSourceAddress()), OaArrivalDetail::getSourceAddress, bo.getSourceAddress()); + lqw.eq(StringUtils.isNotBlank(bo.getTargetAddress()), OaArrivalDetail::getTargetAddress, bo.getTargetAddress()); + lqw.eq(bo.getDetailStatus() != null, OaArrivalDetail::getDetailStatus, bo.getDetailStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getDescription()), OaArrivalDetail::getDescription, bo.getDescription()); + lqw.orderByDesc(OaArrivalDetail::getCreateTime); + return lqw; + } + + /** + * 批量填充关联的需求VO和项目VO + */ + private void batchFillRelatedVos(List list) { + if (list == null || list.isEmpty()) { + return; + } + + // 收集所有需求ID + Set requirementIds = list.stream() + .map(OaArrivalDetailVo::getRequirementId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + // 收集所有项目ID + Set projectIds = list.stream() + .map(OaArrivalDetailVo::getProjectId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + // 批量查询需求完整VO + Map requirementMap = Collections.emptyMap(); + if (!requirementIds.isEmpty()) { + List reqVoList = requirementsMapper.selectVoBatchIds(requirementIds); + if (reqVoList != null) { + requirementMap = reqVoList.stream() + .collect(Collectors.toMap(OaRequirementsVo::getRequirementId, + Function.identity(), (a, b) -> a)); + } + } + + // 批量查询项目完整VO + Map projectMap = Collections.emptyMap(); + if (!projectIds.isEmpty()) { + List projVoList = projectMapper.selectVoBatchIds(projectIds); + if (projVoList != null) { + projectMap = projVoList.stream() + .collect(Collectors.toMap(SysOaProjectVo::getProjectId, + Function.identity(), (a, b) -> a)); + } + } + + // 回填完整 VO 对象 + for (OaArrivalDetailVo vo : list) { + if (vo.getRequirementId() != null) { + vo.setRequirement(requirementMap.get(vo.getRequirementId())); + } + if (vo.getProjectId() != null) { + vo.setProject(projectMap.get(vo.getProjectId())); + } + } + } + + /** + * 单条填充关联VO + */ + private void fillRelatedVo(OaArrivalDetailVo vo) { + if (vo.getRequirementId() != null) { + vo.setRequirement(requirementsMapper.selectVoById(vo.getRequirementId())); + } + if (vo.getProjectId() != null) { + vo.setProject(projectMapper.selectVoById(vo.getProjectId())); + } + } + + /** + * 新增到货明细 + */ + @Override + public Boolean insertByBo(OaArrivalDetailBo bo) { + // 如果前端传了需求ID,自动查询需求表获取项目ID,再查项目表获取贸易类型 + autoFillByRequirement(bo); + + OaArrivalDetail add = BeanUtil.toBean(bo, OaArrivalDetail.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setDetailId(add.getDetailId()); + } + return flag; + } + + /** + * 根据需求ID自动填充项目ID和贸易类型 + */ + private void autoFillByRequirement(OaArrivalDetailBo bo) { + if (bo.getRequirementId() == null) { + return; + } + // 查询需求表获取项目ID + OaRequirements requirement = requirementsMapper.selectById(bo.getRequirementId()); + if (requirement == null) { + return; + } + Long projectId = requirement.getProjectId(); + if (projectId != null && bo.getProjectId() == null) { + bo.setProjectId(projectId); + } + // 查询项目表获取贸易类型(仅当未设置时) + if (bo.getTradeType() == null && projectId != null) { + SysOaProject project = projectMapper.selectById(projectId); + if (project != null && project.getTradeType() != null) { + bo.setTradeType(project.getTradeType().intValue()); + } + } + } + + /** + * 修改到货明细 + */ + @Override + public Boolean updateByBo(OaArrivalDetailBo bo) { + OaArrivalDetail update = BeanUtil.toBean(bo, OaArrivalDetail.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(OaArrivalDetail entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 批量删除到货明细 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } +} diff --git a/ruoyi-oa/src/main/resources/mapper/oa/OaArrivalDetailMapper.xml b/ruoyi-oa/src/main/resources/mapper/oa/OaArrivalDetailMapper.xml new file mode 100644 index 0000000..0fda017 --- /dev/null +++ b/ruoyi-oa/src/main/resources/mapper/oa/OaArrivalDetailMapper.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +