From ca8717f1c2e682f62d54f5a7877f95ab4dcaa96b Mon Sep 17 00:00:00 2001 From: yangk Date: Mon, 25 May 2026 11:04:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(oa/erp):=20=E6=96=B0=E5=A2=9E=E9=A2=84?= =?UTF-8?q?=E6=8A=95=E5=B7=A5=E6=97=B6=E5=88=86=E9=85=8D=E6=98=8E=E7=BB=86?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在控制器中添加 exportDetail 接口支持明细数据导出 - 创建 ErpTimesheetPreAllocDetailExportVo 专门用于导出的数据传输对象 - 实现服务层 queryExportDetailList 方法处理明细查询逻辑 - 支持按勾选分配单或过滤条件两种方式导出明细数据 - 使用 JoinWrappers 关联查询分配主表和明细表数据 - 添加相应的权限注解和日志记录功能 --- .../ErpTimesheetPreAllocController.java | 13 ++ .../ErpTimesheetPreAllocDetailExportVo.java | 67 ++++++++++ .../service/IErpTimesheetPreAllocService.java | 9 ++ .../impl/ErpTimesheetPreAllocServiceImpl.java | 119 ++++++++++++------ 4 files changed, 170 insertions(+), 38 deletions(-) create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpTimesheetPreAllocDetailExportVo.java diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpTimesheetPreAllocController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpTimesheetPreAllocController.java index d07ba3ac..cd2abe87 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpTimesheetPreAllocController.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/controller/ErpTimesheetPreAllocController.java @@ -19,6 +19,7 @@ import org.dromara.common.log.enums.BusinessType; import org.dromara.common.excel.utils.ExcelUtil; import org.dromara.oa.erp.domain.vo.ErpProjectInfoVo; import org.dromara.oa.erp.domain.vo.ErpTimesheetPreAllocVo; +import org.dromara.oa.erp.domain.vo.ErpTimesheetPreAllocDetailExportVo; import org.dromara.oa.erp.domain.bo.ErpTimesheetPreAllocBo; import org.dromara.oa.erp.domain.vo.PreAllocDetailVo; import org.dromara.oa.erp.service.IErpTimesheetPreAllocService; @@ -59,6 +60,18 @@ public class ErpTimesheetPreAllocController extends BaseController { ExcelUtil.exportExcel(list, "预投工时分配", ErpTimesheetPreAllocVo.class, response); } + /** + * 导出预投工时分配明细列表 + * 支持选中多条分配单进行特定导出,若未勾选则根据过滤条件执行匹配导出的明细数据 + */ + @SaCheckPermission("oa/erp:timesheetPreAlloc:export") + @Log(title = "预投工时分配明细", businessType = BusinessType.EXPORT) + @PostMapping("/exportDetail") + public void exportDetail(ErpTimesheetPreAllocBo bo, HttpServletResponse response) { + List list = erpTimesheetPreAllocService.queryExportDetailList(bo); + ExcelUtil.exportExcel(list, "预投工时分配明细", ErpTimesheetPreAllocDetailExportVo.class, response); + } + /** * 获取预投工时分配详细信息 * diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpTimesheetPreAllocDetailExportVo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpTimesheetPreAllocDetailExportVo.java new file mode 100644 index 00000000..9e795064 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/domain/vo/ErpTimesheetPreAllocDetailExportVo.java @@ -0,0 +1,67 @@ +package org.dromara.oa.erp.domain.vo; + +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 预投工时分配明细导出视图对象 + * 该类作为导出专用数据载体,仅保留六个核心明细字段,避免污染原有的实体VO。 + * + * @author Yangk + * @date 2026-05-25 + */ +@Data +@ExcelIgnoreUnannotated +public class ErpTimesheetPreAllocDetailExportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 分配单编号 + */ + @ExcelProperty(value = "分配单编号") + private String allocCode; + + /** + * 月份编码 + */ + @ExcelProperty(value = "月 份") + private String monthCode; + + /** + * 原项目编码 + */ + @ExcelProperty(value = "原项目编码") + private String originalProjectCode; + + /** + * 原项目名称 + */ + @ExcelProperty(value = "原项目名称") + private String originalProjectName; + + /** + * 目标项目编码 + */ + @ExcelProperty(value = "目标项目编码") + private String targetProjectCode; + + /** + * 目标项目名称 + */ + @ExcelProperty(value = "目标项目名称") + private String targetProjectName; + + /** + * 分配工时 + */ + @ExcelProperty(value = "分配工时") + private BigDecimal allocHours; + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpTimesheetPreAllocService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpTimesheetPreAllocService.java index 17140c69..f81e1c2b 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpTimesheetPreAllocService.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/IErpTimesheetPreAllocService.java @@ -6,6 +6,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.oa.erp.domain.vo.ErpProjectInfoVo; import org.dromara.oa.erp.domain.vo.PreAllocDetailVo; +import org.dromara.oa.erp.domain.vo.ErpTimesheetPreAllocDetailExportVo; import java.util.Collection; import java.util.List; @@ -51,6 +52,14 @@ public interface IErpTimesheetPreAllocService { */ List queryList(ErpTimesheetPreAllocBo bo); + /** + * 查询用于导出的预投工时分配明细列表 + * + * @param bo 查询参数 + * @return 预投分配明细导出列表 + */ + List queryExportDetailList(ErpTimesheetPreAllocBo bo); + /** * 查询当前部门指定月份、来源预投项目的员工级可分配明细 * diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpTimesheetPreAllocServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpTimesheetPreAllocServiceImpl.java index 91768da9..e55eaa91 100644 --- a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpTimesheetPreAllocServiceImpl.java +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/erp/service/impl/ErpTimesheetPreAllocServiceImpl.java @@ -21,6 +21,7 @@ import org.dromara.oa.erp.domain.vo.ErpTimesheetPreAllocVo; import org.dromara.oa.erp.domain.vo.PreAllocDetailVo; import org.dromara.oa.erp.domain.vo.PreAllocSourceStatVo; import org.dromara.oa.erp.domain.vo.PreAllocTargetVo; +import org.dromara.oa.erp.domain.vo.ErpTimesheetPreAllocDetailExportVo; import org.dromara.oa.erp.mapper.ErpProjectInfoMapper; import org.dromara.oa.erp.mapper.ErpTimesheetPreAllocDetailMapper; import org.dromara.oa.erp.mapper.ErpTimesheetPreAllocMapper; @@ -123,21 +124,60 @@ public class ErpTimesheetPreAllocServiceImpl implements IErpTimesheetPreAllocSer return baseMapper.selectVoList(lqw); } + /** + * 查询用于导出的预投工时分配明细列表 + * + * @param bo 查询参数 + * @return 预投分配明细导出列表 + */ + @Override + public List queryExportDetailList(ErpTimesheetPreAllocBo bo) { + List allocIds = null; + if (StringUtils.isNotBlank(bo.getAllocIds())) { + // 如果用户在前端勾选了特定的分配单,则仅导出这些分配单的明细 + allocIds = java.util.stream.Stream.of(bo.getAllocIds().split(",")).map(Long::valueOf).toList(); + } else { + // 若用户未勾选,则依据当前列表筛选条件,反查出符合过滤条件的所有分配单,再进行明细关联 + List list = this.queryList(bo); + allocIds = list.stream().map(ErpTimesheetPreAllocVo::getAllocId).toList(); + } + if (cn.hutool.core.collection.CollUtil.isEmpty(allocIds)) { + return List.of(); + } + return preAllocDetailMapper.selectJoinList( + ErpTimesheetPreAllocDetailExportVo.class, + JoinWrappers.lambda(ErpTimesheetPreAllocDetail.class) + .selectAs(ErpTimesheetPreAlloc::getAllocCode, "allocCode") + .selectAs(ErpTimesheetPreAlloc::getMonthCode, "monthCode") + .select(ErpTimesheetPreAllocDetail::getOriginalProjectCode, + ErpTimesheetPreAllocDetail::getOriginalProjectName, + ErpTimesheetPreAllocDetail::getTargetProjectCode, + ErpTimesheetPreAllocDetail::getTargetProjectName, + ErpTimesheetPreAllocDetail::getAllocHours) + .leftJoin(ErpTimesheetPreAlloc.class, ErpTimesheetPreAlloc::getAllocId, + ErpTimesheetPreAllocDetail::getAllocId) + .in(ErpTimesheetPreAllocDetail::getAllocId, allocIds) + .eq(ErpTimesheetPreAllocDetail::getDelFlag, "0")); + } + private MPJLambdaWrapper buildQueryWrapper(ErpTimesheetPreAllocBo bo) { Long deptId = LoginHelper.getDeptId(); return JoinWrappers.lambda(ErpTimesheetPreAlloc.class) - .selectAll(ErpTimesheetPreAlloc.class) - .eq(ErpTimesheetPreAlloc::getDelFlag, DEL_FLAG_NORMAL) - .eq(deptId != null, ErpTimesheetPreAlloc::getCreateDept, deptId) - .eq(StringUtils.isNotBlank(bo.getAllocCode()), ErpTimesheetPreAlloc::getAllocCode, bo.getAllocCode()) - .eq(StringUtils.isNotBlank(bo.getMonthCode()), ErpTimesheetPreAlloc::getMonthCode, bo.getMonthCode()) - .eq(bo.getProjectId() != null, ErpTimesheetPreAlloc::getProjectId, bo.getProjectId()) - .eq(StringUtils.isNotBlank(bo.getProjectCode()), ErpTimesheetPreAlloc::getProjectCode, bo.getProjectCode()) - .like(StringUtils.isNotBlank(bo.getProjectName()), ErpTimesheetPreAlloc::getProjectName, bo.getProjectName()) - .eq(StringUtils.isNotBlank(bo.getAllocStatus()), ErpTimesheetPreAlloc::getAllocStatus, bo.getAllocStatus()) - .in(StringUtils.isNotBlank(bo.getAllocIds()), ErpTimesheetPreAlloc::getAllocId, - StringUtils.isNotBlank(bo.getAllocIds()) ? List.of(bo.getAllocIds().split(",")) : null) - .orderByDesc(ErpTimesheetPreAlloc::getAllocId); + .selectAll(ErpTimesheetPreAlloc.class) + .eq(ErpTimesheetPreAlloc::getDelFlag, DEL_FLAG_NORMAL) + .eq(deptId != null, ErpTimesheetPreAlloc::getCreateDept, deptId) + .eq(StringUtils.isNotBlank(bo.getAllocCode()), ErpTimesheetPreAlloc::getAllocCode, bo.getAllocCode()) + .eq(StringUtils.isNotBlank(bo.getMonthCode()), ErpTimesheetPreAlloc::getMonthCode, bo.getMonthCode()) + .eq(bo.getProjectId() != null, ErpTimesheetPreAlloc::getProjectId, bo.getProjectId()) + .eq(StringUtils.isNotBlank(bo.getProjectCode()), ErpTimesheetPreAlloc::getProjectCode, + bo.getProjectCode()) + .like(StringUtils.isNotBlank(bo.getProjectName()), ErpTimesheetPreAlloc::getProjectName, + bo.getProjectName()) + .eq(StringUtils.isNotBlank(bo.getAllocStatus()), ErpTimesheetPreAlloc::getAllocStatus, + bo.getAllocStatus()) + .in(StringUtils.isNotBlank(bo.getAllocIds()), ErpTimesheetPreAlloc::getAllocId, + StringUtils.isNotBlank(bo.getAllocIds()) ? List.of(bo.getAllocIds().split(",")) : null) + .orderByDesc(ErpTimesheetPreAlloc::getAllocId); } /** @@ -161,8 +201,8 @@ public class ErpTimesheetPreAllocServiceImpl implements IErpTimesheetPreAllocSer ErpTimesheetPreAlloc alloc = queryActiveAlloc(monthCode, projectId, deptId); List allocItems = buildTargetVos(alloc == null ? null : alloc.getAllocId()); BigDecimal allocatedTotal = allocItems.stream() - .map(item -> nvl(item.getAllocHours())) - .reduce(BigDecimal.ZERO, BigDecimal::add); + .map(item -> nvl(item.getAllocHours())) + .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal sourceTotal = nvl(sourceStat.getSourceTotalHours()); PreAllocDetailVo detailVo = new PreAllocDetailVo(); @@ -245,7 +285,8 @@ public class ErpTimesheetPreAllocServiceImpl implements IErpTimesheetPreAllocSer } AllocationResult allocationResult = buildAllocationResult(bo.getAllocItems(), sourceTotal); - ErpTimesheetPreAlloc alloc = resolveAlloc(bo.getAllocId(), bo.getMonthCode(), sourceProject.getProjectId(), deptId); + ErpTimesheetPreAlloc alloc = resolveAlloc(bo.getAllocId(), bo.getMonthCode(), sourceProject.getProjectId(), + deptId); boolean isNew = alloc == null; if (isNew) { alloc = new ErpTimesheetPreAlloc(); @@ -281,8 +322,8 @@ public class ErpTimesheetPreAllocServiceImpl implements IErpTimesheetPreAllocSer return false; } List allocList = baseMapper.selectList(Wrappers.lambdaQuery() - .in(ErpTimesheetPreAlloc::getAllocId, ids) - .eq(ErpTimesheetPreAlloc::getDelFlag, DEL_FLAG_NORMAL)); + .in(ErpTimesheetPreAlloc::getAllocId, ids) + .eq(ErpTimesheetPreAlloc::getDelFlag, DEL_FLAG_NORMAL)); if (allocList.size() != ids.size()) { throw new ServiceException("部分预投工时分配单不存在或已删除"); } @@ -293,7 +334,7 @@ public class ErpTimesheetPreAllocServiceImpl implements IErpTimesheetPreAllocSer } } preAllocDetailMapper.delete(Wrappers.lambdaQuery() - .in(ErpTimesheetPreAllocDetail::getAllocId, ids)); + .in(ErpTimesheetPreAllocDetail::getAllocId, ids)); return baseMapper.deleteByIds(ids) > 0; } @@ -317,14 +358,15 @@ public class ErpTimesheetPreAllocServiceImpl implements IErpTimesheetPreAllocSer private MonthRange monthRange(String monthCode) { YearMonth yearMonth = YearMonth.of( - Integer.parseInt(monthCode.substring(0, 4)), - Integer.parseInt(monthCode.substring(4, 6))); + Integer.parseInt(monthCode.substring(0, 4)), + Integer.parseInt(monthCode.substring(4, 6))); return new MonthRange(Date.valueOf(yearMonth.atDay(1)), Date.valueOf(yearMonth.atEndOfMonth())); } private PreAllocSourceStatVo loadSourceStat(String monthCode, Long deptId, Long projectId) { MonthRange range = monthRange(monthCode); - PreAllocSourceStatVo sourceStat = baseMapper.selectSourceStat(deptId, range.startDate(), range.endDate(), projectId); + PreAllocSourceStatVo sourceStat = baseMapper.selectSourceStat(deptId, range.startDate(), range.endDate(), + projectId); if (sourceStat == null) { sourceStat = new PreAllocSourceStatVo(); } @@ -355,10 +397,10 @@ public class ErpTimesheetPreAllocServiceImpl implements IErpTimesheetPreAllocSer private ErpTimesheetPreAlloc queryActiveAlloc(String monthCode, Long projectId, Long deptId) { List allocList = baseMapper.selectList(Wrappers.lambdaQuery() - .eq(ErpTimesheetPreAlloc::getMonthCode, monthCode) - .eq(ErpTimesheetPreAlloc::getProjectId, projectId) - .eq(ErpTimesheetPreAlloc::getCreateDept, deptId) - .eq(ErpTimesheetPreAlloc::getDelFlag, DEL_FLAG_NORMAL)); + .eq(ErpTimesheetPreAlloc::getMonthCode, monthCode) + .eq(ErpTimesheetPreAlloc::getProjectId, projectId) + .eq(ErpTimesheetPreAlloc::getCreateDept, deptId) + .eq(ErpTimesheetPreAlloc::getDelFlag, DEL_FLAG_NORMAL)); if (allocList.size() > 1) { throw new ServiceException("当前部门该月份该预投项目存在多张有效分配单,请先修正数据"); } @@ -422,11 +464,11 @@ public class ErpTimesheetPreAllocServiceImpl implements IErpTimesheetPreAllocSer } private void fillAlloc(ErpTimesheetPreAlloc alloc, - ErpTimesheetPreAllocBo bo, - ErpProjectInfo sourceProject, - PreAllocSourceStatVo sourceStat, - AllocationResult allocationResult, - Long deptId) { + ErpTimesheetPreAllocBo bo, + ErpProjectInfo sourceProject, + PreAllocSourceStatVo sourceStat, + AllocationResult allocationResult, + Long deptId) { BigDecimal sourceTotal = nvl(sourceStat.getSourceTotalHours()); alloc.setMonthCode(bo.getMonthCode()); alloc.setStandardMonthId(null); @@ -442,10 +484,10 @@ public class ErpTimesheetPreAllocServiceImpl implements IErpTimesheetPreAllocSer } private void rewritePreAllocDetails(ErpTimesheetPreAlloc alloc, - ErpProjectInfo sourceProject, - List targetAllocations) { + ErpProjectInfo sourceProject, + List targetAllocations) { preAllocDetailMapper.delete(Wrappers.lambdaQuery() - .eq(ErpTimesheetPreAllocDetail::getAllocId, alloc.getAllocId())); + .eq(ErpTimesheetPreAllocDetail::getAllocId, alloc.getAllocId())); if (targetAllocations.isEmpty()) { return; } @@ -471,11 +513,12 @@ public class ErpTimesheetPreAllocServiceImpl implements IErpTimesheetPreAllocSer if (allocId == null) { return Collections.emptyList(); } - List detailList = preAllocDetailMapper.selectList(Wrappers.lambdaQuery() - .eq(ErpTimesheetPreAllocDetail::getAllocId, allocId) - .eq(ErpTimesheetPreAllocDetail::getDelFlag, DEL_FLAG_NORMAL) - .orderByAsc(ErpTimesheetPreAllocDetail::getSortOrder) - .orderByAsc(ErpTimesheetPreAllocDetail::getAllocDetailId)); + List detailList = preAllocDetailMapper + .selectList(Wrappers.lambdaQuery() + .eq(ErpTimesheetPreAllocDetail::getAllocId, allocId) + .eq(ErpTimesheetPreAllocDetail::getDelFlag, DEL_FLAG_NORMAL) + .orderByAsc(ErpTimesheetPreAllocDetail::getSortOrder) + .orderByAsc(ErpTimesheetPreAllocDetail::getAllocDetailId)); List targetVos = new ArrayList<>(); for (ErpTimesheetPreAllocDetail detail : detailList) { PreAllocTargetVo targetVo = new PreAllocTargetVo();