施工产值导出,大图

This commit is contained in:
lcj
2025-12-02 15:51:44 +08:00
parent 3e38cf9abb
commit 37c95ab0bd
26 changed files with 1489 additions and 45 deletions

View File

@ -4,7 +4,7 @@ server:
port: 8899
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
# 增加客户端开关
enabled: false
url: http://192.168.110.119:9090/admin
instance:
@ -66,7 +66,7 @@ spring:
# username: xinnengyuan
# password: mEZPC5Sdf3r2HENi
# 从库数据源
# slave:
# slave:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver

View File

@ -25,7 +25,7 @@ import java.util.concurrent.CompletableFuture;
public class DashScopeChat {
@Resource
private SimpleChat simpleChat;
private DashScopeSimpleChat dashScopeSimpleChat;
@Resource
private IAIChatMemoryService chatMemoryService;
@ -66,10 +66,8 @@ public class DashScopeChat {
.collectList()
.flatMapMany(tokens -> {
String aiResponse = String.join("", tokens);
if (isFirst) {
// 异步生成标题
generateChatTitleAsync(chatId, message, aiResponse, userId);
}
// 异步生成标题
generateChatTitleAsync(chatId, message, aiResponse, userId);
// 返回完整的流结果
return Flux.fromIterable(tokens);
});
@ -100,7 +98,7 @@ public class DashScopeChat {
用户:%s
AI%s
""", userMessage, aiResponse);
String title = simpleChat.doChat(prompt);
String title = dashScopeSimpleChat.doChat(prompt);
log.info("用户:{} 生成标题成功:{} -> {}", userId, chatId, title);
// 保存对话数据
AIChatMemory memory = new AIChatMemory();

View File

@ -9,11 +9,11 @@ import org.springframework.stereotype.Component;
* @date 2025-11-04 15:26
*/
@Component
public class SimpleChat {
public class DashScopeSimpleChat {
private final ChatClient dashScopeChatClient;
public SimpleChat(ChatClient.Builder chatClientBuilder) {
public DashScopeSimpleChat(ChatClient.Builder chatClientBuilder) {
this.dashScopeChatClient = chatClientBuilder
// 设置 ChatClient ChatModel Options 参数
.defaultOptions(

View File

@ -41,7 +41,6 @@ import org.dromara.patch.service.IPdMasterService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.system.domain.SysMenu;
import org.dromara.system.domain.vo.RouterVo;
import org.dromara.system.mapper.SysRoleMapper;
import org.dromara.system.service.impl.SysMenuServiceImpl;
import org.dromara.system.service.impl.SysUserServiceImpl;
import org.dromara.warm.flow.core.FlowEngine;
@ -97,8 +96,7 @@ public class PersonalHomeController extends BaseController {
@Resource
private IBusProjectService projectService;
private final SysRoleMapper roleMapper;
private final SysMenuServiceImpl sysMenuService;
private final SysMenuServiceImpl sysMenuService;
// region AI 模块

View File

@ -18,7 +18,7 @@ import org.dromara.common.web.core.BaseController;
import org.dromara.out.domain.bo.OutConstructionValueBo;
import org.dromara.out.domain.bo.OutConstructionValueFacilityReq;
import org.dromara.out.domain.vo.OutConstructionAllValueVo;
import org.dromara.out.domain.vo.OutConstructionValueVo;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueVo;
import org.dromara.out.service.IOutConstructionValueService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -59,6 +59,16 @@ public class OutConstructionValueController extends BaseController {
ExcelUtil.exportExcel(list, "施工产值", OutConstructionValueVo.class, response);
}
/**
* 导出施工产值范围列表
*/
@SaCheckPermission("out:constructionValue:export")
@Log(title = "施工产值", businessType = BusinessType.EXPORT)
@PostMapping("/exportByProject")
public void exportByProject(OutConstructionValueBo bo, HttpServletResponse response) {
outConstructionValueService.exportExcel(bo, response);
}
/**
* 获取施工产值详细信息
*

View File

@ -23,8 +23,8 @@ import org.dromara.out.domain.OutConstructionValue;
import org.dromara.out.domain.OutConstructionValueRange;
import org.dromara.out.domain.bo.OutConstructionValueRangeBo;
import org.dromara.out.domain.vo.OutConstructionAllValueRangeVo;
import org.dromara.out.domain.vo.OutConstructionValueRangeVo;
import org.dromara.out.domain.vo.OutConstructionValueVo;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueVo;
import org.dromara.out.domain.vo.outconstructionvaluerange.OutConstructionValueRangeVo;
import org.dromara.out.service.IOutConstructionValueRangeService;
import org.dromara.out.service.IOutConstructionValueService;
import org.springframework.beans.BeanUtils;
@ -114,6 +114,16 @@ public class OutConstructionValueRangeController extends BaseController {
}
}
/**
* 导出施工产值范围列表
*/
@SaCheckPermission("out:constructionValueRange:export")
@Log(title = "施工产值范围", businessType = BusinessType.EXPORT)
@PostMapping("/exportByProject")
public void exportByProject(OutConstructionValueRangeBo bo, HttpServletResponse response) {
outConstructionValueRangeService.exportExcel(bo, response);
}
/**
* 获取施工产值范围详细信息
*

View File

@ -0,0 +1,119 @@
package org.dromara.out.domain.vo.outconstructionvalue;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* @author lilemy
* @date 2025-12-01 15:46
*/
@Data
public class OutConstructionValueCategoryVo {
/**
* 主键ID
*/
private Long id;
/**
* 范围ID
*/
private Long rangeId;
/**
* 项目ID
*/
private Long projectId;
/**
* 方阵id
*/
private Long matrixId;
/**
* 分项工程id
*/
private Long progressCategoryId;
/**
* 分项工程名称
*/
private String progressCategoryName;
/**
* 计划详情id
*/
private Long detailId;
/**
* 人工填报数量
*/
private Integer artificialNum;
/**
* 无人机识别数量
*/
private Integer uavNum;
/**
* 确认数量
*/
private Integer confirmNum;
/**
* 计划数量
*/
private Integer planNum;
/**
* 対乙产值
*/
private BigDecimal outValue;
/**
* 上报日期
*/
private LocalDate reportDate;
/**
* 计划日期
*/
private LocalDate planDate;
/**
* 对甲产值
*/
private BigDecimal ownerValue;
/**
* 方阵名称
*/
private String matrixName;
/**
* 类别名称
*/
private String name;
/**
* 计量方式0无 1数量 2百分比
*/
private String unitType;
/**
* 计量单位
*/
private String unit;
/**
* 祖级列表
*/
private String ancestors;
/**
* 关联结构(1子项目 2方阵 3项目)
*/
private String relevancyStructure;
}

View File

@ -0,0 +1,71 @@
package org.dromara.out.domain.vo.outconstructionvalue;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-12-01 10:09
*/
@Data
public class OutConstructionValueMatrixVo {
/**
* 项目名
*/
@ExcelProperty(value = "项目")
private String projectName;
/**
* 子项目名
*/
@ExcelProperty(value = "子项")
private String subProjectName;
/**
* 方阵名称
*/
@ExcelProperty(value = "方阵")
private String matrixName;
/**
* 分项工程名称
*/
@ExcelProperty(value = "分部分项")
private String progressCategoryName;
/**
* 计量方式0无 1数量 2百分比
*/
@ExcelProperty(value = "计量方式", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "0=无,1=数量,2=百分比")
private String unitType;
/**
* 单位
*/
@ExcelProperty(value = "单位")
private String unit;
/**
* 数量
*/
@ExcelProperty(value = "数量")
private BigDecimal number;
/**
* 对甲产值
*/
@ExcelProperty(value = "金额(对甲)")
private BigDecimal ownerValue;
/**
* 产值
*/
@ExcelProperty(value = "金额(对乙)")
private BigDecimal outValue;
}

View File

@ -0,0 +1,59 @@
package org.dromara.out.domain.vo.outconstructionvalue;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-12-01 10:08
*/
@Data
public class OutConstructionValueProjectVo {
/**
* 项目名
*/
@ExcelProperty(value = "项目")
private String projectName;
/**
* 分项工程名称
*/
@ExcelProperty(value = "分部分项")
private String progressCategoryName;
/**
* 计量方式0无 1数量 2百分比
*/
@ExcelProperty(value = "计量方式", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "0=无,1=数量,2=百分比")
private String unitType;
/**
* 单位
*/
@ExcelProperty(value = "单位")
private String unit;
/**
* 数量
*/
@ExcelProperty(value = "数量")
private BigDecimal number;
/**
* 对甲产值
*/
@ExcelProperty(value = "金额(对甲)")
private BigDecimal ownerValue;
/**
* 产值
*/
@ExcelProperty(value = "金额(对乙)")
private BigDecimal outValue;
}

View File

@ -0,0 +1,65 @@
package org.dromara.out.domain.vo.outconstructionvalue;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-12-01 10:08
*/
@Data
public class OutConstructionValueSubProjectVo {
/**
* 项目名
*/
@ExcelProperty(value = "项目")
private String projectName;
/**
* 子项目名
*/
@ExcelProperty(value = "子项")
private String subProjectName;
/**
* 分项工程名称
*/
@ExcelProperty(value = "分部分项")
private String progressCategoryName;
/**
* 计量方式0无 1数量 2百分比
*/
@ExcelProperty(value = "计量方式", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "0=无,1=数量,2=百分比")
private String unitType;
/**
* 单位
*/
@ExcelProperty(value = "单位")
private String unit;
/**
* 数量
*/
@ExcelProperty(value = "数量")
private BigDecimal number;
/**
* 对甲产值
*/
@ExcelProperty(value = "金额(对甲)")
private BigDecimal ownerValue;
/**
* 产值
*/
@ExcelProperty(value = "金额(对乙)")
private BigDecimal outValue;
}

View File

@ -1,4 +1,4 @@
package org.dromara.out.domain.vo;
package org.dromara.out.domain.vo.outconstructionvalue;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;

View File

@ -0,0 +1,71 @@
package org.dromara.out.domain.vo.outconstructionvaluerange;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-12-01 11:31
*/
@Data
public class OutConstructionValueRangeMatrixVo {
/**
* 项目名
*/
@ExcelProperty(value = "项目")
private String projectName;
/**
* 子项目名
*/
@ExcelProperty(value = "子项")
private String subProjectName;
/**
* 方阵名称
*/
@ExcelProperty(value = "方阵")
private String matrixName;
/**
* 分项工程名称
*/
@ExcelProperty(value = "分部分项")
private String progressCategoryName;
/**
* 计量方式0无 1数量 2百分比
*/
@ExcelProperty(value = "计量方式", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "0=无,1=数量,2=百分比")
private String unitType;
/**
* 单位
*/
@ExcelProperty(value = "单位")
private String unit;
/**
* 数量
*/
@ExcelProperty(value = "数量")
private BigDecimal number;
/**
* 对甲产值
*/
@ExcelProperty(value = "金额(对甲)")
private BigDecimal ownerValue;
/**
* 产值
*/
@ExcelProperty(value = "金额(对乙)")
private BigDecimal outValue;
}

View File

@ -0,0 +1,59 @@
package org.dromara.out.domain.vo.outconstructionvaluerange;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-12-01 11:30
*/
@Data
public class OutConstructionValueRangeProjectVo {
/**
* 项目名
*/
@ExcelProperty(value = "项目")
private String projectName;
/**
* 分项工程名称
*/
@ExcelProperty(value = "分部分项")
private String progressCategoryName;
/**
* 计量方式0无 1数量 2百分比
*/
@ExcelProperty(value = "计量方式", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "0=无,1=数量,2=百分比")
private String unitType;
/**
* 单位
*/
@ExcelProperty(value = "单位")
private String unit;
/**
* 数量
*/
@ExcelProperty(value = "数量")
private BigDecimal number;
/**
* 对甲产值
*/
@ExcelProperty(value = "金额(对甲)")
private BigDecimal ownerValue;
/**
* 产值
*/
@ExcelProperty(value = "金额(对乙)")
private BigDecimal outValue;
}

View File

@ -0,0 +1,65 @@
package org.dromara.out.domain.vo.outconstructionvaluerange;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-12-01 11:30
*/
@Data
public class OutConstructionValueRangeSubProjectVo {
/**
* 项目名
*/
@ExcelProperty(value = "项目")
private String projectName;
/**
* 子项目名
*/
@ExcelProperty(value = "子项")
private String subProjectName;
/**
* 分项工程名称
*/
@ExcelProperty(value = "分部分项")
private String progressCategoryName;
/**
* 计量方式0无 1数量 2百分比
*/
@ExcelProperty(value = "计量方式", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "0=无,1=数量,2=百分比")
private String unitType;
/**
* 单位
*/
@ExcelProperty(value = "单位")
private String unit;
/**
* 数量
*/
@ExcelProperty(value = "数量")
private BigDecimal number;
/**
* 对甲产值
*/
@ExcelProperty(value = "金额(对甲)")
private BigDecimal ownerValue;
/**
* 产值
*/
@ExcelProperty(value = "金额(对乙)")
private BigDecimal outValue;
}

View File

@ -1,4 +1,4 @@
package org.dromara.out.domain.vo;
package org.dromara.out.domain.vo.outconstructionvaluerange;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
@ -7,6 +7,7 @@ import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.out.domain.OutConstructionValueRange;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueVo;
import java.io.Serial;
import java.io.Serializable;

View File

@ -3,7 +3,7 @@ package org.dromara.out.mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.dromara.out.domain.OutConstructionValue;
import org.dromara.out.domain.vo.OutConstructionValueVo;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.math.BigDecimal;

View File

@ -1,7 +1,7 @@
package org.dromara.out.mapper;
import org.dromara.out.domain.OutConstructionValueRange;
import org.dromara.out.domain.vo.OutConstructionValueRangeVo;
import org.dromara.out.domain.vo.outconstructionvaluerange.OutConstructionValueRangeVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**

View File

@ -1,12 +1,13 @@
package org.dromara.out.service;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.out.domain.OutConstructionValueRange;
import org.dromara.out.domain.bo.OutConstructionValueRangeBo;
import org.dromara.out.domain.vo.OutConstructionAllValueRangeVo;
import org.dromara.out.domain.vo.OutConstructionValueRangeVo;
import org.dromara.out.domain.vo.outconstructionvaluerange.OutConstructionValueRangeVo;
import java.util.Collection;
import java.util.List;
@ -77,4 +78,12 @@ public interface IOutConstructionValueRangeService extends IService<OutConstruct
* @return 所有施工范围产值
*/
OutConstructionAllValueRangeVo getAllValue(OutConstructionValueRangeBo bo);
/**
* 导出数据
*
* @param bo 查询条件
* @param response 响应
*/
void exportExcel(OutConstructionValueRangeBo bo, HttpServletResponse response);
}

View File

@ -1,13 +1,16 @@
package org.dromara.out.service;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.out.domain.OutConstructionValue;
import org.dromara.out.domain.bo.OutConstructionValueBo;
import org.dromara.out.domain.bo.OutConstructionValueFacilityReq;
import org.dromara.out.domain.vo.OutConstructionAllValueVo;
import org.dromara.out.domain.vo.OutConstructionValueVo;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueCategoryVo;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueVo;
import org.dromara.progress.domain.PgsProgressCategory;
import java.math.BigDecimal;
import java.util.Collection;
@ -110,4 +113,23 @@ public interface IOutConstructionValueService extends IService<OutConstructionVa
* @param list 列表
*/
void supplementaryData(List<OutConstructionValueVo> list);
/**
* 导出数据
*
* @param bo 查询条件
* @param response 响应
*/
void exportExcel(OutConstructionValueBo bo, HttpServletResponse response);
/**
* 构建导出需要的数据
*
* @param valueList 施工产值列表
* @param valueCategoryList 进度类别列表
* @param topList 顶层进度类别列表
*/
void buildExportData(List<OutConstructionValue> valueList,
List<OutConstructionValueCategoryVo> valueCategoryList,
List<PgsProgressCategory> topList);
}

View File

@ -2,19 +2,27 @@ package org.dromara.out.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.event.ProcessDeleteEvent;
import org.dromara.common.core.domain.event.ProcessEvent;
import org.dromara.common.core.domain.event.ProcessTaskEvent;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.excel.convert.ExcelBigNumberConvert;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.out.domain.OutConstructionValue;
@ -22,24 +30,36 @@ import org.dromara.out.domain.OutConstructionValueRange;
import org.dromara.out.domain.bo.OutConstructionValueBo;
import org.dromara.out.domain.bo.OutConstructionValueRangeBo;
import org.dromara.out.domain.vo.OutConstructionAllValueRangeVo;
import org.dromara.out.domain.vo.OutConstructionValueRangeVo;
import org.dromara.out.domain.vo.outconstructionvalue.OutConstructionValueCategoryVo;
import org.dromara.out.domain.vo.outconstructionvaluerange.OutConstructionValueRangeMatrixVo;
import org.dromara.out.domain.vo.outconstructionvaluerange.OutConstructionValueRangeProjectVo;
import org.dromara.out.domain.vo.outconstructionvaluerange.OutConstructionValueRangeSubProjectVo;
import org.dromara.out.domain.vo.outconstructionvaluerange.OutConstructionValueRangeVo;
import org.dromara.out.mapper.OutConstructionValueRangeMapper;
import org.dromara.out.service.IOutConstructionValueRangeService;
import org.dromara.out.service.IOutConstructionValueService;
import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.PgsProgressPlanDetail;
import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.progress.service.IPgsProgressPlanDetailService;
import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import java.time.format.DateTimeFormatter;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 施工产值范围Service业务层处理
@ -61,6 +81,9 @@ public class OutConstructionValueRangeServiceImpl extends ServiceImpl<OutConstru
@Resource
private IPgsProgressPlanDetailService progressPlanDetailService;
@Resource
private IBusProjectService projectService;
/**
* 获取指定日期所在的周数(根据中国周规则)
*
@ -126,7 +149,16 @@ public class OutConstructionValueRangeServiceImpl extends ServiceImpl<OutConstru
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<OutConstructionValueRange> lqw = Wrappers.lambdaQuery();
lqw.orderByDesc(OutConstructionValueRange::getId);
lqw.eq(bo.getProjectId() != null, OutConstructionValueRange::getProjectId, bo.getProjectId());
if (bo.getProjectId() != null) {
// 获取当前项目的子项目
List<BusProject> projects = projectService.lambdaQuery()
.eq(BusProject::getPId, bo.getProjectId())
.select(BusProject::getId)
.list();
List<Long> list = new ArrayList<>(projects.stream().map(BusProject::getId).toList());
list.add(bo.getProjectId());
lqw.in(OutConstructionValueRange::getProjectId, list);
}
// 日期范围过滤
if (bo.getStartDate() != null) {
// 获取本周的星期一
@ -219,6 +251,354 @@ public class OutConstructionValueRangeServiceImpl extends ServiceImpl<OutConstru
return vo;
}
/**
* 导出数据
*
* @param bo 查询条件
* @param response 响应
*/
@Override
public void exportExcel(OutConstructionValueRangeBo bo, HttpServletResponse response) {
Long projectId = bo.getProjectId();
if (projectId == null) {
throw new ServiceException("请选择项目");
}
BusProject project = projectService.getById(projectId);
if (project == null) {
throw new ServiceException("项目不存在");
}
// 获取子项目
List<BusProject> projectList = projectService.lambdaQuery()
.eq(BusProject::getPId, projectId)
.list();
projectList.add(project);
Map<Long, String> projectNameMap = projectList.stream()
.collect(Collectors.toMap(BusProject::getId, BusProject::getProjectName));
LambdaQueryWrapper<OutConstructionValueRange> lqw = buildQueryWrapper(bo);
List<OutConstructionValueRange> list = this.list(lqw);
if (CollUtil.isEmpty(list)) {
throw new ServiceException("无数据导出");
}
// 根据周产值查询具体产值
Set<Long> rangeIds = list.stream().map(OutConstructionValueRange::getId).collect(Collectors.toSet());
List<OutConstructionValue> valueList = constructionValueService.lambdaQuery()
.in(OutConstructionValue::getRangeId, rangeIds)
.list();
if (CollUtil.isEmpty(valueList)) {
throw new ServiceException("无数据导出");
}
List<OutConstructionValueCategoryVo> valueCategoryList = new ArrayList<>();
List<PgsProgressCategory> topList = new ArrayList<>();
constructionValueService.buildExportData(valueList, valueCategoryList, topList);
// 汇总数据
List<OutConstructionValueRangeProjectVo> projectVoList = new ArrayList<>();
List<OutConstructionValueRangeSubProjectVo> subProjectVoList = new ArrayList<>();
List<OutConstructionValueRangeMatrixVo> matrixVoList = new ArrayList<>();
// 合计
BigDecimal totalNumber = BigDecimal.ZERO;
BigDecimal totalOwnerValue = BigDecimal.ZERO;
BigDecimal totalOutValue = BigDecimal.ZERO;
BigDecimal subTotalNumber = BigDecimal.ZERO;
BigDecimal subTotalOwnerValue = BigDecimal.ZERO;
BigDecimal subTotalOutValue = BigDecimal.ZERO;
BigDecimal matrixTotalNumber = BigDecimal.ZERO;
BigDecimal matrixTotalOwnerValue = BigDecimal.ZERO;
BigDecimal matrixTotalOutValue = BigDecimal.ZERO;
// 根据名称+结构分类
Map<String, List<PgsProgressCategory>> topNameMap =
topList.stream().collect(Collectors.groupingBy(item -> item.getName() + "_" + item.getRelevancyStructure()));
for (Map.Entry<String, List<PgsProgressCategory>> entry : topNameMap.entrySet()) {
String[] keys = entry.getKey().split("_");
String name = keys[0];
String structure = keys[1];
List<PgsProgressCategory> topNodes = entry.getValue();
List<Long> topIds = topNodes.stream().map(PgsProgressCategory::getId).toList();
// 找出全部子孙节点
List<OutConstructionValueCategoryVo> children = findChildren(valueCategoryList, topIds);
// 子类按名称分组
Map<String, List<OutConstructionValueCategoryVo>> childrenMap =
children.stream().collect(Collectors.groupingBy(OutConstructionValueCategoryVo::getName));
for (Map.Entry<String, List<OutConstructionValueCategoryVo>> childrenEntry : childrenMap.entrySet()) {
String childName = childrenEntry.getKey();
List<OutConstructionValueCategoryVo> childrenEntryValue = childrenEntry.getValue();
// ======= 构建项目级数据 =======
Summary summary = calculateSummary(childrenEntryValue);
OutConstructionValueRangeProjectVo projectVo =
buildProjectVo(project, name, childName, childrenEntryValue, summary);
projectVoList.add(projectVo);
totalNumber = totalNumber.add(summary.number);
totalOwnerValue = totalOwnerValue.add(summary.ownerValue);
totalOutValue = totalOutValue.add(summary.outValue);
// ======= 构建子项目级数据 =======
if (structure.equals("1") || structure.equals("2")) {
Map<Long, List<OutConstructionValueCategoryVo>> subMap =
childrenEntryValue.stream().collect(Collectors.groupingBy(OutConstructionValueCategoryVo::getProjectId));
for (Map.Entry<Long, List<OutConstructionValueCategoryVo>> subEntry : subMap.entrySet()) {
Summary subSummary = calculateSummary(subEntry.getValue());
OutConstructionValueRangeSubProjectVo subVo =
buildSubProjectVo(project, name, childName, subEntry, projectNameMap, subSummary);
subProjectVoList.add(subVo);
subTotalNumber = subTotalNumber.add(subSummary.number);
subTotalOwnerValue = subTotalOwnerValue.add(subSummary.ownerValue);
subTotalOutValue = subTotalOutValue.add(subSummary.outValue);
}
}
// ======= 构建方阵级数据 =======
if (structure.equals("2")) {
Map<String, List<OutConstructionValueCategoryVo>> matrixMap =
childrenEntryValue.stream().collect(Collectors.groupingBy(OutConstructionValueCategoryVo::getMatrixName));
for (Map.Entry<String, List<OutConstructionValueCategoryVo>> matrixEntry : matrixMap.entrySet()) {
Summary matrixSummary = calculateSummary(matrixEntry.getValue());
OutConstructionValueRangeMatrixVo matrixVo =
buildMatrixVo(project, name, childName, matrixEntry, projectNameMap, matrixSummary);
matrixVoList.add(matrixVo);
matrixTotalNumber = matrixTotalNumber.add(matrixSummary.number);
matrixTotalOwnerValue = matrixTotalOwnerValue.add(matrixSummary.ownerValue);
matrixTotalOutValue = matrixTotalOutValue.add(matrixSummary.outValue);
}
}
}
}
// 排序
projectVoList.sort(Comparator.comparing(OutConstructionValueRangeProjectVo::getProgressCategoryName));
subProjectVoList.sort(Comparator.comparing(OutConstructionValueRangeSubProjectVo::getSubProjectName)
.thenComparing(OutConstructionValueRangeSubProjectVo::getProgressCategoryName));
matrixVoList.sort(Comparator.comparing(OutConstructionValueRangeMatrixVo::getSubProjectName)
.thenComparing(OutConstructionValueRangeMatrixVo::getMatrixName)
.thenComparing(OutConstructionValueRangeMatrixVo::getProgressCategoryName));
// 填充合计
OutConstructionValueRangeProjectVo rangeProjectVo = new OutConstructionValueRangeProjectVo();
rangeProjectVo.setProjectName("合计");
rangeProjectVo.setNumber(totalNumber);
rangeProjectVo.setOwnerValue(totalOwnerValue);
rangeProjectVo.setOutValue(totalOutValue);
projectVoList.add(rangeProjectVo);
OutConstructionValueRangeSubProjectVo rangeSubProjectVo = new OutConstructionValueRangeSubProjectVo();
rangeSubProjectVo.setProjectName("合计");
rangeSubProjectVo.setNumber(subTotalNumber);
rangeSubProjectVo.setOwnerValue(subTotalOwnerValue);
rangeSubProjectVo.setOutValue(subTotalOutValue);
subProjectVoList.add(rangeSubProjectVo);
OutConstructionValueRangeMatrixVo rangeMatrixVo = new OutConstructionValueRangeMatrixVo();
rangeMatrixVo.setProjectName("合计");
rangeMatrixVo.setNumber(matrixTotalNumber);
rangeMatrixVo.setOwnerValue(matrixTotalOwnerValue);
rangeMatrixVo.setOutValue(matrixTotalOutValue);
matrixVoList.add(rangeMatrixVo);
// 构建导出数据
buildExportExcel(project.getProjectName(), response, projectVoList, subProjectVoList, matrixVoList);
}
/**
* 查找子级
*
* @param all 所有数据
* @param topIds 顶级ID
* @return 子级
*/
private List<OutConstructionValueCategoryVo> findChildren(
List<OutConstructionValueCategoryVo> all,
List<Long> topIds) {
return all.stream()
.filter(item -> {
String ancestors = item.getAncestors();
if (ancestors == null) return false;
return topIds.stream().anyMatch(topId ->
ancestors.contains("," + topId + ",") ||
ancestors.startsWith(topId + ",") ||
ancestors.endsWith("," + topId) ||
ancestors.equals(String.valueOf(topId))
);
}).toList();
}
/**
* 汇总静态类
*/
static class Summary {
BigDecimal number;
BigDecimal ownerValue;
BigDecimal outValue;
}
/**
* 计算汇总
*
* @param list 数据
* @return 汇总
*/
private Summary calculateSummary(List<OutConstructionValueCategoryVo> list) {
Summary s = new Summary();
s.number = BigDecimal.ZERO;
s.ownerValue = BigDecimal.ZERO;
s.outValue = BigDecimal.ZERO;
for (OutConstructionValueCategoryVo c : list) {
int num = (c.getConfirmNum() == null || c.getConfirmNum() == 0)
? c.getArtificialNum() + c.getUavNum()
: c.getConfirmNum();
s.number = s.number.add(BigDecimal.valueOf(num));
s.ownerValue = s.ownerValue.add(c.getOwnerValue());
s.outValue = s.outValue.add(c.getOutValue());
}
return s;
}
/**
* 获取第一个非空的值
*
* @param list 数据
* @param getter 获取器
* @return 值
*/
private <T> T getFirstNonNull(List<OutConstructionValueCategoryVo> list,
Function<OutConstructionValueCategoryVo, T> getter) {
return list.stream()
.map(getter)
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
/**
* 构建项目VO
*
* @param project 项目
* @param name 名称
* @param childName 子名称
* @param list 数据
* @param summary 合计
* @return 项目VO
*/
private OutConstructionValueRangeProjectVo buildProjectVo(
BusProject project,
String name,
String childName,
List<OutConstructionValueCategoryVo> list,
Summary summary) {
OutConstructionValueRangeProjectVo vo = new OutConstructionValueRangeProjectVo();
vo.setProjectName(project.getProjectName());
vo.setProgressCategoryName(name + "/" + childName);
vo.setUnit(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnit));
vo.setUnitType(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnitType));
vo.setNumber(summary.number);
vo.setOwnerValue(summary.ownerValue);
vo.setOutValue(summary.outValue);
return vo;
}
/**
* 构建子项VO
*
* @param project 项目
* @param name 名称
* @param childName 子名称
* @param entry 数据
* @param summary 合计
* @return 子项VO
*/
private OutConstructionValueRangeSubProjectVo buildSubProjectVo(
BusProject project,
String name,
String childName,
Map.Entry<Long, List<OutConstructionValueCategoryVo>> entry,
Map<Long, String> projectNameMap,
Summary summary) {
OutConstructionValueRangeSubProjectVo vo = new OutConstructionValueRangeSubProjectVo();
vo.setProjectName(project.getProjectName());
vo.setSubProjectName(projectNameMap.get(entry.getKey()));
vo.setProgressCategoryName(name + "/" + childName);
vo.setUnit(getFirstNonNull(entry.getValue(), OutConstructionValueCategoryVo::getUnit));
vo.setUnitType(getFirstNonNull(entry.getValue(), OutConstructionValueCategoryVo::getUnitType));
vo.setNumber(summary.number);
vo.setOwnerValue(summary.ownerValue);
vo.setOutValue(summary.outValue);
return vo;
}
/**
* 构建方阵VO
*
* @param project 项目
* @param name 名称
* @param childName 子名称
* @param entry 数据
* @param projectNameMap 项目名称
* @param summary 合计
* @return 方阵VO
*/
private OutConstructionValueRangeMatrixVo buildMatrixVo(
BusProject project,
String name,
String childName,
Map.Entry<String, List<OutConstructionValueCategoryVo>> entry,
Map<Long, String> projectNameMap,
Summary summary) {
List<OutConstructionValueCategoryVo> list = entry.getValue();
OutConstructionValueRangeMatrixVo vo = new OutConstructionValueRangeMatrixVo();
vo.setProjectName(project.getProjectName());
vo.setMatrixName(entry.getKey());
vo.setProgressCategoryName(name + "/" + childName);
Long pid = list.stream()
.map(OutConstructionValueCategoryVo::getProjectId)
.filter(Objects::nonNull)
.findFirst().orElse(project.getId());
vo.setSubProjectName(projectNameMap.getOrDefault(pid, project.getProjectName()));
vo.setUnit(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnit));
vo.setUnitType(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnitType));
vo.setNumber(summary.number);
vo.setOwnerValue(summary.ownerValue);
vo.setOutValue(summary.outValue);
return vo;
}
/**
* 构建导出Excel
*
* @param projectName 项目名称
* @param response 响应
* @param projectVoList 项目VO
* @param subProjectVoList 子项VO
* @param matrixVoList 方阵VO
*/
private void buildExportExcel(String projectName, HttpServletResponse response,
List<OutConstructionValueRangeProjectVo> projectVoList,
List<OutConstructionValueRangeSubProjectVo> subProjectVoList,
List<OutConstructionValueRangeMatrixVo> matrixVoList) {
String fileName = projectName + "-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + "-" + "施工产值.xlsx";
FileUtils.setAttachmentResponseHeader(response, fileName);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
// 构建 ExcelWriter
try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
.autoCloseStream(false)
// 自动适配
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
// 大数值自动转换 防止失真
.registerConverter(new ExcelBigNumberConvert())
.build()) {
// === Sheet1 ===
WriteSheet sheet1 = EasyExcel.writerSheet(0, "按项目汇总")
.head(OutConstructionValueRangeProjectVo.class)
.build();
excelWriter.write(projectVoList, sheet1);
// === Sheet2 ===
WriteSheet sheet2 = EasyExcel.writerSheet(1, "按子项汇总")
.head(OutConstructionValueRangeSubProjectVo.class)
.build();
excelWriter.write(subProjectVoList, sheet2);
// === Sheet3 ===
WriteSheet sheet3 = EasyExcel.writerSheet(2, "按方阵汇总")
.head(OutConstructionValueRangeMatrixVo.class)
.build();
excelWriter.write(matrixVoList, sheet3);
} catch (IOException e) {
log.error("施工产值Excel导出失败", e);
throw new ServiceException("导出Excel失败");
}
}
/**
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
* 正常使用只需#processEvent.flowCode=='leave1'

View File

@ -1,16 +1,23 @@
package org.dromara.out.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.excel.convert.ExcelBigNumberConvert;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.facility.domain.FacMatrix;
@ -20,7 +27,7 @@ import org.dromara.out.domain.OutConstructionValueRange;
import org.dromara.out.domain.bo.OutConstructionValueBo;
import org.dromara.out.domain.bo.OutConstructionValueFacilityReq;
import org.dromara.out.domain.vo.OutConstructionAllValueVo;
import org.dromara.out.domain.vo.OutConstructionValueVo;
import org.dromara.out.domain.vo.outconstructionvalue.*;
import org.dromara.out.mapper.OutConstructionValueMapper;
import org.dromara.out.service.IOutConstructionValueRangeService;
import org.dromara.out.service.IOutConstructionValueService;
@ -35,11 +42,17 @@ import org.dromara.progress.service.IPgsProgressPlanDetailService;
import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.vo.project.BusProjectVo;
import org.dromara.project.service.IBusProjectService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 施工产值Service业务层处理
@ -65,6 +78,8 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
private final IOutConstructionValueRangeService constructionValueRangeService;
private final IPgsProgressCategoryService progressCategoryService;
/**
* 查询施工产值
*
@ -357,6 +372,402 @@ public class OutConstructionValueServiceImpl extends ServiceImpl<OutConstruction
list.sort(Comparator.comparing(OutConstructionValueVo::getProgressCategoryName, Comparator.nullsLast(String::compareTo)));
}
/**
* 导出数据
*
* @param bo 查询条件
* @param response 响应
*/
@Override
public void exportExcel(OutConstructionValueBo bo, HttpServletResponse response) {
Long projectId = bo.getProjectId();
if (projectId == null) {
throw new ServiceException("请选择项目");
}
BusProject project = projectService.getById(projectId);
if (project == null) {
throw new ServiceException("项目不存在");
}
// 获取子项目
List<BusProject> projectList = projectService.lambdaQuery()
.eq(BusProject::getPId, projectId)
.list();
projectList.add(project);
Map<Long, String> projectNameMap = projectList.stream()
.collect(Collectors.toMap(BusProject::getId, BusProject::getProjectName));
LambdaQueryWrapper<OutConstructionValue> lqw = buildQueryWrapper(bo);
List<OutConstructionValue> valueList = this.list(lqw);
if (CollUtil.isEmpty(valueList)) {
throw new ServiceException("无数据导出");
}
List<OutConstructionValueCategoryVo> valueCategoryList = new ArrayList<>();
List<PgsProgressCategory> topList = new ArrayList<>();
this.buildExportData(valueList, valueCategoryList, topList);
// 汇总数据
List<OutConstructionValueProjectVo> projectVoList = new ArrayList<>();
List<OutConstructionValueSubProjectVo> subProjectVoList = new ArrayList<>();
List<OutConstructionValueMatrixVo> matrixVoList = new ArrayList<>();
// 合计
BigDecimal totalNumber = BigDecimal.ZERO;
BigDecimal totalOwnerValue = BigDecimal.ZERO;
BigDecimal totalOutValue = BigDecimal.ZERO;
BigDecimal subTotalNumber = BigDecimal.ZERO;
BigDecimal subTotalOwnerValue = BigDecimal.ZERO;
BigDecimal subTotalOutValue = BigDecimal.ZERO;
BigDecimal matrixTotalNumber = BigDecimal.ZERO;
BigDecimal matrixTotalOwnerValue = BigDecimal.ZERO;
BigDecimal matrixTotalOutValue = BigDecimal.ZERO;
// 根据名称+结构分类
Map<String, List<PgsProgressCategory>> topNameMap =
topList.stream().collect(Collectors.groupingBy(item -> item.getName() + "_" + item.getRelevancyStructure()));
for (Map.Entry<String, List<PgsProgressCategory>> entry : topNameMap.entrySet()) {
String[] keys = entry.getKey().split("_");
String name = keys[0];
String structure = keys[1];
List<PgsProgressCategory> topNodes = entry.getValue();
List<Long> topIds = topNodes.stream().map(PgsProgressCategory::getId).toList();
// 找出全部子孙节点
List<OutConstructionValueCategoryVo> children = findChildren(valueCategoryList, topIds);
// 子类按名称分组
Map<String, List<OutConstructionValueCategoryVo>> childrenMap =
children.stream().collect(Collectors.groupingBy(OutConstructionValueCategoryVo::getName));
for (Map.Entry<String, List<OutConstructionValueCategoryVo>> childrenEntry : childrenMap.entrySet()) {
String childName = childrenEntry.getKey();
List<OutConstructionValueCategoryVo> childrenEntryValue = childrenEntry.getValue();
// ======= 构建项目级数据 =======
Summary summary = calculateSummary(childrenEntryValue);
OutConstructionValueProjectVo projectVo =
buildProjectVo(project, name, childName, childrenEntryValue, summary);
projectVoList.add(projectVo);
totalNumber = totalNumber.add(summary.number);
totalOwnerValue = totalOwnerValue.add(summary.ownerValue);
totalOutValue = totalOutValue.add(summary.outValue);
// ======= 构建子项目级数据 =======
if (structure.equals("1") || structure.equals("2")) {
Map<Long, List<OutConstructionValueCategoryVo>> subMap =
childrenEntryValue.stream().collect(Collectors.groupingBy(OutConstructionValueCategoryVo::getProjectId));
for (Map.Entry<Long, List<OutConstructionValueCategoryVo>> subEntry : subMap.entrySet()) {
Summary subSummary = calculateSummary(subEntry.getValue());
OutConstructionValueSubProjectVo subVo =
buildSubProjectVo(project, name, childName, subEntry, projectNameMap, subSummary);
subProjectVoList.add(subVo);
subTotalNumber = subTotalNumber.add(subSummary.number);
subTotalOwnerValue = subTotalOwnerValue.add(subSummary.ownerValue);
subTotalOutValue = subTotalOutValue.add(subSummary.outValue);
}
}
// ======= 构建方阵级数据 =======
if (structure.equals("2")) {
Map<String, List<OutConstructionValueCategoryVo>> matrixMap =
childrenEntryValue.stream().collect(Collectors.groupingBy(OutConstructionValueCategoryVo::getMatrixName));
for (Map.Entry<String, List<OutConstructionValueCategoryVo>> matrixEntry : matrixMap.entrySet()) {
Summary matrixSummary = calculateSummary(matrixEntry.getValue());
OutConstructionValueMatrixVo matrixVo =
buildMatrixVo(project, name, childName, matrixEntry, projectNameMap, matrixSummary);
matrixVoList.add(matrixVo);
matrixTotalNumber = matrixTotalNumber.add(matrixSummary.number);
matrixTotalOwnerValue = matrixTotalOwnerValue.add(matrixSummary.ownerValue);
matrixTotalOutValue = matrixTotalOutValue.add(matrixSummary.outValue);
}
}
}
}
// 排序
projectVoList.sort(Comparator.comparing(OutConstructionValueProjectVo::getProgressCategoryName));
subProjectVoList.sort(Comparator.comparing(OutConstructionValueSubProjectVo::getSubProjectName)
.thenComparing(OutConstructionValueSubProjectVo::getProgressCategoryName));
matrixVoList.sort(Comparator.comparing(OutConstructionValueMatrixVo::getSubProjectName)
.thenComparing(OutConstructionValueMatrixVo::getMatrixName)
.thenComparing(OutConstructionValueMatrixVo::getProgressCategoryName));
// 填充合计
OutConstructionValueProjectVo rangeProjectVo = new OutConstructionValueProjectVo();
rangeProjectVo.setProjectName("合计");
rangeProjectVo.setNumber(totalNumber);
rangeProjectVo.setOwnerValue(totalOwnerValue);
rangeProjectVo.setOutValue(totalOutValue);
projectVoList.add(rangeProjectVo);
OutConstructionValueSubProjectVo rangeSubProjectVo = new OutConstructionValueSubProjectVo();
rangeSubProjectVo.setProjectName("合计");
rangeSubProjectVo.setNumber(subTotalNumber);
rangeSubProjectVo.setOwnerValue(subTotalOwnerValue);
rangeSubProjectVo.setOutValue(subTotalOutValue);
subProjectVoList.add(rangeSubProjectVo);
OutConstructionValueMatrixVo rangeMatrixVo = new OutConstructionValueMatrixVo();
rangeMatrixVo.setProjectName("合计");
rangeMatrixVo.setNumber(matrixTotalNumber);
rangeMatrixVo.setOwnerValue(matrixTotalOwnerValue);
rangeMatrixVo.setOutValue(matrixTotalOutValue);
matrixVoList.add(rangeMatrixVo);
// 构建导出数据
buildExportExcel(project.getProjectName(), response, projectVoList, subProjectVoList, matrixVoList);
}
/**
* 构建导出需要的数据
*
* @param valueList 施工产值列表
* @param valueCategoryList 进度类别列表
* @param topList 顶层进度类别列表
*/
@Override
public void buildExportData(List<OutConstructionValue> valueList,
List<OutConstructionValueCategoryVo> valueCategoryList,
List<PgsProgressCategory> topList) {
// 获取对应进度类别
Set<Long> progressCategoryIds = valueList.stream()
.map(OutConstructionValue::getProgressCategoryId)
.collect(Collectors.toSet());
List<PgsProgressCategory> progressCategoryList = progressCategoryService.lambdaQuery()
.in(PgsProgressCategory::getId, progressCategoryIds)
.list();
valueCategoryList.addAll(
valueList.stream().map(value -> {
OutConstructionValueCategoryVo vo = new OutConstructionValueCategoryVo();
BeanUtils.copyProperties(value, vo);
PgsProgressCategory category = progressCategoryList.stream()
.filter(p -> p.getId().equals(value.getProgressCategoryId()))
.findFirst().orElse(null);
if (category != null) {
vo.setProjectId(category.getProjectId());
vo.setMatrixName(category.getMatrixName());
vo.setName(category.getName());
vo.setUnitType(category.getUnitType());
vo.setUnit(category.getUnit());
vo.setAncestors(category.getAncestors());
vo.setRelevancyStructure(category.getRelevancyStructure());
}
return vo;
}).toList()
);
// 顶级进度类别
Set<Long> topProgressCategoryIds = progressCategoryList.stream()
.map(p -> {
String ancestors = p.getAncestors();
if (StringUtils.isNotBlank(ancestors)) {
String[] split = ancestors.split(",");
return split.length > 1 ? split[1] : null;
}
return null;
}).filter(Objects::nonNull)
.map(Long::parseLong)
.collect(Collectors.toSet());
List<PgsProgressCategory> tops = progressCategoryService.listByIds(topProgressCategoryIds)
.stream()
.sorted(Comparator.comparing(PgsProgressCategory::getSort))
.toList();
topList.addAll(tops);
}
/**
* 查找子级
*
* @param all 所有数据
* @param topIds 顶级ID
* @return 子级
*/
private List<OutConstructionValueCategoryVo> findChildren(
List<OutConstructionValueCategoryVo> all,
List<Long> topIds) {
return all.stream()
.filter(item -> {
String ancestors = item.getAncestors();
if (ancestors == null) return false;
return topIds.stream().anyMatch(topId ->
ancestors.contains("," + topId + ",") ||
ancestors.startsWith(topId + ",") ||
ancestors.endsWith("," + topId) ||
ancestors.equals(String.valueOf(topId))
);
}).toList();
}
/**
* 汇总静态类
*/
static class Summary {
BigDecimal number;
BigDecimal ownerValue;
BigDecimal outValue;
}
/**
* 计算汇总
*
* @param list 数据
* @return 汇总
*/
private Summary calculateSummary(List<OutConstructionValueCategoryVo> list) {
Summary s = new Summary();
s.number = BigDecimal.ZERO;
s.ownerValue = BigDecimal.ZERO;
s.outValue = BigDecimal.ZERO;
for (OutConstructionValueCategoryVo c : list) {
int num = (c.getConfirmNum() == null || c.getConfirmNum() == 0)
? c.getArtificialNum() + c.getUavNum()
: c.getConfirmNum();
s.number = s.number.add(BigDecimal.valueOf(num));
s.ownerValue = s.ownerValue.add(c.getOwnerValue());
s.outValue = s.outValue.add(c.getOutValue());
}
return s;
}
/**
* 获取第一个非空的值
*
* @param list 数据
* @param getter 获取器
* @return 值
*/
private <T> T getFirstNonNull(List<OutConstructionValueCategoryVo> list,
Function<OutConstructionValueCategoryVo, T> getter) {
return list.stream()
.map(getter)
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
/**
* 构建项目VO
*
* @param project 项目
* @param name 名称
* @param childName 子名称
* @param list 数据
* @param summary 合计
* @return 项目VO
*/
private OutConstructionValueProjectVo buildProjectVo(
BusProject project,
String name,
String childName,
List<OutConstructionValueCategoryVo> list,
Summary summary) {
OutConstructionValueProjectVo vo = new OutConstructionValueProjectVo();
vo.setProjectName(project.getProjectName());
vo.setProgressCategoryName(name + "/" + childName);
vo.setUnit(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnit));
vo.setUnitType(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnitType));
vo.setNumber(summary.number);
vo.setOwnerValue(summary.ownerValue);
vo.setOutValue(summary.outValue);
return vo;
}
/**
* 构建子项VO
*
* @param project 项目
* @param name 名称
* @param childName 子名称
* @param entry 数据
* @param summary 合计
* @return 子项VO
*/
private OutConstructionValueSubProjectVo buildSubProjectVo(
BusProject project,
String name,
String childName,
Map.Entry<Long, List<OutConstructionValueCategoryVo>> entry,
Map<Long, String> projectNameMap,
Summary summary) {
OutConstructionValueSubProjectVo vo = new OutConstructionValueSubProjectVo();
vo.setProjectName(project.getProjectName());
vo.setSubProjectName(projectNameMap.get(entry.getKey()));
vo.setProgressCategoryName(name + "/" + childName);
vo.setUnit(getFirstNonNull(entry.getValue(), OutConstructionValueCategoryVo::getUnit));
vo.setUnitType(getFirstNonNull(entry.getValue(), OutConstructionValueCategoryVo::getUnitType));
vo.setNumber(summary.number);
vo.setOwnerValue(summary.ownerValue);
vo.setOutValue(summary.outValue);
return vo;
}
/**
* 构建方阵VO
*
* @param project 项目
* @param name 名称
* @param childName 子名称
* @param entry 数据
* @param projectNameMap 项目名称
* @param summary 合计
* @return 方阵VO
*/
private OutConstructionValueMatrixVo buildMatrixVo(
BusProject project,
String name,
String childName,
Map.Entry<String, List<OutConstructionValueCategoryVo>> entry,
Map<Long, String> projectNameMap,
Summary summary) {
List<OutConstructionValueCategoryVo> list = entry.getValue();
OutConstructionValueMatrixVo vo = new OutConstructionValueMatrixVo();
vo.setProjectName(project.getProjectName());
vo.setMatrixName(entry.getKey());
vo.setProgressCategoryName(name + "/" + childName);
Long pid = list.stream()
.map(OutConstructionValueCategoryVo::getProjectId)
.filter(Objects::nonNull)
.findFirst().orElse(project.getId());
vo.setSubProjectName(projectNameMap.getOrDefault(pid, project.getProjectName()));
vo.setUnit(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnit));
vo.setUnitType(getFirstNonNull(list, OutConstructionValueCategoryVo::getUnitType));
vo.setNumber(summary.number);
vo.setOwnerValue(summary.ownerValue);
vo.setOutValue(summary.outValue);
return vo;
}
/**
* 构建导出Excel
*
* @param projectName 项目名称
* @param response 响应
* @param projectVoList 项目VO
* @param subProjectVoList 子项VO
* @param matrixVoList 方阵VO
*/
private void buildExportExcel(String projectName, HttpServletResponse response,
List<OutConstructionValueProjectVo> projectVoList,
List<OutConstructionValueSubProjectVo> subProjectVoList,
List<OutConstructionValueMatrixVo> matrixVoList) {
String fileName = projectName + "-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + "-" + "施工产值.xlsx";
FileUtils.setAttachmentResponseHeader(response, fileName);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
// 构建 ExcelWriter
try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
.autoCloseStream(false)
// 自动适配
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
// 大数值自动转换 防止失真
.registerConverter(new ExcelBigNumberConvert())
.build()) {
// === Sheet1 ===
WriteSheet sheet1 = EasyExcel.writerSheet(0, "按项目汇总")
.head(OutConstructionValueProjectVo.class)
.build();
excelWriter.write(projectVoList, sheet1);
// === Sheet2 ===
WriteSheet sheet2 = EasyExcel.writerSheet(1, "按子项汇总")
.head(OutConstructionValueSubProjectVo.class)
.build();
excelWriter.write(subProjectVoList, sheet2);
// === Sheet3 ===
WriteSheet sheet3 = EasyExcel.writerSheet(2, "按方阵汇总")
.head(OutConstructionValueMatrixVo.class)
.build();
excelWriter.write(matrixVoList, sheet3);
} catch (IOException e) {
log.error("施工产值Excel导出失败", e);
throw new ServiceException("导出Excel失败");
}
}
public void getName(OutConstructionValueVo vo) {
//查询分部工程以及分项工程
PgsProgressCategoryVo pgsProgressCategoryVo = pgsProgressCategoryService.queryById(vo.getProgressCategoryId());

View File

@ -0,0 +1,77 @@
package org.dromara.progress.domain.dto.progresscategory;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-11-28 14:24
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PgsProgressCategoryImportTemp {
/**
* 主键id
*/
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 方阵id
*/
private Long matrixId;
/**
* 方阵名称
*/
private String matrixName;
/**
* 类别名称
*/
private String name;
/**
* 计量方式0无 1数量 2百分比
*/
private String unitType;
/**
* 总数量
*/
private BigDecimal total;
/**
* 已完成数量
*/
private BigDecimal completed;
/**
* 计划总数量
*/
private BigDecimal planTotal;
/**
* 完成状态0未开始 1进行中 2已完成
*/
private String status;
/**
* 工作类型
*/
private String workType;
/**
* 新增完成数量
*/
private BigDecimal newComplete;
}

View File

@ -2850,6 +2850,9 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
log.info("导入数据:{}", voList);
// 获取当前的所有旧数据
List<Long> ids = voList.stream().map(PgsProgressCategoryEnterTemplateVo::getId).toList();
if (CollUtil.isEmpty(ids)) {
throw new ServiceException("数据错误,无法从当前表格中获取到有效数据");
}
List<PgsProgressCategory> categoryList = this.listByIds(ids);
if (CollUtil.isEmpty(categoryList)) {
throw new ServiceException("数据错误,当前项目无此数据");
@ -2862,18 +2865,22 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
.list();
projects.add(project);
List<Long> allProjectIds = projects.stream().map(BusProject::getId).toList();
List<PgsProgressCategoryImportTemp> tempList = new ArrayList<>();
List<PgsProgressCategory> list = voList.stream().map(vo -> {
PgsProgressCategory update = new PgsProgressCategory();
PgsProgressCategoryImportTemp temp = new PgsProgressCategoryImportTemp();
Long id = vo.getId();
update.setId(id);
temp.setId(id);
if (progressCategoryMap.containsKey(id)) {
PgsProgressCategory old = progressCategoryMap.get(id);
// 如果不是当前项目,或当前项目的子项目,则返回 null
if (!allProjectIds.contains(old.getProjectId())) {
return null;
}
BigDecimal oldCompleted = old.getCompleted();
// 当已完成数据等于总数,返回 null
if (old.getCompleted().compareTo(old.getTotal()) >= 0) {
if (old.getTotal().compareTo(BigDecimal.ZERO) == 0 || oldCompleted.compareTo(old.getTotal()) >= 0) {
return null;
}
// 如果完成数量小于等于0则返回 null
@ -2882,9 +2889,17 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
return null;
}
// 计算完成数量
BigDecimal add = old.getCompleted().add(completionCount);
BigDecimal add = oldCompleted.add(completionCount);
// 确保完成数量小于等于总数
BigDecimal minVal = add.min(old.getTotal());
// 记录本次新增的数量
BigDecimal newCompleted = minVal.subtract(oldCompleted);
temp.setNewComplete(newCompleted);
// 如果完成数量等于总数量,设置为完成状态
if (minVal.compareTo(old.getTotal()) == 0) {
update.setStatus(PgsFinishStatusEnum.FINISH.getValue());
}
tempList.add(temp);
update.setCompleted(minVal);
} else {
log.warn("未匹配的值 => id{}name{}", id, vo.getName());
@ -2895,7 +2910,6 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
if (CollUtil.isEmpty(list)) {
throw new ServiceException("没有需要更新的数据");
}
boolean b = this.updateBatchById(list);
if (!b) {
throw new ServiceException("更新失败");
@ -2906,6 +2920,9 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
List<PgsProgressPlanDetail> detailList = progressPlanDetailService.lambdaQuery()
.in(PgsProgressPlanDetail::getProgressCategoryId, updateList)
.list();
if (CollUtil.isEmpty(detailList)) {
// 详情为空,直接创建新详情数据
}
return "导入成功,共更新" + list.size() + "条数据";
}

View File

@ -1146,12 +1146,12 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
String file = req.getFile();
String tif = req.getTif();
if (StringUtils.isNotBlank(file)) {
fileUrl = droneBigImageProperties.getUrl() + file;
fileUrl = file;
} else {
fileUrl = req.getFileUrl();
}
if (StringUtils.isNotBlank(tif)) {
tifUrl = droneBigImageProperties.getUrl() + tif;
tifUrl = tif;
} else {
tifUrl = req.getTifUrl();
}
@ -1225,6 +1225,7 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
recognizeVo = recognizerManager.recognize(fileUrl);
} catch (Exception e) {
log.error("识别失败:{}", e.getMessage());
return CompletableFuture.completedFuture(false);
}
if (recognizeVo == null) {
return CompletableFuture.completedFuture(false);
@ -1288,7 +1289,7 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
}
} catch (IOException | URISyntaxException e) {
log.error("将识别数据同步到图片上失败", e);
throw new ServiceException("将识别数据同步到图片上失败", HttpStatus.ERROR);
return CompletableFuture.completedFuture(false);
}
String recognizerStr = JSONUtil.toJsonStr(recognizerVoList);
// 更新数据和状态

View File

@ -96,12 +96,12 @@ public class XzdBxBxsqServiceImpl extends ServiceImpl<XzdBxBxsqMapper, XzdBxBxsq
@Override
public TableDataInfo<XzdBxBxsqVo> queryPageList(XzdBxBxsqBo bo, PageQuery pageQuery) {
//暂时定为只能看见自己的报销
if (bo.getBxr() == null && !LoginHelper.isSuperAdmin()) {
/* if (bo.getBxr() == null && !LoginHelper.isSuperAdmin()) {
bo.setBxr(LoginHelper.getUserId());
}
}*/
LambdaQueryWrapper<XzdBxBxsq> lqw = buildQueryWrapper(bo);
Page<XzdBxBxsqVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
Page<XzdBxBxsqVo> result = baseMapper.selectPage(pageQuery.build(), lqw);
setValue(result.getRecords());
return TableDataInfo.build(result);
}

View File

@ -276,10 +276,10 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
public TableDataInfo<FlowTaskVo> pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
List<Long> definitionIds = new ArrayList<>();
if (!"0".equals(flowTaskBo.getProjectId())){
if (!"0".equals(flowTaskBo.getProjectId())) {
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>()
.select(FlowDefinition::getId)
.like(FlowDefinition::getFlowCode, flowTaskBo.getProjectId()));
.like(StringUtils.isNotBlank(flowTaskBo.getProjectId()), FlowDefinition::getFlowCode, flowTaskBo.getProjectId()));
if (flowDefinitions != null && !flowDefinitions.isEmpty()) {
flowDefinitions.forEach(flowDefinition -> {
definitionIds.add(flowDefinition.getId());
@ -292,7 +292,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr());
queryWrapper.in("t.flow_status", BusinessStatusEnum.WAITING.getStatus());
Page<FlowTaskVo> page = this.getFlowTaskDefinitionIdsVoPage(pageQuery,definitionIds, queryWrapper);
Page<FlowTaskVo> page = this.getFlowTaskDefinitionIdsVoPage(pageQuery, definitionIds, queryWrapper);
return TableDataInfo.build(page);
}
@ -306,7 +306,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
public TableDataInfo<FlowHisTaskVo> pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
List<Long> definitionIds = new ArrayList<>();
if (!"0".equals(flowTaskBo.getProjectId())){
if (!"0".equals(flowTaskBo.getProjectId())) {
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>()
.select(FlowDefinition::getId)
.like(FlowDefinition::getFlowCode, flowTaskBo.getProjectId()));
@ -322,7 +322,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
queryWrapper.in("t.approver", LoginHelper.getUserIdStr());
queryWrapper.orderByDesc("t.create_time").orderByDesc("t.update_time");
Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishDefinitionIdsTask(pageQuery.build(),definitionIds, queryWrapper);
Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishDefinitionIdsTask(pageQuery.build(), definitionIds, queryWrapper);
return TableDataInfo.build(page);
}
@ -356,8 +356,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
}
return page;
}
private Page<FlowTaskVo> getFlowTaskDefinitionIdsVoPage(PageQuery pageQuery, List<Long> definitionIds, QueryWrapper<FlowTaskBo> queryWrapper) {
Page<FlowTaskVo> page = flwTaskMapper.getListRunTaskDefinitionIds(pageQuery.build(),definitionIds, queryWrapper);
Page<FlowTaskVo> page = flwTaskMapper.getListRunTaskDefinitionIds(pageQuery.build(), definitionIds, queryWrapper);
List<FlowTaskVo> records = page.getRecords();
if (CollUtil.isNotEmpty(records)) {
List<Long> taskIds = StreamUtils.toList(records, FlowTaskVo::getId);
@ -396,7 +397,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
public TableDataInfo<FlowTaskVo> pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
List<Long> definitionIds = new ArrayList<>();
if (!"0".equals(flowTaskBo.getProjectId())){
if (!"0".equals(flowTaskBo.getProjectId())) {
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>()
.select(FlowDefinition::getId)
.like(FlowDefinition::getFlowCode, flowTaskBo.getProjectId()));
@ -409,9 +410,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
return null;
}
}
queryWrapper.eq(StringUtils.isNotBlank(flowTaskBo.getIsRead()),"t.is_read", flowTaskBo.getIsRead());
queryWrapper.eq(StringUtils.isNotBlank(flowTaskBo.getIsRead()), "t.is_read", flowTaskBo.getIsRead());
queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr());
Page<FlowTaskVo> page = flwTaskMapper.getTaskCopyDefinitionIdsByPage(pageQuery.build(),definitionIds, queryWrapper);
Page<FlowTaskVo> page = flwTaskMapper.getTaskCopyDefinitionIdsByPage(pageQuery.build(), definitionIds, queryWrapper);
return TableDataInfo.build(page);
}
@ -598,7 +599,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
for (FlowNode flowNode : nextFlowNodes) {
buildNextTaskList.stream().filter(t -> t.getNodeCode().equals(flowNode.getNodeCode())).findFirst().ifPresent(t -> {
if (CollUtil.isNotEmpty(t.getPermissionList())) {
List<UserDTO> users = flwTaskAssigneeService.fetchUsersByStorageIds(String.join(StringUtils.SEPARATOR, t.getPermissionList()),null);
List<UserDTO> users = flwTaskAssigneeService.fetchUsersByStorageIds(String.join(StringUtils.SEPARATOR, t.getPermissionList()), null);
if (CollUtil.isNotEmpty(users)) {
flowNode.setPermissionFlag(StreamUtils.join(users, e -> String.valueOf(e.getUserId())));
}