Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
@ -1,10 +1,7 @@
|
||||
package org.dromara.common.excel.coryUtils;
|
||||
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@ -84,7 +81,7 @@ public class ExcelReader {
|
||||
SheetData sheetData = new SheetData();
|
||||
sheetData.setSheetName(sheet.getSheetName());
|
||||
|
||||
processSheetData(sheet, sheetData);
|
||||
processSheetData(workbook,sheet, sheetData);
|
||||
sheetDataList.add(sheetData);
|
||||
}
|
||||
}
|
||||
@ -114,7 +111,7 @@ public class ExcelReader {
|
||||
sheetData.setSheetName(sheet.getSheetName());
|
||||
|
||||
// 处理单个sheet的数据
|
||||
processSheetData(sheet, sheetData);
|
||||
processSheetData(workbook, sheet, sheetData);
|
||||
|
||||
sheetDataList.add(sheetData);
|
||||
}
|
||||
@ -129,7 +126,7 @@ public class ExcelReader {
|
||||
/**
|
||||
* 处理单个工作表的数据
|
||||
*/
|
||||
private static void processSheetData(org.apache.poi.ss.usermodel.Sheet sheet, SheetData sheetData) {
|
||||
private static void processSheetData(Workbook workbook, Sheet sheet, SheetData sheetData) {
|
||||
boolean foundChineseStart = false;
|
||||
List<List<String>> data = new ArrayList<>();
|
||||
boolean isFirstRow = true;
|
||||
@ -140,29 +137,44 @@ public class ExcelReader {
|
||||
isFirstRow = false;
|
||||
continue;
|
||||
}
|
||||
if(hasValidData(workbook,row)){
|
||||
List<String> rowData = new ArrayList<>();
|
||||
// 读取A到E列(索引0到4)
|
||||
for (int cellIndex = 0; cellIndex < 6; cellIndex++) {
|
||||
Cell cell = row.getCell(cellIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
|
||||
rowData.add(getCellValue(workbook,cell));
|
||||
}
|
||||
|
||||
List<String> rowData = new ArrayList<>();
|
||||
// 读取A到E列(索引0到4)
|
||||
for (int cellIndex = 0; cellIndex < 6; cellIndex++) {
|
||||
Cell cell = row.getCell(cellIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
|
||||
rowData.add(getCellValue(cell));
|
||||
// 检查是否找到中文数字开头的行
|
||||
String aColumnValue = rowData.get(0).trim();
|
||||
if (aColumnValue.matches(CHINESE_NUMBERS_REGEX)) {
|
||||
foundChineseStart = true;
|
||||
}
|
||||
|
||||
// 只有找到中文数字开头的行之后,才开始收集数据
|
||||
if (foundChineseStart) {
|
||||
data.add(rowData);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否找到中文数字开头的行
|
||||
String aColumnValue = rowData.get(0).trim();
|
||||
if (aColumnValue.matches(CHINESE_NUMBERS_REGEX)) {
|
||||
foundChineseStart = true;
|
||||
}
|
||||
|
||||
// 只有找到中文数字开头的行之后,才开始收集数据
|
||||
if (foundChineseStart) {
|
||||
data.add(rowData);
|
||||
}
|
||||
}
|
||||
|
||||
sheetData.setData(data);
|
||||
}
|
||||
|
||||
private static boolean hasValidData(Workbook workbook,Row row) {
|
||||
// 遍历行中的所有单元格
|
||||
for (int cellIndex = 0; cellIndex < row.getLastCellNum(); cellIndex++) {
|
||||
Cell cell = row.getCell(cellIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
|
||||
String cellValue = getCellValue(workbook, cell).trim();
|
||||
|
||||
// 只要有一个单元格有非空值,就认为是有效行
|
||||
if (!cellValue.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 根据数据构建树形结构
|
||||
*/
|
||||
@ -263,7 +275,7 @@ public class ExcelReader {
|
||||
/**
|
||||
* 获取单元格的值,处理不同数据类型
|
||||
*/
|
||||
private static String getCellValue(Cell cell) {
|
||||
private static String getCellValue(Workbook workbook, Cell cell) {
|
||||
if (cell == null) {
|
||||
return "";
|
||||
}
|
||||
@ -278,6 +290,21 @@ public class ExcelReader {
|
||||
return numericValue.substring(0, numericValue.length() - 2);
|
||||
}
|
||||
return numericValue;
|
||||
case FORMULA:
|
||||
//这样对于字符串cell.getStringCellValue()方法即可取得其值,如果公式生成的是数值,使用cell.getStringCellValue()方法会抛出IllegalStateException异常,在异常处理中使用cell.getNumericCellValue();
|
||||
// 1. 获取公式文本(如 "A1+B1")
|
||||
String formula = cell.getCellFormula();
|
||||
System.out.println("公式文本:" + formula);
|
||||
|
||||
// 2. 创建公式计算器(关键步骤:用于计算公式结果)
|
||||
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
|
||||
|
||||
// 3. 计算公式,返回包含结果类型和值的CellValue对象
|
||||
CellValue cellValue = evaluator.evaluate(cell);
|
||||
|
||||
// 4. 根据结果类型提取值
|
||||
return getValue( cellValue.getCellType(), cellValue);
|
||||
|
||||
case BOOLEAN:
|
||||
return String.valueOf(cell.getBooleanCellValue());
|
||||
default:
|
||||
@ -285,6 +312,19 @@ public class ExcelReader {
|
||||
}
|
||||
}
|
||||
|
||||
private static String getValue( CellType resultType, CellValue cellValue) {
|
||||
return switch (resultType) {
|
||||
case NUMERIC -> String.valueOf(cellValue.getNumberValue());
|
||||
case STRING -> String.valueOf(cellValue.getStringValue());
|
||||
case BOOLEAN -> String.valueOf(cellValue.getBooleanValue());
|
||||
case ERROR -> String.valueOf(cellValue.getErrorValue());
|
||||
case BLANK -> String.valueOf(CellType.BLANK);
|
||||
default ->
|
||||
// 保留原公式(不处理的类型)
|
||||
cellValue.getStringValue();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据A列的值确定父节点的键
|
||||
*/
|
||||
|
||||
@ -141,8 +141,8 @@ public class BusMrpBaseController extends BaseController {
|
||||
* 获取剩余量
|
||||
*/
|
||||
@GetMapping("/remaining")
|
||||
public R<Map<String,Object>> remaining(Long suppliespriceId,Long mrpBaseId) {
|
||||
return R.ok(busMrpBaseService.remaining(suppliespriceId,mrpBaseId));
|
||||
public R<Map<String,Object>> remaining(Long projectId, String suppliespriceName,String specification,Long mrpBaseId) {
|
||||
return R.ok(busMrpBaseService.remaining(projectId,suppliespriceName,specification,mrpBaseId));
|
||||
}
|
||||
|
||||
|
||||
@ -182,19 +182,20 @@ public class BusMrpBaseController extends BaseController {
|
||||
@GetMapping("/coryEngineeringList")
|
||||
public R<List<BusBillofquantities>> obtainTheList(CoryObtainTheListReq req) {
|
||||
// public R<List<ObtainTheListRes>> obtainTheList(CoryObtainTheListReq req) {
|
||||
BusBillofquantitiesVersions one = busBillofquantitiesVersionsService.getOne(Wrappers.<BusBillofquantitiesVersions>lambdaQuery()
|
||||
.eq(BusBillofquantitiesVersions::getWorkOrderType, "3") //物资工程量清单
|
||||
.eq(BusBillofquantitiesVersions::getProjectId, req.getProjectId())
|
||||
.eq(BusBillofquantitiesVersions::getVersions, req.getVersions())
|
||||
.eq(BusBillofquantitiesVersions::getStatus, BusinessStatusEnum.FINISH.getStatus())
|
||||
.last("limit 1")
|
||||
);
|
||||
if (one == null){
|
||||
throw new ServiceException("请先完成物资工程量清单");
|
||||
}
|
||||
List<BusBillofquantities> list = busBillofquantitiesService.list(Wrappers.<BusBillofquantities>lambdaQuery()
|
||||
.eq(BusBillofquantities::getVersions, one.getVersions())
|
||||
);
|
||||
// BusBillofquantitiesVersions one = busBillofquantitiesVersionsService.getOne(Wrappers.<BusBillofquantitiesVersions>lambdaQuery()
|
||||
// .eq(BusBillofquantitiesVersions::getWorkOrderType, "3") //物资工程量清单
|
||||
// .eq(BusBillofquantitiesVersions::getProjectId, req.getProjectId())
|
||||
// .eq(BusBillofquantitiesVersions::getVersions, req.getVersions())
|
||||
// .eq(BusBillofquantitiesVersions::getStatus, BusinessStatusEnum.FINISH.getStatus())
|
||||
// .last("limit 1")
|
||||
// );
|
||||
// if (one == null){
|
||||
// throw new ServiceException("请先完成物资工程量清单");
|
||||
// }
|
||||
// List<BusBillofquantities> list = busBillofquantitiesService.list(Wrappers.<BusBillofquantities>lambdaQuery()
|
||||
// .eq(BusBillofquantities::getVersions, one.getVersions())
|
||||
// );
|
||||
// return R.ok(list);
|
||||
// List<ObtainTheListRes> obtainTheListRes = new ArrayList<>();
|
||||
// list.forEach(billofquantities -> {
|
||||
// ObtainTheListRes res = new ObtainTheListRes();
|
||||
@ -208,8 +209,19 @@ public class BusMrpBaseController extends BaseController {
|
||||
// // 3. 递归组装树形结构,从顶级节点(pid=0)开始
|
||||
// List<ObtainTheListRes> treeList = buildTree("0", parentMap);
|
||||
// return R.ok(treeList);
|
||||
return R.ok(list);
|
||||
// return R.ok(busBillofquantitiesService.getBaseMapper().selectList(new LambdaQueryWrapper<BusBillofquantities>().eq(BusBillofquantities::getPid, req.getSid())));
|
||||
List<BusBillofquantities> busBillofquantities = busBillofquantitiesService.getBaseMapper()
|
||||
.selectList(new LambdaQueryWrapper<BusBillofquantities>()
|
||||
.eq(BusBillofquantities::getProjectId, req.getProjectId())
|
||||
.eq(BusBillofquantities::getName, req.getSid()));
|
||||
List<String> sids = new ArrayList<>();
|
||||
busBillofquantities.forEach(busBillofquantities1 -> {
|
||||
sids.add(busBillofquantities1.getSid());
|
||||
});
|
||||
return R.ok(busBillofquantitiesService
|
||||
.getBaseMapper()
|
||||
.selectList(new LambdaQueryWrapper<BusBillofquantities>()
|
||||
.eq(BusBillofquantities::getProjectId, req.getProjectId())
|
||||
.in(BusBillofquantities::getPid, sids)));
|
||||
}
|
||||
|
||||
private List<ObtainTheListRes> buildTree(String parentId, Map<String, List<ObtainTheListRes>> parentMap) {
|
||||
|
||||
@ -86,5 +86,5 @@ public interface IBusMrpBaseService extends IService<BusMrpBase>{
|
||||
/**
|
||||
* 获取物资已有数量
|
||||
*/
|
||||
Map<String, Object> remaining(Long suppliespriceId, Long mrpBaseId);
|
||||
Map<String, Object> remaining(Long projectId, String suppliespriceName, String specification, Long mrpBaseId);
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ public class BusMrpBaseServiceImpl extends ServiceImpl<BusMrpBaseMapper, BusMrpB
|
||||
planBo.setMrpBaseId(id);
|
||||
List<BusMaterialbatchdemandplanVo> voList = planservice.queryList(planBo);
|
||||
for (BusMaterialbatchdemandplanVo vo : voList) {
|
||||
Map<String, Object> map = remaining(vo.getSuppliespriceId(), id);
|
||||
Map<String, Object> map = remaining(vo.getProjectId(),vo.getName(), vo.getSpecification(), id);
|
||||
vo.setRemaining(Convert.toBigDecimal(map.get("remainingQuantity")));
|
||||
}
|
||||
busMrpVo.setMrpBaseBo(busMrpBaseVo);
|
||||
@ -190,25 +190,34 @@ public class BusMrpBaseServiceImpl extends ServiceImpl<BusMrpBaseMapper, BusMrpB
|
||||
|
||||
if (CollectionUtil.isNotEmpty(dto.getPlanList())) {
|
||||
// 按 suppliespriceId 分组统计本次提交的数量
|
||||
Map<Long, BigDecimal> batchSumMap = dto.getPlanList().stream()
|
||||
Map<String, BigDecimal> batchSumMap = dto.getPlanList().stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
BusMaterialbatchdemandplanBo::getSuppliespriceId,
|
||||
// 关键修改:使用 name + specification 拼接作为分组键
|
||||
item -> {
|
||||
String name = item.getName() != null ? item.getName() : "";
|
||||
String spec = item.getSpecification() != null ? item.getSpecification() : "";
|
||||
return name + "&&&" + spec;
|
||||
},
|
||||
Collectors.reducing(
|
||||
BigDecimal.ZERO,
|
||||
BusMaterialbatchdemandplanBo::getDemandQuantity,
|
||||
item -> {
|
||||
BigDecimal quantity = item.getDemandQuantity();
|
||||
return quantity != null ? quantity : BigDecimal.ZERO;
|
||||
},
|
||||
BigDecimal::add
|
||||
)
|
||||
));
|
||||
|
||||
// 检查每种物料是否超出数量限制
|
||||
for (Map.Entry<Long, BigDecimal> entry : batchSumMap.entrySet()) {
|
||||
Long suppliespriceId = entry.getKey();
|
||||
for (Map.Entry<String, BigDecimal> entry : batchSumMap.entrySet()) {
|
||||
String biaoshi = entry.getKey();
|
||||
BigDecimal batchSum = entry.getValue();
|
||||
|
||||
String[] split = biaoshi.split("&&&");
|
||||
// 获取数据库中已有的数量
|
||||
List<BusMaterialbatchdemandplan> existingList = planservice.list(
|
||||
Wrappers.lambdaQuery(BusMaterialbatchdemandplan.class)
|
||||
.eq(BusMaterialbatchdemandplan::getSuppliespriceId, suppliespriceId)
|
||||
.eq(BusMaterialbatchdemandplan::getName, split[0])
|
||||
.eq(BusMaterialbatchdemandplan::getSpecification,split[1])
|
||||
.ne(BusMaterialbatchdemandplan::getMrpBaseId, convert.getId()) // 排除当前批次
|
||||
);
|
||||
|
||||
@ -217,13 +226,29 @@ public class BusMrpBaseServiceImpl extends ServiceImpl<BusMrpBaseMapper, BusMrpB
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
// 检查总数量是否超出限制
|
||||
BusBillofquantities billofquantities = busBillofquantitiesService.getById(suppliespriceId);
|
||||
if (existingSum.add(batchSum).compareTo(billofquantities.getQuantity()) > 0) {
|
||||
List<BusBillofquantities> busBillofquantities = busBillofquantitiesService.getBaseMapper().selectList(new LambdaQueryWrapper<BusBillofquantities>()
|
||||
.eq(BusBillofquantities::getProjectId, dto.getMrpBaseBo().getProjectId())
|
||||
.eq(BusBillofquantities::getName, split[0])
|
||||
.eq(BusBillofquantities::getSpecification, split[1]));
|
||||
BigDecimal quantity = busBillofquantities.stream()
|
||||
.map(BusBillofquantities::getQuantity)
|
||||
.filter(Objects::nonNull)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
if (existingSum.add(batchSum).compareTo(quantity) > 0) {
|
||||
// 找到超出限制的物料名称用于提示
|
||||
String itemName = dto.getPlanList().stream()
|
||||
.filter(plan -> plan.getSuppliespriceId().equals(suppliespriceId))
|
||||
.filter(item -> {
|
||||
String name = item.getName() != null ? item.getName() : "";
|
||||
String spec = item.getSpecification() != null ? item.getSpecification() : "";
|
||||
return (name + "&&&" + spec).equals(biaoshi);
|
||||
|
||||
})
|
||||
.findFirst()
|
||||
.map(BusMaterialbatchdemandplanBo::getName)
|
||||
.map(item -> {
|
||||
String name = item.getName() != null ? item.getName() : "";
|
||||
String spec = item.getSpecification() != null ? item.getSpecification() : "";
|
||||
return "名称:“"+name + "”,规格:“" + spec+"”";
|
||||
})
|
||||
.orElse("未知物料");
|
||||
throw new ServiceException(itemName + "超出数量");
|
||||
}
|
||||
@ -272,13 +297,23 @@ public class BusMrpBaseServiceImpl extends ServiceImpl<BusMrpBaseMapper, BusMrpB
|
||||
|
||||
|
||||
@Override
|
||||
public Map<String, Object> remaining(Long suppliespriceId, Long mrpBaseId) {
|
||||
public Map<String, Object> remaining(Long projectId, String suppliespriceName, String specification, Long mrpBaseId) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
BusBillofquantities byId = busBillofquantitiesService.getById(suppliespriceId);
|
||||
List<BusBillofquantities> busBillofquantities = busBillofquantitiesService.getBaseMapper()
|
||||
.selectList(new LambdaQueryWrapper<BusBillofquantities>()
|
||||
.eq(BusBillofquantities::getProjectId, projectId)
|
||||
.eq(BusBillofquantities::getName, suppliespriceName)
|
||||
.eq(BusBillofquantities::getSpecification,specification));
|
||||
BigDecimal quantity = busBillofquantities.stream()
|
||||
.map(BusBillofquantities::getQuantity)
|
||||
.filter(Objects::nonNull)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
// BusBillofquantities byId = busBillofquantitiesService.getById(suppliespriceId);
|
||||
// 获取数据库中已有的数量
|
||||
List<BusMaterialbatchdemandplan> existingList = planservice.list(
|
||||
Wrappers.lambdaQuery(BusMaterialbatchdemandplan.class)
|
||||
.eq(BusMaterialbatchdemandplan::getSuppliespriceId, suppliespriceId)
|
||||
.eq(BusMaterialbatchdemandplan::getName, suppliespriceName)
|
||||
.eq(BusMaterialbatchdemandplan::getSpecification ,specification)
|
||||
.ne(mrpBaseId!=null,BusMaterialbatchdemandplan::getMrpBaseId, mrpBaseId)// 排除当前批次
|
||||
);
|
||||
BigDecimal reduce = BigDecimal.ZERO;
|
||||
@ -287,11 +322,11 @@ public class BusMrpBaseServiceImpl extends ServiceImpl<BusMrpBaseMapper, BusMrpB
|
||||
.map(BusMaterialbatchdemandplan::getDemandQuantity)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
}
|
||||
map.put("remainingQuantity",byId.getQuantity().subtract(reduce));
|
||||
map.put("specification",byId.getSpecification());
|
||||
map.put("unit",byId.getUnit());
|
||||
map.put("remark",byId.getRemark());
|
||||
map.put("name",byId.getName());
|
||||
map.put("remainingQuantity",quantity.subtract(reduce));
|
||||
map.put("specification",busBillofquantities.getFirst().getSpecification());
|
||||
map.put("unit",busBillofquantities.getFirst().getUnit());
|
||||
map.put("remark",busBillofquantities.getFirst().getRemark());
|
||||
map.put("name",busBillofquantities.getFirst().getName());
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
package org.dromara.contractor.controller.app;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.contractor.domain.SubUserSalaryDetail;
|
||||
import org.dromara.contractor.domain.dto.usersalarydetail.SubUserSalaryDetailQueryReq;
|
||||
import org.dromara.contractor.domain.dto.usersalaryperiod.SubConstructionUserSalaryDto;
|
||||
import org.dromara.contractor.domain.vo.usersalarydetail.SubUserSalaryDetailVo;
|
||||
import org.dromara.contractor.domain.vo.usersalaryperiod.SubConstructionUserSalaryVo;
|
||||
import org.dromara.contractor.service.ISubUserSalaryDetailService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* app工资
|
||||
*
|
||||
* @author lilemy
|
||||
* @date 2025-09-04
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/contractor/userSalaryDetail")
|
||||
public class SubUserSalaryDetailAppController extends BaseController {
|
||||
|
||||
private final ISubUserSalaryDetailService subUserSalaryDetailService;
|
||||
|
||||
|
||||
/**
|
||||
* 工资分页
|
||||
*/
|
||||
@GetMapping("/salaryPageList")
|
||||
public TableDataInfo<SubConstructionUserSalaryVo> salaryPageList( SubConstructionUserSalaryDto dto, PageQuery pageQuery) {
|
||||
return subUserSalaryDetailService.salaryPageList(dto, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 工资详情
|
||||
*/
|
||||
@GetMapping("/detailList")
|
||||
public R<List<SubUserSalaryDetail>> detailList( SubConstructionUserSalaryDto dto) {
|
||||
return R.ok(subUserSalaryDetailService.detailList(dto));
|
||||
}
|
||||
|
||||
}
|
||||
@ -100,4 +100,29 @@ public class SubConstructionUserSalaryVo implements Serializable {
|
||||
*/
|
||||
private String createTime;
|
||||
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy")
|
||||
private String createByName;
|
||||
|
||||
|
||||
/**
|
||||
* 发放时间
|
||||
*/
|
||||
private Long tim;
|
||||
|
||||
|
||||
/**
|
||||
* 班组id
|
||||
*/
|
||||
private Long teamId;
|
||||
|
||||
/**
|
||||
* 班组名
|
||||
*/
|
||||
private String teamName;
|
||||
|
||||
}
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
package org.dromara.contractor.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.contractor.domain.SubUserSalaryDetail;
|
||||
import org.dromara.contractor.domain.vo.usersalarydetail.SubUserSalaryDetailVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 员工每日工资Mapper接口
|
||||
*
|
||||
@ -12,4 +16,15 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
*/
|
||||
public interface SubUserSalaryDetailMapper extends BaseMapperPlus<SubUserSalaryDetail, SubUserSalaryDetailVo> {
|
||||
|
||||
|
||||
|
||||
@Insert({
|
||||
"<script>",
|
||||
"INSERT INTO sub_user_salary_detail (project_id, team_id, user_id, user_name, report_date, work_hour, daily_salary, total_salary, create_by, update_by, remark) VALUES ",
|
||||
"<foreach collection='list' item='item' separator=','>",
|
||||
"(#{item.projectId}, #{item.teamId}, #{item.userId}, #{item.userName}, #{item.reportDate}, #{item.workHour}, #{item.dailySalary}, #{item.totalSalary}, #{userId}, #{userId}, #{item.remark})",
|
||||
"</foreach>",
|
||||
"</script>"
|
||||
})
|
||||
Boolean insertAll(@Param("list")List<SubUserSalaryDetail> list, @Param("userId") Long userId);
|
||||
}
|
||||
|
||||
@ -935,7 +935,10 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
|
||||
constructionUserVo.setPostId(one.getPostId());
|
||||
}
|
||||
|
||||
}else {
|
||||
constructionUserVo.setTeamName(null);
|
||||
}
|
||||
|
||||
return constructionUserVo;
|
||||
}).toList();
|
||||
constructionUserVoPage.setRecords(constructionUserVoList);
|
||||
|
||||
@ -18,6 +18,7 @@ import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.pdfbox.io.IOUtils;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
@ -30,6 +31,7 @@ import org.dromara.common.core.utils.ObjectUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.utils.IdCardEncryptorUtil;
|
||||
import org.dromara.contractor.domain.SubConstructionUser;
|
||||
import org.dromara.contractor.domain.SubUserSalaryDetail;
|
||||
@ -54,17 +56,16 @@ import org.dromara.project.service.IBusAttendanceService;
|
||||
import org.dromara.project.service.IBusProjectService;
|
||||
import org.dromara.project.service.IBusProjectTeamService;
|
||||
import org.dromara.project.service.IBusWorkWageService;
|
||||
import org.dromara.project.service.impl.BusProjectTeamServiceImpl;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import software.amazon.awssdk.utils.CollectionUtils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.net.URLEncoder;
|
||||
@ -72,6 +73,7 @@ import java.time.LocalDate;
|
||||
import java.time.YearMonth;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import org.dromara.contractor.excel.SalaryExcelReader;
|
||||
|
||||
@ -83,6 +85,7 @@ import org.dromara.contractor.excel.SalaryExcelReader;
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@Slf4j
|
||||
public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDetailMapper, SubUserSalaryDetail>
|
||||
implements ISubUserSalaryDetailService {
|
||||
|
||||
@ -272,14 +275,13 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
|
||||
@Override
|
||||
public TableDataInfo<SubConstructionUserSalaryVo> salaryPageList(SubConstructionUserSalaryDto dto, PageQuery pageQuery) {
|
||||
|
||||
|
||||
String time = dto.getTime();
|
||||
YearMonth parse = YearMonth.parse(time, DateTimeFormatter.ofPattern("yyyy-MM"));
|
||||
LocalDate start = parse.atDay(1);
|
||||
LocalDate end = parse.atEndOfMonth();
|
||||
|
||||
QueryWrapper<SubUserSalaryDetail> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.select("user_id", "SUM(work_hour) as workHour", "SUM(total_salary) as totalSalary","max(create_time) as createTime")
|
||||
queryWrapper.select("user_id","max(team_id) as teamId","max(create_by) as createBy", "SUM(work_hour) as workHour", "SUM(total_salary) as totalSalary","max(create_time) as createTime")
|
||||
.eq("project_id", dto.getProjectId())
|
||||
.between("report_date", start, end)
|
||||
.eq(dto.getTeamId()!=null,"team_id", dto.getTeamId())
|
||||
@ -290,15 +292,24 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
|
||||
Page<SubUserSalaryDetail> result = this.page(pageQuery.build(), queryWrapper);
|
||||
List<SubUserSalaryDetail> records = result.getRecords();
|
||||
List<Long> userIds = records.stream().map(SubUserSalaryDetail::getUserId).toList();
|
||||
|
||||
Map<Long, SubConstructionUser> collect = new HashMap<>();
|
||||
if(CollectionUtil.isNotEmpty(userIds)){
|
||||
List<SubConstructionUser> subConstructionUsers = constructionUserService.list(Wrappers.lambdaQuery(SubConstructionUser.class)
|
||||
.in(SubConstructionUser::getSysUserId, userIds));
|
||||
collect = subConstructionUsers.stream().collect(Collectors.toMap(SubConstructionUser::getSysUserId, vo -> vo));
|
||||
}
|
||||
Set<Long> teamIds = records.stream().map(SubUserSalaryDetail::getTeamId).collect(Collectors.toSet());
|
||||
|
||||
Map<Long, BusProjectTeam> teamMap = new HashMap<>();
|
||||
if(CollectionUtil.isNotEmpty(teamIds)){
|
||||
List<BusProjectTeam> busProjectTeams = projectTeamService.listByIds(teamIds);
|
||||
teamMap = busProjectTeams.stream().collect(Collectors.toMap(BusProjectTeam::getId, vo -> vo));
|
||||
}
|
||||
ArrayList<SubConstructionUserSalaryVo> vos = new ArrayList<>();
|
||||
for (SubUserSalaryDetail detail : records) {
|
||||
SubConstructionUserSalaryVo vo = new SubConstructionUserSalaryVo();
|
||||
vo.setCreateBy(detail.getCreateBy());
|
||||
vo.setId(detail.getId());
|
||||
vo.setTime(dto.getTime());
|
||||
vo.setTotalSalary(detail.getTotalSalary());
|
||||
@ -306,6 +317,7 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
|
||||
vo.setWorkDay(detail.getWorkHour());
|
||||
vo.setProjectId(dto.getProjectId());
|
||||
vo.setUserId(detail.getUserId());
|
||||
vo.setTeamId(detail.getTeamId());
|
||||
SubConstructionUser constructionUser = collect.get(detail.getUserId());
|
||||
if(constructionUser != null){
|
||||
if(constructionUser.getSfzNumber() != null){
|
||||
@ -314,6 +326,11 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
|
||||
vo.setUserName(constructionUser.getUserName());
|
||||
vo.setYhkNumber(constructionUser.getYhkNumber());
|
||||
vo.setYhkOpeningBank(constructionUser.getYhkOpeningBank());
|
||||
|
||||
}
|
||||
BusProjectTeam projectTeam = teamMap.get(detail.getTeamId());
|
||||
if(projectTeam != null){
|
||||
vo.setTeamName(projectTeam.getTeamName());
|
||||
}
|
||||
vos.add(vo);
|
||||
}
|
||||
@ -323,157 +340,162 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
|
||||
|
||||
@Override
|
||||
public void export(HttpServletResponse response, SubConstructionUserSalaryDto dto) throws IOException {
|
||||
// 1. 查询项目和人员数据
|
||||
// 1. 查询项目信息并校验
|
||||
BusProject project = projectService.getById(dto.getProjectId());
|
||||
if (project == null) {
|
||||
throw new ServiceException("项目不存在");
|
||||
}
|
||||
// 2. 解析年月和查询薪资明细
|
||||
|
||||
// 2. 解析时间参数
|
||||
YearMonth yearMonth = YearMonth.parse(dto.getTime(), DateTimeFormatter.ofPattern("yyyy-MM"));
|
||||
LocalDate start = yearMonth.atDay(1);
|
||||
LocalDate end = yearMonth.atEndOfMonth();
|
||||
|
||||
// 3. 查询薪资明细数据
|
||||
QueryWrapper<SubUserSalaryDetail> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.select("user_id", "SUM(work_hour) as workHour", "SUM(total_salary) as totalSalary","max(create_time) as createTime")
|
||||
queryWrapper.select("user_id", "SUM(work_hour) as workHour", "SUM(total_salary) as totalSalary")
|
||||
.eq("project_id", dto.getProjectId())
|
||||
.between("report_date", start, end)
|
||||
.eq(dto.getUserId()!=null,"user_id", dto.getUserId())
|
||||
.eq(dto.getTeamId()!=null,"team_id", dto.getTeamId())
|
||||
.like(StringUtils.isNotBlank(dto.getUserName()),"user_name", dto.getUserName())
|
||||
.eq(dto.getUserId() != null, "user_id", dto.getUserId())
|
||||
.eq(dto.getTeamId() != null, "team_id", dto.getTeamId())
|
||||
.like(StringUtils.isNotBlank(dto.getUserName()), "user_name", dto.getUserName())
|
||||
.groupBy("user_id");
|
||||
|
||||
List<SubUserSalaryDetail> salaryDetailsList= baseMapper.selectList(queryWrapper);
|
||||
|
||||
List<SubUserSalaryDetail> salaryDetailsList = baseMapper.selectList(queryWrapper);
|
||||
if (salaryDetailsList.isEmpty()) {
|
||||
throw new ServiceException("暂无数据");
|
||||
}
|
||||
Map<Long, SubUserSalaryDetail> map = salaryDetailsList.stream().collect(Collectors.toMap(SubUserSalaryDetail::getUserId, vo -> vo));
|
||||
|
||||
|
||||
List<Long> userIds = salaryDetailsList.stream().map(SubUserSalaryDetail::getUserId).toList();
|
||||
|
||||
|
||||
// 4. 构建薪资数据映射
|
||||
Map<Long, SubUserSalaryDetail> salaryMap = salaryDetailsList.stream()
|
||||
.collect(Collectors.toMap(SubUserSalaryDetail::getUserId, vo -> vo));
|
||||
|
||||
// 5. 批量查询用户信息(只查必要字段)
|
||||
Set<Long> userIds = salaryMap.keySet();
|
||||
List<SubConstructionUser> userList = constructionUserService.lambdaQuery()
|
||||
.select(SubConstructionUser::getSysUserId, SubConstructionUser::getTeamId, SubConstructionUser::getUserName
|
||||
, SubConstructionUser::getYhkNumber, SubConstructionUser::getYhkOpeningBank)
|
||||
.in(SubConstructionUser::getSysUserId, userIds)
|
||||
.list();
|
||||
|
||||
// 3. 设置响应头(下载文件配置)
|
||||
// 6. 预处理班组信息(解决null键问题)
|
||||
// 使用-1L作为临时键替代null,避免groupingBy出现null键错误
|
||||
Map<Long, List<SubConstructionUser>> teamUsersMap = userList.stream()
|
||||
.collect(Collectors.groupingBy(user -> {
|
||||
Long teamId = user.getTeamId();
|
||||
return teamId != null ? teamId : -1L; // 关键修复:null键映射为-1
|
||||
}));
|
||||
|
||||
// 提取实际班组ID(排除-1)并计算数量
|
||||
List<Long> teamIds = teamUsersMap.keySet().stream()
|
||||
.filter(id -> !id.equals(-1L))
|
||||
.collect(Collectors.toList());
|
||||
int actualTeamCount = teamIds.size();
|
||||
|
||||
// 动态计算初始容量,避免HashMap扩容
|
||||
Map<Long, String> teamNameMap = new HashMap<>((int) Math.ceil(actualTeamCount * 1.5));
|
||||
|
||||
// 批量查询班组名称
|
||||
if (!teamIds.isEmpty()) {
|
||||
List<BusProjectTeam> teams = projectTeamService.lambdaQuery()
|
||||
.select(BusProjectTeam::getId, BusProjectTeam::getTeamName)
|
||||
.in(BusProjectTeam::getId, teamIds)
|
||||
.list();
|
||||
teams.forEach(team -> teamNameMap.put(team.getId(), team.getTeamName()));
|
||||
}
|
||||
|
||||
// 7. 检查班组数量阈值
|
||||
int maxSheetThreshold = 100; // 根据实际情况调整
|
||||
if (actualTeamCount > maxSheetThreshold) {
|
||||
log.warn("班组数量过多({}个),可能导致Excel文件过大或导出缓慢", actualTeamCount);
|
||||
// 若需严格限制,可在此处抛出异常
|
||||
// throw new ServiceException("班组数量超过限制,最多支持" + maxSheetThreshold + "个");
|
||||
}
|
||||
|
||||
// 8. 设置响应头
|
||||
setResponseHeader(response, yearMonth.getYear(), yearMonth.getMonthValue());
|
||||
|
||||
// 5. 读取模板文件到字节数组(复用模板)
|
||||
// 9. 读取模板文件(缓冲流优化)
|
||||
byte[] templateBytes;
|
||||
try (InputStream templateStream = Thread.currentThread().getContextClassLoader()
|
||||
.getResourceAsStream("excelTemplate/salary_template.xlsx")) {
|
||||
.getResourceAsStream("excelTemplate/salary_template.xlsx");
|
||||
BufferedInputStream bis = new BufferedInputStream(templateStream);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||
|
||||
if (templateStream == null) {
|
||||
throw new ServiceException("模板文件不存在(路径:excelTemplate/salary_template.xlsx)");
|
||||
}
|
||||
templateBytes = IOUtils.toByteArray(templateStream);
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
while ((bytesRead = bis.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, bytesRead);
|
||||
}
|
||||
templateBytes = baos.toByteArray();
|
||||
}
|
||||
|
||||
// 6. POI 处理多 sheet(核心:克隆模板 + 命名)
|
||||
// 存储 <sheet名称, sheet对象> 映射,方便后续 EasyExcel 匹配
|
||||
Map<String, Sheet> sheetMap = new LinkedHashMap<>();
|
||||
// 10. POI处理多Sheet(核心逻辑)
|
||||
try (Workbook workbook = WorkbookFactory.create(new ByteArrayInputStream(templateBytes));
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
|
||||
|
||||
// 校验模板是否有有效 sheet
|
||||
if (workbook.getNumberOfSheets() == 0) {
|
||||
throw new ServiceException("模板文件中无任何 sheet 页,请检查模板");
|
||||
throw new ServiceException("模板文件中无任何sheet页,请检查模板");
|
||||
}
|
||||
|
||||
// 6.1 预处理班组信息(获取班组ID + 班组名称映射)
|
||||
List<Long> teamIds = userList.stream()
|
||||
.map(SubConstructionUser::getTeamId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
Map<Long, String> teamNameMap = new HashMap<>();
|
||||
if (!teamIds.isEmpty()) {
|
||||
List<BusProjectTeam> teams = projectTeamService.lambdaQuery()
|
||||
.in(BusProjectTeam::getId, teamIds)
|
||||
.list();
|
||||
teamNameMap = teams.stream()
|
||||
.collect(Collectors.toMap(
|
||||
BusProjectTeam::getId,
|
||||
BusProjectTeam::getTeamName,
|
||||
(oldVal, newVal) -> newVal // 避免重复ID冲突
|
||||
));
|
||||
}
|
||||
int originalSheetIndex = 0;
|
||||
|
||||
// 6.2 克隆模板:为每个班组生成 sheet(关键修正)
|
||||
// 10.1 为每个班组创建sheet
|
||||
for (Long teamId : teamIds) {
|
||||
// ① 克隆原始模板 sheet(返回克隆后的 Sheet 对象)
|
||||
Sheet newSheet = workbook.cloneSheet(0);
|
||||
// ② 生成班组名称(避免空名称)
|
||||
Sheet newSheet = workbook.cloneSheet(originalSheetIndex);
|
||||
String teamName = teamNameMap.getOrDefault(teamId, "未知班组_" + teamId);
|
||||
// ③ 给新 sheet 命名(通过 sheet 对象获取索引)
|
||||
int newSheetIndex = workbook.getSheetIndex(newSheet);
|
||||
workbook.setSheetName(newSheetIndex, teamName);
|
||||
// ④ 存入映射,方便后续填充
|
||||
sheetMap.put(teamName, newSheet);
|
||||
}
|
||||
|
||||
// 6.3 克隆模板:处理“无班组”数据(如果需要)
|
||||
boolean needNoTeamSheet = dto.getTeamId() == null;
|
||||
// 10.2 处理无班组数据(使用-1对应的用户列表)
|
||||
boolean needNoTeamSheet = dto.getTeamId() == null && teamUsersMap.containsKey(-1L);
|
||||
if (needNoTeamSheet) {
|
||||
Sheet noTeamSheet = workbook.cloneSheet(0);
|
||||
String noTeamName = "无班组";
|
||||
Sheet noTeamSheet = workbook.cloneSheet(originalSheetIndex);
|
||||
int noTeamSheetIndex = workbook.getSheetIndex(noTeamSheet);
|
||||
workbook.setSheetName(noTeamSheetIndex, noTeamName);
|
||||
sheetMap.put(noTeamName, noTeamSheet);
|
||||
workbook.setSheetName(noTeamSheetIndex, "无班组");
|
||||
}
|
||||
|
||||
// 6.4 删除原始模板 sheet(避免最终文件保留空模板)
|
||||
workbook.removeSheetAt(0);
|
||||
// 10.3 移除原始模板sheet
|
||||
workbook.removeSheetAt(originalSheetIndex);
|
||||
|
||||
// 6.5 将 POI 处理后的 workbook 写入字节数组,供 EasyExcel 使用
|
||||
// 10.4 写入并关闭workbook
|
||||
workbook.write(bos);
|
||||
workbook.close();
|
||||
byte[] workbookBytes = bos.toByteArray();
|
||||
|
||||
// 7. EasyExcel 填充数据(按 sheet 映射顺序填充)
|
||||
// 11. EasyExcel填充数据
|
||||
try (InputStream workbookStream = new ByteArrayInputStream(workbookBytes);
|
||||
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
|
||||
.withTemplate(workbookStream)
|
||||
.build()) {
|
||||
|
||||
// 7.1 填充“班组”sheet 数据
|
||||
for (Map.Entry<String, Sheet> entry : sheetMap.entrySet()) {
|
||||
String sheetName = entry.getKey();
|
||||
// 跳过“无班组”sheet,后续单独处理
|
||||
if ("无班组".equals(sheetName)) {
|
||||
continue;
|
||||
}
|
||||
// 根据 sheet 名称反查班组ID(用于过滤数据)
|
||||
Long teamId = teamNameMap.entrySet().stream()
|
||||
.filter(e -> sheetName.equals(e.getValue()))
|
||||
.map(Map.Entry::getKey)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
|
||||
|
||||
// 创建 EasyExcel 的 WriteSheet(通过名称匹配 sheet)
|
||||
WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
|
||||
FillConfig fillConfig = FillConfig.builder()
|
||||
.forceNewRow(true) // 强制新增行,不覆盖模板内容
|
||||
.build();
|
||||
|
||||
// 填充列表数据和汇总数据
|
||||
excelWriter.fill(getTeamData(userList, map, teamId), fillConfig, writeSheet);
|
||||
excelWriter.fill(getTeamSummary(project, teamNameMap.get(teamId), yearMonth), writeSheet);
|
||||
// 11.1 填充各班组数据
|
||||
for (Long teamId : teamIds) {
|
||||
String teamName = teamNameMap.getOrDefault(teamId, "未知班组_" + teamId);
|
||||
WriteSheet writeSheet = EasyExcel.writerSheet(teamName).build();
|
||||
// 使用提前分组好的数据
|
||||
excelWriter.fill(getTeamData(teamUsersMap.get(teamId), salaryMap, teamId), fillConfig, writeSheet);
|
||||
excelWriter.fill(getTeamSummary(project, teamName, yearMonth), writeSheet);
|
||||
}
|
||||
|
||||
// 7.2 填充“无班组”sheet 数据
|
||||
// 11.2 填充无班组数据
|
||||
if (needNoTeamSheet) {
|
||||
WriteSheet noTeamSheet = EasyExcel.writerSheet("无班组").build();
|
||||
FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
|
||||
|
||||
excelWriter.fill(getTeamData(userList, map, null), fillConfig, noTeamSheet);
|
||||
excelWriter.fill(getTeamData(teamUsersMap.get(-1L), salaryMap, null), fillConfig, noTeamSheet);
|
||||
excelWriter.fill(getTeamSummary(project, null, yearMonth), noTeamSheet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置响应头信息
|
||||
*/
|
||||
@ -492,15 +514,15 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
|
||||
|
||||
private List<SubConstructionUserSalaryVo> getTeamData(List<SubConstructionUser> rows,
|
||||
Map<Long, SubUserSalaryDetail> map,Long teamId){
|
||||
List<SubConstructionUser> list1 ;
|
||||
if(teamId == null){
|
||||
list1 = rows.stream().filter(row -> row.getTeamId() == null && Arrays.asList("1","2").contains(row.getExitStatus())).toList();
|
||||
}else {
|
||||
list1 = rows.stream().filter(row -> teamId.equals(row.getTeamId())).toList();
|
||||
}
|
||||
// List<SubConstructionUser> list1 ;
|
||||
// if(teamId == null){
|
||||
// list1 = rows.stream().filter(row -> row.getTeamId() == null && Arrays.asList("1","2").contains(row.getExitStatus())).toList();
|
||||
// }else {
|
||||
// list1 = rows.stream().filter(row -> teamId.equals(row.getTeamId())).toList();
|
||||
// }
|
||||
ArrayList<SubConstructionUserSalaryVo> vos = new ArrayList<>();
|
||||
int i =1;
|
||||
for (SubConstructionUser row : list1) {
|
||||
for (SubConstructionUser row : rows) {
|
||||
SubConstructionUserSalaryVo vo = new SubConstructionUserSalaryVo();
|
||||
BeanUtil.copyProperties(row,vo);
|
||||
vo.setOrder(i);
|
||||
@ -525,19 +547,21 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void importData(MultipartFile file, String month) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
// 1. 校验文件合法性
|
||||
if (file.isEmpty()) {
|
||||
throw new IllegalArgumentException("上传的Excel文件不能为空!");
|
||||
}
|
||||
// 校验文件格式(仅允许xlsx/xls)
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
if (originalFilename == null || !(originalFilename.endsWith(".xlsx"))) {
|
||||
throw new IllegalArgumentException("仅支持上传Excel文件(.xlsx 格式)!");
|
||||
}
|
||||
|
||||
List<DynamicSalaryData> dataList;
|
||||
try {
|
||||
// 2. 将 MultipartFile 转为 InputStream,传给工具类解析
|
||||
dataList = SalaryExcelReader.readAllAttendanceByStream(file.getInputStream(), month);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Excel流解析失败:" + e.getMessage(), e);
|
||||
@ -546,42 +570,79 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
|
||||
throw new ServiceException("未读取到数据");
|
||||
}
|
||||
|
||||
Map<String, Map<String, Double>> dataMap = dataList.stream().collect(Collectors.toMap(vo -> idCardEncryptorUtil.encrypt(vo.getIdCard()), DynamicSalaryData::getDailyAttendance));
|
||||
Set<String> cards = dataMap.keySet();
|
||||
// 2. 数据预处理 - 使用并行流提高处理速度
|
||||
Map<String, Map<String, Double>> dataMap = dataList.parallelStream()
|
||||
.collect(Collectors.toMap(
|
||||
vo -> idCardEncryptorUtil.encrypt(vo.getIdCard()),
|
||||
DynamicSalaryData::getDailyAttendance
|
||||
));
|
||||
|
||||
Set<String> cards = dataMap.keySet();
|
||||
month = dataList.getFirst().getMonth();
|
||||
YearMonth parse = YearMonth.parse(month, DateTimeFormatter.ofPattern("yyyy-MM"));
|
||||
LocalDate start = parse.atDay(1);
|
||||
LocalDate end = parse.atEndOfMonth();
|
||||
|
||||
//人员数据
|
||||
List<SubConstructionUser> list = constructionUserService.list(Wrappers.<SubConstructionUser>lambdaQuery()
|
||||
.in(SubConstructionUser::getSfzNumber, cards));
|
||||
// 3. 分批处理人员数据 - 避免一次性加载大量数据
|
||||
List<SubConstructionUser> allUsers = new ArrayList<>();
|
||||
int batchSize = 1000; // 批量查询大小
|
||||
|
||||
List<Long> userIds = list.stream().map(SubConstructionUser::getSysUserId).toList();
|
||||
//考勤数据
|
||||
List<BusAttendance> attendanceList = attendanceService
|
||||
.list(Wrappers.<BusAttendance>lambdaQuery()
|
||||
.in(BusAttendance::getUserId, userIds)
|
||||
.between(BusAttendance::getClockDate, start, end)
|
||||
// 分批查询用户数据
|
||||
List<List<String>> cardBatches = new ArrayList<>();
|
||||
List<String> cardList = new ArrayList<>(cards);
|
||||
for (int i = 0; i < cardList.size(); i += batchSize) {
|
||||
int endIndex = Math.min(i + batchSize, cardList.size());
|
||||
cardBatches.add(cardList.subList(i, endIndex));
|
||||
}
|
||||
|
||||
for (List<String> batchCards : cardBatches) {
|
||||
List<SubConstructionUser> batchUsers = constructionUserService.list(
|
||||
Wrappers.<SubConstructionUser>lambdaQuery()
|
||||
.in(SubConstructionUser::getSfzNumber, batchCards)
|
||||
);
|
||||
// 将 attendanceList 转换为 Map<String, BigDecimal> 格式
|
||||
Map<String, BigDecimal> attendanceSalaryMap = new HashMap<>();
|
||||
allUsers.addAll(batchUsers);
|
||||
}
|
||||
|
||||
// 按 userId+日期 分组,只保留每组的第一条记录的salary
|
||||
attendanceList.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
attendance -> attendance.getUserId() + "_" + attendance.getClockDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
|
||||
Collectors.toList()
|
||||
))
|
||||
.forEach((key, dateList) -> attendanceSalaryMap.put(key, dateList.getFirst().getSalary()));
|
||||
if (CollUtil.isEmpty(allUsers)) {
|
||||
throw new ServiceException("未找到匹配的人员信息");
|
||||
}
|
||||
|
||||
// 4. 分批处理考勤数据 - 避免内存溢出
|
||||
List<Long> userIds = allUsers.stream()
|
||||
.map(SubConstructionUser::getSysUserId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<SubUserSalaryDetail> addList = new ArrayList<>();
|
||||
for(SubConstructionUser constructionUser : list){
|
||||
Map<String, Double> stringIntegerMap = dataMap.get(constructionUser.getSfzNumber());
|
||||
if(stringIntegerMap != null){
|
||||
for(Map.Entry<String, Double> entry : stringIntegerMap.entrySet()){
|
||||
Map<String, BigDecimal> attendanceSalaryMap = new ConcurrentHashMap<>();
|
||||
|
||||
// 分批查询考勤数据
|
||||
for (int i = 0; i < userIds.size(); i += batchSize) {
|
||||
int endIndex = Math.min(i + batchSize, userIds.size());
|
||||
List<Long> batchUserIds = userIds.subList(i, endIndex);
|
||||
|
||||
List<BusAttendance> batchAttendanceList = attendanceService.list(
|
||||
Wrappers.<BusAttendance>lambdaQuery()
|
||||
.in(BusAttendance::getUserId, batchUserIds)
|
||||
.between(BusAttendance::getClockDate, start, end)
|
||||
);
|
||||
|
||||
// 并行处理考勤数据
|
||||
batchAttendanceList.parallelStream()
|
||||
.collect(Collectors.groupingBy(
|
||||
attendance -> attendance.getUserId() + "_" + attendance.getClockDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
|
||||
Collectors.toList()
|
||||
))
|
||||
.forEach((key, dateList) -> attendanceSalaryMap.put(key, dateList.getFirst().getSalary()));
|
||||
}
|
||||
|
||||
// 5. 批量构建数据 - 使用并行处理
|
||||
List<SubUserSalaryDetail> allAddList = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
// 并行处理用户数据构建
|
||||
allUsers.parallelStream().forEach(constructionUser -> {
|
||||
Map<String, Double> userAttendanceMap = dataMap.get(constructionUser.getSfzNumber());
|
||||
if(userAttendanceMap != null){
|
||||
userAttendanceMap.entrySet().parallelStream().forEach(entry -> {
|
||||
String key = entry.getKey();
|
||||
Double value = entry.getValue();
|
||||
|
||||
@ -600,16 +661,35 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
|
||||
}
|
||||
subUserSalaryDetail.setDailySalary(bigDecimal);
|
||||
subUserSalaryDetail.setTotalSalary(bigDecimal.multiply(new BigDecimal(value.toString())));
|
||||
addList.add(subUserSalaryDetail);
|
||||
}
|
||||
|
||||
allAddList.add(subUserSalaryDetail);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 6. 批量删除和插入 - 分批处理避免数据库压力
|
||||
if (CollUtil.isNotEmpty(allAddList)) {
|
||||
// 批量删除现有数据
|
||||
for (int i = 0; i < userIds.size(); i += batchSize) {
|
||||
int endIndex = Math.min(i + batchSize, userIds.size());
|
||||
List<Long> deleteUserIds = userIds.subList(i, endIndex);
|
||||
|
||||
baseMapper.delete(Wrappers.<SubUserSalaryDetail>lambdaQuery()
|
||||
.in(SubUserSalaryDetail::getUserId, deleteUserIds)
|
||||
.between(SubUserSalaryDetail::getReportDate, start, end)
|
||||
);
|
||||
}
|
||||
|
||||
// 批量插入新数据 - 使用自定义批量插入方法
|
||||
for (int i = 0; i < allAddList.size(); i += batchSize) {
|
||||
int endIndex = Math.min(i + batchSize, allAddList.size());
|
||||
List<SubUserSalaryDetail> insertBatch = allAddList.subList(i, endIndex);
|
||||
baseMapper.insertAll(insertBatch,LoginHelper.getUserId());
|
||||
}
|
||||
}
|
||||
baseMapper.delete(Wrappers.<SubUserSalaryDetail>lambdaQuery()
|
||||
.in(SubUserSalaryDetail::getUserId, userIds)
|
||||
.between(SubUserSalaryDetail::getReportDate, start, end)
|
||||
);
|
||||
baseMapper.insertBatch(addList);
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
log.info("工资数据导入完成,耗时: {} ms,处理数据: {} 条", (endTime - startTime), allAddList.size());
|
||||
}
|
||||
|
||||
|
||||
@ -626,6 +706,7 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
|
||||
wrapper.eq( dto.getTeamId()!=null,SubUserSalaryDetail::getTeamId, dto.getTeamId());
|
||||
wrapper.eq(dto.getUserId()!=null,SubUserSalaryDetail::getUserId, dto.getUserId());
|
||||
wrapper.between(SubUserSalaryDetail::getReportDate,start, end);
|
||||
wrapper.orderByAsc(SubUserSalaryDetail::getReportDate);
|
||||
|
||||
return this.list(wrapper);
|
||||
}
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
package org.dromara.cory.controller.app;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.cory.domain.bo.BusContactnoticeBo;
|
||||
import org.dromara.cory.domain.dto.BusContactnoticeAppDto;
|
||||
import org.dromara.cory.domain.vo.BusContactnoticeVo;
|
||||
import org.dromara.cory.service.IBusContactnoticeService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* APP联系单
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-07-03
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/cory/contactnotice")
|
||||
public class BusContactnoticeAppController extends BaseController {
|
||||
|
||||
private final IBusContactnoticeService busContactnoticeService;
|
||||
|
||||
/**
|
||||
* 查询联系单列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<BusContactnoticeVo> list(BusContactnoticeAppDto dto, PageQuery pageQuery) {
|
||||
return busContactnoticeService.queryAppPageList(dto, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取联系单详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public R<BusContactnoticeVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(busContactnoticeService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增联系单
|
||||
*/
|
||||
@Log(title = "联系单", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<BusContactnoticeVo> add(@Validated(AddGroup.class) @RequestBody BusContactnoticeBo bo) {
|
||||
return R.ok(busContactnoticeService.insertByBo(bo));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package org.dromara.cory.domain.dto;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.core.validate.QueryGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.cory.domain.BusContactnotice;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 联系单业务对象 bus_contactnotice
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-07-03
|
||||
*/
|
||||
@Data
|
||||
public class BusContactnoticeAppDto extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 项目ID
|
||||
*/
|
||||
private Long projectId;
|
||||
|
||||
/**
|
||||
* 模板类型
|
||||
*/
|
||||
private Long type;
|
||||
|
||||
/**
|
||||
* 查询参数
|
||||
*/
|
||||
private String queryParam;
|
||||
}
|
||||
@ -3,6 +3,7 @@ package org.dromara.cory.service;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.cory.domain.bo.BusContactnoticeBo;
|
||||
import org.dromara.cory.domain.dto.BusContactnoticeAppDto;
|
||||
import org.dromara.cory.domain.vo.BusContactnoticeVo;
|
||||
|
||||
import java.util.Collection;
|
||||
@ -65,4 +66,9 @@ public interface IBusContactnoticeService {
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* app列表
|
||||
*/
|
||||
TableDataInfo<BusContactnoticeVo> queryAppPageList(BusContactnoticeAppDto dto, PageQuery pageQuery);
|
||||
}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
package org.dromara.cory.service.impl;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.stream.StreamUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@ -19,12 +21,14 @@ import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.cory.domain.BusContactnotice;
|
||||
import org.dromara.cory.domain.bo.BusContactnoticeBo;
|
||||
import org.dromara.cory.domain.dto.BusContactnoticeAppDto;
|
||||
import org.dromara.cory.domain.vo.BusContactnoticeVo;
|
||||
import org.dromara.cory.mapper.BusContactnoticeMapper;
|
||||
import org.dromara.cory.service.IBusContactnoticeService;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -158,6 +162,28 @@ public class BusContactnoticeServiceImpl implements IBusContactnoticeService {
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<BusContactnoticeVo> queryAppPageList(BusContactnoticeAppDto dto, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<BusContactnotice> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(BusContactnotice::getProjectId, dto.getProjectId());
|
||||
lqw.eq(BusContactnotice::getType, dto.getType());
|
||||
// 处理查询参数(避免空值)
|
||||
String queryParam = dto.getQueryParam();
|
||||
if (StrUtil.isNotBlank(queryParam)) {
|
||||
// 使用JSON函数+参数绑定,避免SQL注入
|
||||
lqw.and(wrapper -> wrapper
|
||||
// 对volumeNumber进行模糊查询
|
||||
.apply("detail->>'$.volumeNumber' LIKE CONCAT('%', {0}, '%')", queryParam)
|
||||
// 或对volumeName进行模糊查询
|
||||
.or()
|
||||
.apply("detail->>'$.volumeName' LIKE CONCAT('%', {0}, '%')", queryParam)
|
||||
);
|
||||
}
|
||||
Page<BusContactnoticeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
|
||||
* 正常使用只需#processEvent.flowCode=='leave1'
|
||||
|
||||
@ -0,0 +1,143 @@
|
||||
package org.dromara.design.controller.app;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.enums.BusinessStatusEnum;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.design.domain.DesVolumeFile;
|
||||
import org.dromara.design.domain.dto.designchange.DesDesignChangeCreateReq;
|
||||
import org.dromara.design.domain.dto.designchange.DesDesignChangeQueryReq;
|
||||
import org.dromara.design.domain.dto.designchange.DesDesignChangeUpdateReq;
|
||||
import org.dromara.design.domain.vo.designchange.DesDesignChangeVo;
|
||||
import org.dromara.design.domain.vo.volumecatalog.DesVolumeCatalogVo;
|
||||
import org.dromara.design.service.IDesDesignChangeService;
|
||||
import org.dromara.design.service.IDesVolumeCatalogService;
|
||||
import org.dromara.design.service.IDesVolumeFileService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设计变更管理
|
||||
*
|
||||
* @author lilemy
|
||||
* @date 2025-07-03
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping("/app/design/designChange")
|
||||
public class DesDesignChangeAppController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private IDesDesignChangeService desDesignChangeService;
|
||||
|
||||
@Resource
|
||||
private IDesVolumeCatalogService desVolumeCatalogService;
|
||||
|
||||
@Resource
|
||||
private IDesVolumeFileService desVolumeFileService;
|
||||
|
||||
/**
|
||||
* 查询设计变更管理列表
|
||||
*/
|
||||
@SaCheckPermission("design:designChange:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<DesDesignChangeVo> list(DesDesignChangeQueryReq req, PageQuery pageQuery) {
|
||||
return desDesignChangeService.queryPageList(req, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主键导出设计变更单
|
||||
*/
|
||||
@SaCheckPermission("design:designChange:exportWord")
|
||||
@Log(title = "设计变更管理", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export/word")
|
||||
public void exportWordById(@NotNull(message = "主键不能为空") Long id,
|
||||
HttpServletResponse response) {
|
||||
desDesignChangeService.exportWordById(id, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设计变更管理详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("design:designChange:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<DesDesignChangeVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(desDesignChangeService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增设计变更管理
|
||||
*/
|
||||
@SaCheckPermission("design:designChange:add")
|
||||
@Log(title = "设计变更管理", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<DesDesignChangeVo> add(@Validated(AddGroup.class) @RequestBody DesDesignChangeCreateReq req) {
|
||||
return R.ok(desDesignChangeService.insertByBo(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改设计变更管理
|
||||
*/
|
||||
@SaCheckPermission("design:designChange:edit")
|
||||
@Log(title = "设计变更管理", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<DesDesignChangeVo> edit(@Validated(EditGroup.class) @RequestBody DesDesignChangeUpdateReq req) {
|
||||
return R.ok(desDesignChangeService.updateByBo(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设计变更管理
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("design:designChange:remove")
|
||||
@Log(title = "设计变更管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(desDesignChangeService.deleteByIds(List.of(ids)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询选择卷册目录
|
||||
*/
|
||||
@SaCheckPermission("design:designChange:catalogList")
|
||||
@GetMapping("/catalogList/{projectId}")
|
||||
public R<List<DesVolumeCatalogVo>> catalogList(@PathVariable("projectId") Long projectId) {
|
||||
return R.ok(desVolumeCatalogService.catalogList(projectId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询选择目录下的蓝图
|
||||
*/
|
||||
@SaCheckPermission("design:designChange:blueprint")
|
||||
@GetMapping("/blueprint/{volumeCatalogId}")
|
||||
public R<List<DesVolumeFile>> blueprint(@PathVariable("volumeCatalogId") Long volumeCatalogId) {
|
||||
List<DesVolumeFile> list = desVolumeFileService.list(Wrappers.lambdaQuery(DesVolumeFile.class)
|
||||
.eq(DesVolumeFile::getVolumeCatalogId, volumeCatalogId)
|
||||
.eq(DesVolumeFile::getType, DesVolumeFile.BLUEPRINT)
|
||||
.eq(DesVolumeFile::getAuditStatus, BusinessStatusEnum.FINISH.getStatus()));
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package org.dromara.design.controller.app;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.design.domain.bo.DesVolumeFileBo;
|
||||
import org.dromara.design.domain.dto.volumefile.DesVolumeFileAppPageDto;
|
||||
import org.dromara.design.domain.dto.volumefile.DesVolumeFileCreateReq;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileAppVo;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileCodeVo;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileJoinVo;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileVo;
|
||||
import org.dromara.design.service.IDesVolumeFileService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* App图纸
|
||||
*
|
||||
* @author lilemy
|
||||
* @date 2025-07-30
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping("/app/design/volumeFile")
|
||||
public class DesVolumeFileAppController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private IDesVolumeFileService desVolumeFileService;
|
||||
|
||||
|
||||
/**
|
||||
* app图纸管理分页查询
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<DesVolumeFileAppVo> list(DesVolumeFileAppPageDto dto, PageQuery pageQuery) {
|
||||
return desVolumeFileService.queryAppPageList(dto, pageQuery);
|
||||
}
|
||||
|
||||
}
|
||||
@ -42,4 +42,6 @@ public class CoryObtainTheListReq implements Serializable {
|
||||
|
||||
private String sid;
|
||||
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
package org.dromara.design.domain.dto.volumefile;
|
||||
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.design.domain.DesVolumeFile;
|
||||
|
||||
/**
|
||||
* 卷册文件业务对象 des_volume_file
|
||||
*
|
||||
* @author lilemy
|
||||
* @date 2025-08-19
|
||||
*/
|
||||
@Data
|
||||
public class DesVolumeFileAppPageDto {
|
||||
|
||||
/**
|
||||
* 项目ID
|
||||
*/
|
||||
private Long projectId;
|
||||
|
||||
/**
|
||||
* 图纸类型(1-过程,3-蓝图,4-作废)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 查询参数
|
||||
*/
|
||||
private String queryParam;
|
||||
}
|
||||
@ -20,6 +20,7 @@ public class DetailsMaterialAndEquipmentApprovalRes implements Serializable {
|
||||
* 版本号
|
||||
*/
|
||||
private String versions;
|
||||
private String versionsName;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -0,0 +1,108 @@
|
||||
package org.dromara.design.domain.vo.volumefile;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.translation.annotation.Translation;
|
||||
import org.dromara.common.translation.constant.TransConstant;
|
||||
import org.dromara.design.domain.DesVolumeFile;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* 卷册文件视图对象 des_volume_file
|
||||
*
|
||||
* @author lilemy
|
||||
* @date 2025-07-30
|
||||
*/
|
||||
@Data
|
||||
public class DesVolumeFileAppVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 卷册目录ID
|
||||
*/
|
||||
private Long volumeCatalogId;
|
||||
|
||||
/**
|
||||
* 卷册号
|
||||
*/
|
||||
private String volumeNumber;
|
||||
|
||||
|
||||
/**
|
||||
* 设计子项
|
||||
*/
|
||||
private String designSubitem;
|
||||
|
||||
|
||||
/**
|
||||
* 文件ID
|
||||
*/
|
||||
private Long fileId;
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* 状态(1正常 2变更)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 专业
|
||||
*/
|
||||
private String specialty;
|
||||
|
||||
/**
|
||||
* 专业
|
||||
*/
|
||||
@Translation(type = TransConstant.DICT_TYPE_TO_LABEL, mapper = "specialty",other = "des_user_major")
|
||||
private String specialtyName;
|
||||
|
||||
/**
|
||||
* 图纸类型(1-过程,3-蓝图,4-作废)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 审核状态
|
||||
*/
|
||||
private String auditStatus;
|
||||
|
||||
/**
|
||||
* 负责人
|
||||
*/
|
||||
private String principal;
|
||||
|
||||
/**
|
||||
* 负责人
|
||||
*/
|
||||
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "principal")
|
||||
private String principalName;
|
||||
|
||||
/**
|
||||
* 路径
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 资料名称
|
||||
*/
|
||||
private String documentName;
|
||||
}
|
||||
@ -62,7 +62,7 @@ public class DesVolumeFileVo implements Serializable {
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 图纸类型(1-过程,2-变更,3-蓝图,4-作废)
|
||||
* 图纸类型(1-过程,3-蓝图,4-作废)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
|
||||
@ -5,6 +5,8 @@ import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.design.domain.DesVolumeFile;
|
||||
import org.dromara.design.domain.bo.DesVolumeFileBo;
|
||||
import org.dromara.design.domain.dto.volumefile.DesVolumeFileAppPageDto;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileAppVo;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileJoinVo;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
@ -20,4 +22,7 @@ public interface DesVolumeFileMapper extends BaseMapperPlus<DesVolumeFile, DesVo
|
||||
|
||||
|
||||
Page<DesVolumeFileJoinVo> queryJoinPageList(@Param("page")Page<DesVolumeFileJoinVo> page, @Param("bo")DesVolumeFileBo bo);
|
||||
|
||||
|
||||
Page<DesVolumeFileAppVo> queryAppPageList(@Param("page")Page<DesVolumeFileJoinVo> page, @Param("dto") DesVolumeFileAppPageDto dto);
|
||||
}
|
||||
|
||||
@ -6,7 +6,9 @@ import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.design.domain.DesVolumeFile;
|
||||
import org.dromara.design.domain.bo.DesVolumeFileBo;
|
||||
import org.dromara.design.domain.dto.volumefile.DesVolumeFileAppPageDto;
|
||||
import org.dromara.design.domain.dto.volumefile.DesVolumeFileCreateReq;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileAppVo;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileCodeVo;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileJoinVo;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileVo;
|
||||
@ -93,4 +95,9 @@ public interface IDesVolumeFileService extends IService<DesVolumeFile> {
|
||||
* 二维码获取卷册文件详细信息
|
||||
*/
|
||||
DesVolumeFileCodeVo getCodeInfo(Long id);
|
||||
|
||||
/**
|
||||
* app分页查询
|
||||
*/
|
||||
TableDataInfo<DesVolumeFileAppVo> queryAppPageList(DesVolumeFileAppPageDto dto, PageQuery pageQuery);
|
||||
}
|
||||
|
||||
@ -208,9 +208,20 @@ public class BusBillofquantitiesVersionsServiceImpl extends ServiceImpl<BusBillo
|
||||
//1、获取到解析数据
|
||||
ExcelReader.ExcelData excelData = ExcelReader.readExcelFromMultipartFile(file);
|
||||
//走正常的工程清单
|
||||
if (!Objects.equals(bo.getWorkOrderType(), "3")) {
|
||||
// 2. 解析所有工作表,转换为带父子关系的ExcelMaterial列表 解析所有Sheet数据,按规则生成sid和pid
|
||||
List<BusBillofquantities> allMaterials = new ArrayList<>();
|
||||
// if (!Objects.equals(bo.getWorkOrderType(), "3")) {
|
||||
// 2. 解析所有工作表,转换为带父子关系的ExcelMaterial列表 解析所有Sheet数据,按规则生成sid和pid
|
||||
List<BusBillofquantities> allMaterials = new ArrayList<>();
|
||||
if (Objects.equals(bo.getWorkOrderType(), "3")){
|
||||
ExcelReader.SheetData sheetData = excelData.getSheetDataList().getFirst();
|
||||
String sheetName = sheetData.getSheetName();
|
||||
List<List<String>> rowDataList = sheetData.getData();
|
||||
// 构建当前Sheet的树形结构(复用ExcelReader的buildTree方法)
|
||||
ExcelReader.TreeNode rootNode = ExcelReader.buildTree(rowDataList);
|
||||
// 存储节点映射:TreeNode → ExcelMaterial(用于子节点关联父节点)
|
||||
Map<ExcelReader.TreeNode, BusBillofquantities> nodeMap = new HashMap<>();
|
||||
// 递归遍历树形结构,生成sid和pid
|
||||
traverseTree(rootNode, nodeMap, allMaterials, sheetName, banBen);
|
||||
}else {
|
||||
for (ExcelReader.SheetData sheetData : excelData.getSheetDataList()) {
|
||||
String sheetName = sheetData.getSheetName();
|
||||
List<List<String>> rowDataList = sheetData.getData();
|
||||
@ -221,35 +232,36 @@ public class BusBillofquantitiesVersionsServiceImpl extends ServiceImpl<BusBillo
|
||||
// 递归遍历树形结构,生成sid和pid
|
||||
traverseTree(rootNode, nodeMap, allMaterials, sheetName, banBen);
|
||||
}
|
||||
// 3. 批量插入数据库
|
||||
for (BusBillofquantities allMaterial : allMaterials) {
|
||||
allMaterial.setProjectId(bo.getProjectId());
|
||||
}
|
||||
boolean b = busBillofquantitiesService.saveBatch(allMaterials);
|
||||
if (!b) {
|
||||
throw new RuntimeException("导入失败");
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
// 跳过1行(表头),读取0到6列(共7列),映射到ExcelData实体类
|
||||
List<MaterialsAndEquipmentExcelDto> dataList = ExcelDynamicReader.readExcel(
|
||||
file, // 上传的文件
|
||||
1, // 跳过1行(表头)
|
||||
0, // 从第0列开始
|
||||
5, // 到第5列结束
|
||||
MaterialsAndEquipmentExcelDto.class // 目标实体类
|
||||
);
|
||||
List<BusBillofquantities> busBillofquantities = BeanUtil.copyToList(dataList, BusBillofquantities.class);
|
||||
for (BusBillofquantities busBillofquantity : busBillofquantities) {
|
||||
busBillofquantity.setProjectId(bo.getProjectId());
|
||||
busBillofquantity.setVersions(banBen);
|
||||
}
|
||||
boolean b = busBillofquantitiesService.saveBatch(busBillofquantities);
|
||||
if (!b) {
|
||||
throw new RuntimeException("导入失败");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// 3. 批量插入数据库
|
||||
for (BusBillofquantities allMaterial : allMaterials) {
|
||||
allMaterial.setProjectId(bo.getProjectId());
|
||||
}
|
||||
boolean b = busBillofquantitiesService.saveBatch(allMaterials);
|
||||
if (!b) {
|
||||
throw new RuntimeException("导入失败");
|
||||
}
|
||||
return true;
|
||||
// } else {
|
||||
// // 跳过1行(表头),读取0到6列(共7列),映射到ExcelData实体类
|
||||
// List<MaterialsAndEquipmentExcelDto> dataList = ExcelDynamicReader.readExcel(
|
||||
// file, // 上传的文件
|
||||
// 1, // 跳过1行(表头)
|
||||
// 0, // 从第0列开始
|
||||
// 5, // 到第5列结束
|
||||
// MaterialsAndEquipmentExcelDto.class // 目标实体类
|
||||
// );
|
||||
// List<BusBillofquantities> busBillofquantities = BeanUtil.copyToList(dataList, BusBillofquantities.class);
|
||||
// for (BusBillofquantities busBillofquantity : busBillofquantities) {
|
||||
// busBillofquantity.setProjectId(bo.getProjectId());
|
||||
// busBillofquantity.setVersions(banBen);
|
||||
// }
|
||||
// boolean b = busBillofquantitiesService.saveBatch(busBillofquantities);
|
||||
// if (!b) {
|
||||
// throw new RuntimeException("导入失败");
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@ -261,9 +273,9 @@ public class BusBillofquantitiesVersionsServiceImpl extends ServiceImpl<BusBillo
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// sheet为空表示不走下面的代码
|
||||
if (StringUtils.isBlank(bo.getSheet())) {
|
||||
return flatList;
|
||||
}
|
||||
// if (StringUtils.isBlank(bo.getSheet())) {
|
||||
// return flatList;
|
||||
// }
|
||||
// 2. 构建父子映射:key=父节点pid,value=该父节点的所有子节点
|
||||
Map<String, List<ObtainTheListRes>> parentMap = flatList.stream()
|
||||
.collect(Collectors.groupingBy(ObtainTheListRes::getPid));
|
||||
@ -288,6 +300,7 @@ public class BusBillofquantitiesVersionsServiceImpl extends ServiceImpl<BusBillo
|
||||
throw new ServiceException("版本不存在");
|
||||
}
|
||||
detailsMaterialAndEquipmentApprovalRes.setVersions(busBillofquantitiesVersions.getVersions());
|
||||
detailsMaterialAndEquipmentApprovalRes.setVersionsName(StringUtils.isNotBlank(busBillofquantitiesVersions.getVersionsName())?busBillofquantitiesVersions.getVersionsName(): null);
|
||||
detailsMaterialAndEquipmentApprovalRes.setStatus(busBillofquantitiesVersions.getStatus());
|
||||
detailsMaterialAndEquipmentApprovalRes.setAuditData(busBillofquantities);
|
||||
return detailsMaterialAndEquipmentApprovalRes;
|
||||
@ -337,7 +350,8 @@ public class BusBillofquantitiesVersionsServiceImpl extends ServiceImpl<BusBillo
|
||||
public List<BusBillofquantitiesVo> obtainAllClassification(ObtainAllVersionNumbersReq bo) {
|
||||
LambdaQueryWrapper<BusBillofquantitiesVersions> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getProjectId() != null, BusBillofquantitiesVersions::getProjectId, bo.getProjectId());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getWorkOrderType()), BusBillofquantitiesVersions::getWorkOrderType, bo.getWorkOrderType());
|
||||
lqw.eq(BusBillofquantitiesVersions::getWorkOrderType, "3");
|
||||
lqw.eq(BusBillofquantitiesVersions::getStatus, BusinessStatusEnum.FINISH.getStatus());
|
||||
List<BusBillofquantitiesVersionsVo> result = baseMapper.selectVoList(lqw);
|
||||
List<String> versionss = new ArrayList<>();
|
||||
result.forEach(v -> versionss.add(v.getVersions()));
|
||||
|
||||
@ -15,10 +15,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.design.domain.dto.desUser.DesUserBatchDto;
|
||||
import org.dromara.system.domain.SysUserRole;
|
||||
import org.dromara.system.domain.bo.SysUserBo;
|
||||
import org.dromara.system.domain.vo.SysDictDataVo;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.system.service.ISysDictDataService;
|
||||
import org.dromara.system.service.ISysRoleService;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.dromara.design.domain.bo.DesUserBo;
|
||||
@ -26,6 +28,7 @@ import org.dromara.design.domain.vo.DesUserVo;
|
||||
import org.dromara.design.domain.DesUser;
|
||||
import org.dromara.design.mapper.DesUserMapper;
|
||||
import org.dromara.design.service.IDesUserService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
@ -49,6 +52,8 @@ public class DesUserServiceImpl extends ServiceImpl<DesUserMapper, DesUser> impl
|
||||
|
||||
private final ISysUserService sysUserService;
|
||||
|
||||
private final ISysRoleService roleService;
|
||||
|
||||
/**
|
||||
* 查询设计人员
|
||||
*
|
||||
@ -151,9 +156,44 @@ public class DesUserServiceImpl extends ServiceImpl<DesUserMapper, DesUser> impl
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean batchAddOrUpdate(DesUserBatchDto dto) {
|
||||
baseMapper.delete(Wrappers.<DesUser>lambdaQuery().eq(DesUser::getProjectId, dto.getProjectId()));
|
||||
|
||||
//1961314792461586433 校审员 3
|
||||
//1961315028017893378 审核员 5
|
||||
//1961315147199041537 审定员 4
|
||||
|
||||
List<DesUser> desUsers = MapstructUtils.convert(dto.getList(), DesUser.class);
|
||||
|
||||
roleService.deleteDesignUser(dto.getProjectId());
|
||||
|
||||
ArrayList<String> userIds = new ArrayList<>();
|
||||
|
||||
List<SysUserRole> sysUserRoles = new ArrayList<>();
|
||||
for (DesUserBo bo : dto.getList()) {
|
||||
if(bo.getUserId()==null){
|
||||
continue;
|
||||
}
|
||||
SysUserRole sysUserRole = new SysUserRole();
|
||||
if("3".equals(bo.getUserType())){
|
||||
sysUserRole.setRoleId(1961314792461586433L);
|
||||
}else if("5".equals(bo.getUserType())){
|
||||
sysUserRole.setRoleId(1961315028017893378L);
|
||||
}else if("4".equals(bo.getUserType())){
|
||||
sysUserRole.setRoleId(1961315147199041537L);
|
||||
}else {
|
||||
continue;
|
||||
}
|
||||
sysUserRole.setUserId(bo.getUserId());
|
||||
sysUserRole.setProjectId(dto.getProjectId());
|
||||
if(userIds.contains(sysUserRole.getUserId()+"-"+sysUserRole.getRoleId())){
|
||||
continue;
|
||||
}
|
||||
sysUserRoles.add(sysUserRole);
|
||||
userIds.add(sysUserRole.getUserId()+"-"+sysUserRole.getRoleId());
|
||||
}
|
||||
roleService.insertUserRoleBatch(sysUserRoles);
|
||||
//todo:发消息
|
||||
return saveBatch(desUsers);
|
||||
}
|
||||
@ -428,5 +468,9 @@ public class DesUserServiceImpl extends ServiceImpl<DesUserMapper, DesUser> impl
|
||||
DataValidationConstraint constraint = helper.createFormulaListConstraint(personRange);
|
||||
// 作用范围:第2行到100行,第四列
|
||||
CellRangeAddressList addressList = new CellRangeAddressList(1, 100, rowCount, rowCount);
|
||||
|
||||
DataValidation validation = helper.createValidation(constraint, addressList);
|
||||
validation.setShowErrorBox(true);
|
||||
mainSheet.addValidationData(validation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,8 +27,10 @@ import org.dromara.common.sse.utils.SseMessageUtils;
|
||||
import org.dromara.design.domain.DesVolumeCatalog;
|
||||
import org.dromara.design.domain.DesVolumeFile;
|
||||
import org.dromara.design.domain.bo.DesVolumeFileBo;
|
||||
import org.dromara.design.domain.dto.volumefile.DesVolumeFileAppPageDto;
|
||||
import org.dromara.design.domain.dto.volumefile.DesVolumeFileCreateReq;
|
||||
import org.dromara.design.domain.vo.BusDrawingreviewReceiptsVo;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileAppVo;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileCodeVo;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileJoinVo;
|
||||
import org.dromara.design.domain.vo.volumefile.DesVolumeFileVo;
|
||||
@ -469,6 +471,12 @@ public class DesVolumeFileServiceImpl extends ServiceImpl<DesVolumeFileMapper, D
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TableDataInfo<DesVolumeFileAppVo> queryAppPageList(DesVolumeFileAppPageDto dto, PageQuery pageQuery) {
|
||||
Page<DesVolumeFileAppVo> result = baseMapper.queryAppPageList(pageQuery.build(), dto);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
|
||||
* 正常使用只需#processEvent.flowCode=='leave1'
|
||||
|
||||
@ -50,7 +50,7 @@ public class BusAttendanceController extends BaseController {
|
||||
/**
|
||||
* 查询施工人员月份考勤列表
|
||||
*/
|
||||
@SaCheckPermission("project:attendance:list")
|
||||
// @SaCheckPermission("project:attendance:list")
|
||||
@GetMapping("/list/month/byUserId")
|
||||
public R<List<BusAttendanceMonthByUserIdVo>> listAttendanceMonthListByUserId(BusAttendanceMonthByUserIdReq req) {
|
||||
return R.ok(busAttendanceService.listAttendanceMonthListByUserId(req));
|
||||
|
||||
@ -60,7 +60,7 @@ public class BusProjectAppController {
|
||||
@GetMapping("/login/list")
|
||||
public R<List<BusLoginUserProjectRelevancyVo>> listByLoginUser() {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
return R.ok(userProjectRelevancyService.queryListByUserId(userId));
|
||||
return R.ok(userProjectRelevancyService.appQueryListByUserId(userId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -35,6 +35,11 @@ public class BusProjectTeamMemberCreateReq implements Serializable {
|
||||
*/
|
||||
private String postId;
|
||||
|
||||
/**
|
||||
* 工种
|
||||
*/
|
||||
private String typeOfWork;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
|
||||
@ -44,4 +44,10 @@ public class BusLoginUserProjectRelevancyVo implements Serializable {
|
||||
* 用户类型(0系统管理员 1普通人员 2项目管理员)
|
||||
*/
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* 班组
|
||||
*/
|
||||
private Long teamId;
|
||||
|
||||
}
|
||||
|
||||
@ -115,6 +115,8 @@ public interface IBusUserProjectRelevancyService extends IService<BusUserProject
|
||||
*/
|
||||
List<BusLoginUserProjectRelevancyVo> queryListByUserId(Long userId);
|
||||
|
||||
List<BusLoginUserProjectRelevancyVo> appQueryListByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 获取当前登录用户项目分页
|
||||
*
|
||||
|
||||
@ -17,6 +17,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.dromara.common.core.constant.DateConstant;
|
||||
import org.dromara.common.core.constant.HttpStatus;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
@ -1041,7 +1042,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
AttendanceUserDataDetailVo detailVo = new AttendanceUserDataDetailVo();
|
||||
detailVo.setClockDate(key);
|
||||
detailVo.setWeek(key.getDayOfWeek().getValue());
|
||||
detailVo.setWorkDay(value.size()*0.5);
|
||||
detailVo.setWorkDay(value.size() * 0.5);
|
||||
workList.add(detailVo);
|
||||
}
|
||||
vo.setWork(workList);
|
||||
@ -1178,164 +1179,170 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
|
||||
@Override
|
||||
public void getExportList(AttendanceExportDto dto, HttpServletResponse response) {
|
||||
try (OutputStream outputStream = response.getOutputStream()) {
|
||||
BusProject project = projectService.getById(dto.getProjectId());
|
||||
|
||||
BusProject project = projectService.getById(dto.getProjectId());
|
||||
|
||||
if (project == null) {
|
||||
throw new ServiceException("项目不存在");
|
||||
}
|
||||
|
||||
List<SubConstructionUser> list = constructionUserService.list(Wrappers.lambdaQuery(SubConstructionUser.class)
|
||||
.eq(SubConstructionUser::getProjectId, dto.getProjectId())
|
||||
.eq(dto.getTeamId() != null, SubConstructionUser::getTeamId, dto.getTeamId())
|
||||
.eq(StrUtil.isNotBlank(dto.getTypeOfWork()), SubConstructionUser::getTypeOfWork, dto.getTypeOfWork())
|
||||
.like(StringUtils.isNotBlank(dto.getUserName()), SubConstructionUser::getUserName, dto.getUserName())
|
||||
);
|
||||
|
||||
if (list.isEmpty()) {
|
||||
throw new ServiceException("未查询到相关人员");
|
||||
}
|
||||
|
||||
List<Long> userIds = list.stream().map(SubConstructionUser::getSysUserId).toList();
|
||||
String clockDate = dto.getClockDate();
|
||||
|
||||
YearMonth yearMonth = YearMonth.parse(clockDate, DateTimeFormatter.ofPattern("yyyy-MM"));
|
||||
LocalDate start = yearMonth.atDay(1);
|
||||
LocalDate end = yearMonth.atEndOfMonth();
|
||||
|
||||
int daysInMonth = yearMonth.lengthOfMonth(); // 动态获取天数
|
||||
|
||||
List<BusAttendance> attendanceList = list(Wrappers.lambdaQuery(BusAttendance.class)
|
||||
.in(BusAttendance::getUserId, userIds)
|
||||
.between(BusAttendance::getClockDate, start, end)
|
||||
);
|
||||
|
||||
Map<Long, List<SubConstructionUser>> teamUserMap = list.stream()
|
||||
.collect(Collectors.groupingBy(user ->
|
||||
user.getTeamId() != null ? user.getTeamId() : 0L));
|
||||
Workbook workbook = new HSSFWorkbook();
|
||||
|
||||
for (Map.Entry<Long, List<SubConstructionUser>> entry : teamUserMap.entrySet()) {
|
||||
Long teamId = entry.getKey();
|
||||
System.out.println("teamId:" + teamId);
|
||||
List<SubConstructionUser> users = entry.getValue();
|
||||
SubConstructionUser constructionUser = users.getFirst();
|
||||
String teamName = constructionUser.getTeamName();
|
||||
if (teamId == 0) {
|
||||
teamName = "无班组";
|
||||
if (project == null) {
|
||||
throw new ServiceException("项目不存在");
|
||||
}
|
||||
if (StringUtils.isBlank(teamName)) {
|
||||
teamName = teamId.toString();
|
||||
}
|
||||
System.out.println("name:" + teamName);
|
||||
Sheet sheet = workbook.createSheet(teamName);
|
||||
String clockDate = dto.getClockDate();
|
||||
YearMonth yearMonth = YearMonth.parse(clockDate, DateTimeFormatter.ofPattern("yyyy-MM"));
|
||||
LocalDate start = yearMonth.atDay(1);
|
||||
LocalDate end = yearMonth.atEndOfMonth();
|
||||
|
||||
// ==================== 设置列宽 ====================
|
||||
sheet.setColumnWidth(0, 5 * 256); // 序号
|
||||
sheet.setColumnWidth(1, 10 * 256); // 姓名/日期
|
||||
sheet.setColumnWidth(2, 30 * 256); // 身份证号
|
||||
LocalDateTime startTime = LocalDateTime.of(yearMonth.atDay(1), LocalTime.MIN); // 00:00:00
|
||||
LocalDateTime endTime = LocalDateTime.of(yearMonth.atEndOfMonth(), LocalTime.MAX);
|
||||
|
||||
// 日期列(每天一列)
|
||||
for (int i = 3; i < 3 + daysInMonth; i++) {
|
||||
sheet.setColumnWidth(i, 5 * 256); // 每天列宽 15 字符
|
||||
List<SubConstructionUser> list = constructionUserService.list(Wrappers.lambdaQuery(SubConstructionUser.class)
|
||||
.eq(SubConstructionUser::getProjectId, dto.getProjectId())
|
||||
.isNotNull(SubConstructionUser::getEntryDate)
|
||||
.and(wrapper -> wrapper.between(SubConstructionUser::getLeaveDate, startTime, endTime).or()
|
||||
.isNull(SubConstructionUser::getLeaveDate))
|
||||
.eq(dto.getTeamId() != null, SubConstructionUser::getTeamId, dto.getTeamId())
|
||||
.eq(StrUtil.isNotBlank(dto.getTypeOfWork()), SubConstructionUser::getTypeOfWork, dto.getTypeOfWork())
|
||||
.like(StringUtils.isNotBlank(dto.getUserName()), SubConstructionUser::getUserName, dto.getUserName())
|
||||
);
|
||||
|
||||
if (list.isEmpty()) {
|
||||
throw new ServiceException("未查询到相关人员");
|
||||
}
|
||||
|
||||
sheet.setColumnWidth(3 + daysInMonth, 5 * 256); // 合计
|
||||
sheet.setColumnWidth(3 + daysInMonth + 1, 10 * 256); // 是否离场
|
||||
sheet.setColumnWidth(3 + daysInMonth + 2, 15 * 256); // 签字
|
||||
List<Long> userIds = list.stream().map(SubConstructionUser::getSysUserId).toList();
|
||||
|
||||
// ==================== 创建样式 ====================
|
||||
CellStyle borderStyle = createBorderStyle(workbook);
|
||||
int daysInMonth = yearMonth.lengthOfMonth(); // 动态获取天数
|
||||
|
||||
List<BusAttendance> attendanceList = list(Wrappers.lambdaQuery(BusAttendance.class)
|
||||
.in(BusAttendance::getUserId, userIds)
|
||||
.between(BusAttendance::getClockDate, start, end)
|
||||
);
|
||||
|
||||
Map<Long, List<SubConstructionUser>> teamUserMap = list.stream()
|
||||
.collect(Collectors.groupingBy(user ->
|
||||
user.getTeamId() != null ? user.getTeamId() : 0L));
|
||||
|
||||
Workbook workbook = new XSSFWorkbook();
|
||||
|
||||
for (Map.Entry<Long, List<SubConstructionUser>> entry : teamUserMap.entrySet()) {
|
||||
Long teamId = entry.getKey();
|
||||
System.out.println("teamId:" + teamId);
|
||||
List<SubConstructionUser> users = entry.getValue();
|
||||
SubConstructionUser constructionUser = users.getFirst();
|
||||
String teamName = constructionUser.getTeamName();
|
||||
if (teamId == 0) {
|
||||
teamName = "无班组";
|
||||
}
|
||||
if (StringUtils.isBlank(teamName)) {
|
||||
teamName = teamId.toString();
|
||||
}
|
||||
System.out.println("name:" + teamName);
|
||||
Sheet sheet = workbook.createSheet(teamName);
|
||||
|
||||
// ==================== 设置列宽 ====================
|
||||
sheet.setColumnWidth(0, 5 * 256); // 序号
|
||||
sheet.setColumnWidth(1, 10 * 256); // 姓名/日期
|
||||
sheet.setColumnWidth(2, 30 * 256); // 身份证号
|
||||
|
||||
// 日期列(每天一列)
|
||||
for (int i = 3; i < 3 + daysInMonth; i++) {
|
||||
sheet.setColumnWidth(i, 5 * 256); // 每天列宽 15 字符
|
||||
}
|
||||
|
||||
sheet.setColumnWidth(3 + daysInMonth, 5 * 256); // 合计
|
||||
sheet.setColumnWidth(3 + daysInMonth + 1, 10 * 256); // 是否离场
|
||||
sheet.setColumnWidth(3 + daysInMonth + 2, 15 * 256); // 签字
|
||||
|
||||
// ==================== 创建样式 ====================
|
||||
CellStyle borderStyle = createBorderStyle(workbook);
|
||||
// CellStyle numberStyle = createNumberStyle(workbook);
|
||||
|
||||
|
||||
// ==================== 表头部分 ====================
|
||||
Row titleRow = sheet.createRow(0);
|
||||
Cell titleCell = titleRow.createCell(0);
|
||||
titleCell.setCellValue("建筑施工企业现场人员考勤表(" + clockDate + ")");
|
||||
titleCell.setCellStyle(createTitleCellStyle(workbook));
|
||||
// ==================== 表头部分 ====================
|
||||
Row titleRow = sheet.createRow(0);
|
||||
Cell titleCell = titleRow.createCell(0);
|
||||
titleCell.setCellValue("建筑施工企业现场人员考勤表(" + clockDate + ")");
|
||||
titleCell.setCellStyle(createTitleCellStyle(workbook));
|
||||
|
||||
// 合并标题行,横跨所有列
|
||||
int totalColumns = 3 + daysInMonth + 3; // 总列数
|
||||
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, totalColumns - 1));
|
||||
// 合并标题行,横跨所有列
|
||||
int totalColumns = 3 + daysInMonth + 3; // 总列数
|
||||
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, totalColumns - 1));
|
||||
|
||||
// ==================== 第二行:项目名称和班组类别 ====================
|
||||
Row projectRow = sheet.createRow(1);
|
||||
// ==================== 第二行:项目名称和班组类别 ====================
|
||||
Row projectRow = sheet.createRow(1);
|
||||
|
||||
// 设置项目名称(左对齐,占据前半部分)
|
||||
Cell projectNameCell = projectRow.createCell(0);
|
||||
projectNameCell.setCellValue("项目名称:" + project.getProjectName());
|
||||
projectNameCell.setCellStyle(createProjectCellStyle(workbook)); // 可选:设置样式
|
||||
// 设置项目名称(左对齐,占据前半部分)
|
||||
Cell projectNameCell = projectRow.createCell(0);
|
||||
projectNameCell.setCellValue("项目名称:" + project.getProjectName());
|
||||
projectNameCell.setCellStyle(createProjectCellStyle(workbook)); // 可选:设置样式
|
||||
|
||||
int midColumn = (totalColumns / 2) - 1;
|
||||
int midColumn = (totalColumns / 2) - 1;
|
||||
|
||||
// 设置班组类别(右对齐,占据后半部分)
|
||||
int teamCol = midColumn + 1; //
|
||||
Cell teamNameCell = projectRow.createCell(teamCol);
|
||||
teamNameCell.setCellValue("班组类别:" + teamName);
|
||||
teamNameCell.setCellStyle(createProjectCellStyle(workbook));
|
||||
// 设置班组类别(右对齐,占据后半部分)
|
||||
int teamCol = midColumn + 1; //
|
||||
Cell teamNameCell = projectRow.createCell(teamCol);
|
||||
teamNameCell.setCellValue("班组类别:" + teamName);
|
||||
teamNameCell.setCellStyle(createProjectCellStyle(workbook));
|
||||
|
||||
// 合并项目名称区域(从第 0 列到中间)
|
||||
if (midColumn >= 0) {
|
||||
sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, midColumn));
|
||||
}
|
||||
|
||||
// 合并班组类别区域(从 teamCol 开始,到最后一列)
|
||||
if (teamCol < totalColumns) {
|
||||
sheet.addMergedRegion(new CellRangeAddress(1, 1, teamCol, totalColumns - 1));
|
||||
}
|
||||
|
||||
// ==================== 数据表头 ====================
|
||||
Row headerRow = sheet.createRow(2);
|
||||
writeHeaderRow(headerRow, daysInMonth);
|
||||
// 设置表头边框
|
||||
for (int i = 0; i < totalColumns; i++) {
|
||||
Cell cell = headerRow.getCell(i);
|
||||
if (cell != null) {
|
||||
cell.setCellStyle(borderStyle);
|
||||
// 合并项目名称区域(从第 0 列到中间)
|
||||
if (midColumn >= 0) {
|
||||
sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, midColumn));
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 数据行 ====================
|
||||
CellStyle numberBorderStyle = createNumberBorderStyle(workbook);
|
||||
// 合并班组类别区域(从 teamCol 开始,到最后一列)
|
||||
if (teamCol < totalColumns) {
|
||||
sheet.addMergedRegion(new CellRangeAddress(1, 1, teamCol, totalColumns - 1));
|
||||
}
|
||||
|
||||
int rowIndex = 3;
|
||||
for (SubConstructionUser user : users) {
|
||||
Row row = sheet.createRow(rowIndex++);
|
||||
writeDataRow(row, user, attendanceList, start, end, daysInMonth,borderStyle,numberBorderStyle);
|
||||
|
||||
// 设置数据行边框
|
||||
// ==================== 数据表头 ====================
|
||||
Row headerRow = sheet.createRow(2);
|
||||
writeHeaderRow(headerRow, daysInMonth);
|
||||
// 设置表头边框
|
||||
for (int i = 0; i < totalColumns; i++) {
|
||||
Cell cell = row.getCell(i);
|
||||
Cell cell = headerRow.getCell(i);
|
||||
if (cell != null) {
|
||||
cell.setCellStyle(borderStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ==================== 设置月份天数列为数字格式 + 边框 ====================
|
||||
|
||||
// ==================== 数据行 ====================
|
||||
CellStyle numberBorderStyle = createNumberBorderStyle(workbook);
|
||||
|
||||
// 表头
|
||||
for (int i = 3; i < 3 + daysInMonth; i++) {
|
||||
Cell headerCell = headerRow.getCell(i);
|
||||
if (headerCell != null) {
|
||||
headerCell.setCellStyle(numberBorderStyle);
|
||||
}
|
||||
}
|
||||
int rowIndex = 3;
|
||||
for (SubConstructionUser user : users) {
|
||||
Row row = sheet.createRow(rowIndex++);
|
||||
writeDataRow(row, user, attendanceList, start, end, daysInMonth, borderStyle, numberBorderStyle);
|
||||
|
||||
// 数据行
|
||||
for (int i = 3; i < 3 + daysInMonth; i++) {
|
||||
for (int j = 3; j < rowIndex; j++) {
|
||||
Row dataRow = sheet.getRow(j);
|
||||
if (dataRow != null) {
|
||||
Cell dataCell = dataRow.getCell(i);
|
||||
if (dataCell != null) {
|
||||
dataCell.setCellStyle(numberBorderStyle);
|
||||
// 设置数据行边框
|
||||
for (int i = 0; i < totalColumns; i++) {
|
||||
Cell cell = row.getCell(i);
|
||||
if (cell != null) {
|
||||
cell.setCellStyle(borderStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ==================== 设置合计列公式 ====================
|
||||
// ==================== 设置月份天数列为数字格式 + 边框 ====================
|
||||
|
||||
|
||||
// 表头
|
||||
for (int i = 3; i < 3 + daysInMonth; i++) {
|
||||
Cell headerCell = headerRow.getCell(i);
|
||||
if (headerCell != null) {
|
||||
headerCell.setCellStyle(numberBorderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
// 数据行
|
||||
for (int i = 3; i < 3 + daysInMonth; i++) {
|
||||
for (int j = 3; j < rowIndex; j++) {
|
||||
Row dataRow = sheet.getRow(j);
|
||||
if (dataRow != null) {
|
||||
Cell dataCell = dataRow.getCell(i);
|
||||
if (dataCell != null) {
|
||||
dataCell.setCellStyle(numberBorderStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ==================== 设置合计列公式 ====================
|
||||
// for (int i = 4; i < rowIndex; i++) {
|
||||
// Row dataRow = sheet.getRow(i);
|
||||
// if (dataRow != null) {
|
||||
@ -1358,47 +1365,47 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
// }
|
||||
// }
|
||||
|
||||
// ==================== 表尾部分 ====================
|
||||
// ==================== 表尾部分 ====================
|
||||
|
||||
sheet.createRow(rowIndex++);
|
||||
sheet.createRow(rowIndex++);
|
||||
|
||||
Row footerRow1 = sheet.createRow(rowIndex++);
|
||||
int allTotalColumns = 3 + daysInMonth + 3;
|
||||
int quarter = allTotalColumns / 4;
|
||||
Row footerRow1 = sheet.createRow(rowIndex++);
|
||||
int allTotalColumns = 3 + daysInMonth + 3;
|
||||
int quarter = allTotalColumns / 4;
|
||||
|
||||
int[] colSpans = {
|
||||
quarter - 3, // 第一列减少3列
|
||||
quarter + 2, // 第二列增加2列
|
||||
quarter + 2, // 第三列增加2列
|
||||
allTotalColumns - (quarter - 3 + quarter + 2 + quarter + 2) // 自动计算最后一列
|
||||
};
|
||||
int[] colSpans = {
|
||||
quarter - 3, // 第一列减少3列
|
||||
quarter + 2, // 第二列增加2列
|
||||
quarter + 2, // 第三列增加2列
|
||||
allTotalColumns - (quarter - 3 + quarter + 2 + quarter + 2) // 自动计算最后一列
|
||||
};
|
||||
|
||||
int startCol = 0;
|
||||
String[] footerLabels = {"制表人:", "班组负责人:", "项目负责人:", "制表日期:"};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int endCol = startCol + colSpans[i] - 1;
|
||||
int startCol = 0;
|
||||
String[] footerLabels = {"制表人:", "班组负责人:", "项目负责人:", "制表日期:"};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int endCol = startCol + colSpans[i] - 1;
|
||||
|
||||
// 合并单元格
|
||||
sheet.addMergedRegion(new CellRangeAddress(rowIndex - 1, rowIndex - 1, startCol, endCol));
|
||||
// 合并单元格
|
||||
sheet.addMergedRegion(new CellRangeAddress(rowIndex - 1, rowIndex - 1, startCol, endCol));
|
||||
|
||||
// 创建单元格并设置内容
|
||||
Cell cell = footerRow1.createCell(startCol);
|
||||
cell.setCellValue(footerLabels[i]);
|
||||
cell.setCellStyle(createLeftAlignedCellStyle(workbook)); // 左对齐
|
||||
// 创建单元格并设置内容
|
||||
Cell cell = footerRow1.createCell(startCol);
|
||||
cell.setCellValue(footerLabels[i]);
|
||||
cell.setCellStyle(createLeftAlignedCellStyle(workbook)); // 左对齐
|
||||
|
||||
startCol = endCol + 1;
|
||||
}
|
||||
|
||||
Row footerRow2 = sheet.createRow(rowIndex++);
|
||||
footerRow2.createCell(0).setCellValue("注:");
|
||||
footerRow2.createCell(1).setCellValue("1、本考勤表必须按照每日实际工时进行填写;");
|
||||
Row footerRow3 = sheet.createRow(rowIndex++);
|
||||
footerRow3.createCell(0).setCellValue("");
|
||||
footerRow3.createCell(1).setCellValue("2、本考勤表作为工资计发的重要依据。");
|
||||
|
||||
startCol = endCol + 1;
|
||||
}
|
||||
|
||||
Row footerRow2 = sheet.createRow(rowIndex++);
|
||||
footerRow2.createCell(0).setCellValue("注:");
|
||||
footerRow2.createCell(1).setCellValue("1、本考勤表必须按照每日实际工时进行填写;");
|
||||
Row footerRow3 = sheet.createRow(rowIndex++);
|
||||
footerRow3.createCell(0).setCellValue("");
|
||||
footerRow3.createCell(1).setCellValue("2、本考勤表作为工资计发的重要依据。");
|
||||
|
||||
}
|
||||
|
||||
try (OutputStream outputStream = response.getOutputStream()) {
|
||||
workbook.write(outputStream);
|
||||
workbook.close();
|
||||
} catch (IOException e) {
|
||||
@ -1417,6 +1424,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
}
|
||||
return columnName.toString();
|
||||
}
|
||||
|
||||
private CellStyle createBorderStyle(Workbook workbook) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
@ -1425,10 +1433,11 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
return style;
|
||||
}
|
||||
|
||||
private CellStyle createNumberBorderStyle(Workbook workbook) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
DataFormat format = workbook.createDataFormat();
|
||||
style.setDataFormat(format.getFormat("0")); // 强制显示 0
|
||||
style.setDataFormat(format.getFormat("0.0")); // 显示一位小数
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
@ -1478,8 +1487,8 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
row.createCell(2 + daysInMonth + 3).setCellValue("签字");
|
||||
}
|
||||
|
||||
private void writeDataRow(Row row, SubConstructionUser user, List<BusAttendance> attendanceList, LocalDate start, LocalDate end, int daysInMonth,CellStyle borderStyle,CellStyle numberBorderStyle) {
|
||||
int index = row.getRowNum()-2;
|
||||
private void writeDataRow(Row row, SubConstructionUser user, List<BusAttendance> attendanceList, LocalDate start, LocalDate end, int daysInMonth, CellStyle borderStyle, CellStyle numberBorderStyle) {
|
||||
int index = row.getRowNum() - 2;
|
||||
row.createCell(0).setCellValue(index);
|
||||
row.createCell(1).setCellValue(user.getUserName());
|
||||
row.createCell(2).setCellValue(idCardEncryptorUtil.decrypt(user.getSfzNumber()));
|
||||
@ -1502,7 +1511,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
sumCell.setCellFormula(formula);
|
||||
sumCell.setCellStyle(borderStyle);
|
||||
|
||||
String leaveStatus = "0".equals(user.getExitStatus()) ? "未离场" : "已离场";
|
||||
String leaveStatus = user.getLeaveDate() != null ? "已离场" : "未离场";
|
||||
row.createCell(2 + daysInMonth + 2).setCellValue(leaveStatus);
|
||||
|
||||
row.createCell(2 + daysInMonth + 3).setCellValue("");
|
||||
@ -1541,7 +1550,7 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
|
||||
|
||||
while (!current.isAfter(end)) {
|
||||
Double value = getAttendanceValue(userId, current, attendanceList);
|
||||
total+=value;
|
||||
total += value;
|
||||
current = current.plusDays(1);
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.project.constant.BusProjectConstant;
|
||||
import org.dromara.project.domain.BusProject;
|
||||
import org.dromara.project.domain.BusProjectTeamMember;
|
||||
import org.dromara.project.domain.BusUserProjectRelevancy;
|
||||
import org.dromara.project.domain.dto.project.BusProjectBatchByProjectListReq;
|
||||
import org.dromara.project.domain.dto.userprojectrelevancy.BusUserProjectRelevancyCreateReq;
|
||||
@ -25,6 +26,7 @@ import org.dromara.project.domain.vo.userprojectrelevancy.BusLoginUserProjectRel
|
||||
import org.dromara.project.domain.vo.userprojectrelevancy.BusUserProjectRelevancyVo;
|
||||
import org.dromara.project.mapper.BusUserProjectRelevancyMapper;
|
||||
import org.dromara.project.service.IBusProjectService;
|
||||
import org.dromara.project.service.IBusProjectTeamMemberService;
|
||||
import org.dromara.project.service.IBusUserProjectRelevancyService;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
@ -52,6 +54,10 @@ public class BusUserProjectRelevancyServiceImpl extends ServiceImpl<BusUserProje
|
||||
@Resource
|
||||
private ISysUserService userService;
|
||||
|
||||
@Lazy
|
||||
@Resource
|
||||
private IBusProjectTeamMemberService projectMemberService;
|
||||
|
||||
/**
|
||||
* 查询系统用户与项目关联
|
||||
*
|
||||
@ -329,6 +335,54 @@ public class BusUserProjectRelevancyServiceImpl extends ServiceImpl<BusUserProje
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BusLoginUserProjectRelevancyVo> appQueryListByUserId(Long userId) {
|
||||
// 添加查询条件,根据当前用户,获取数据
|
||||
LambdaQueryWrapper<BusUserProjectRelevancy> queryWrapper = Wrappers.lambdaQuery();
|
||||
queryWrapper.eq(BusUserProjectRelevancy::getUserId, userId);
|
||||
// 查询数据库,获取数据
|
||||
List<BusUserProjectRelevancy> list = this.list(queryWrapper);
|
||||
List<Long> projectIdList = list.stream().map(BusUserProjectRelevancy::getProjectId).toList();
|
||||
if (CollUtil.isEmpty(projectIdList)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Map<Long, List<BusProject>> projectMap = projectService.lambdaQuery()
|
||||
.select(BusProject::getId, BusProject::getPId, BusProject::getProjectName, BusProject::getShortName)
|
||||
.in(BusProject::getId, projectIdList)
|
||||
.eq(BusProject::getPId, BusProjectConstant.PARENT_ID)
|
||||
.list()
|
||||
.stream().collect(Collectors.groupingBy(BusProject::getId));
|
||||
|
||||
Map<Long, Long> teamMap = projectMemberService.lambdaQuery().eq(BusProjectTeamMember::getMemberId, userId).list()
|
||||
.stream().collect(Collectors.toMap(BusProjectTeamMember::getProjectId, BusProjectTeamMember::getTeamId));
|
||||
|
||||
|
||||
// 获取封装
|
||||
return list.stream()
|
||||
.map(userProjectRelevancy -> {
|
||||
Long projectId = userProjectRelevancy.getProjectId();
|
||||
BusProject project = null;
|
||||
if (projectMap.containsKey(projectId)) {
|
||||
project = projectMap.get(projectId).getFirst();
|
||||
}
|
||||
if (project != null && project.getPId().equals(BusProjectConstant.PARENT_ID)) {
|
||||
BusLoginUserProjectRelevancyVo loginUserProjectRelevancy = new BusLoginUserProjectRelevancyVo();
|
||||
loginUserProjectRelevancy.setId(userProjectRelevancy.getId());
|
||||
loginUserProjectRelevancy.setUserId(userProjectRelevancy.getUserId());
|
||||
loginUserProjectRelevancy.setProjectId(projectId);
|
||||
loginUserProjectRelevancy.setProjectName(project.getProjectName());
|
||||
loginUserProjectRelevancy.setShortName(project.getShortName());
|
||||
loginUserProjectRelevancy.setTeamId(teamMap.get(projectId));
|
||||
return loginUserProjectRelevancy;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户项目分页
|
||||
*
|
||||
|
||||
@ -7,11 +7,13 @@ import lombok.Data;
|
||||
import org.dromara.common.translation.annotation.Translation;
|
||||
import org.dromara.common.translation.constant.TransConstant;
|
||||
import org.dromara.quality.domain.QltQualityConstructionLog;
|
||||
import org.dromara.system.domain.vo.SysOssVo;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
@ -76,8 +78,7 @@ public class QltQualityConstructionLogVo implements Serializable {
|
||||
/**
|
||||
* 附件列表
|
||||
*/
|
||||
@Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "file")
|
||||
private String fileList;
|
||||
private List<SysOssVo> fileList;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
|
||||
@ -196,6 +196,13 @@ public class QltQualityConstructionLogServiceImpl extends ServiceImpl<QltQuality
|
||||
if (qualityConstructionLog == null) {
|
||||
return qualityConstructionLogVo;
|
||||
}
|
||||
// 关联附件信息
|
||||
String file = qualityConstructionLog.getFile();
|
||||
if (StringUtils.isNotBlank(file)) {
|
||||
List<Long> ossIdList = Arrays.stream(file.split(",")).map(Long::parseLong).toList();
|
||||
List<SysOssVo> ossVoList = ossService.listByIds(ossIdList);
|
||||
qualityConstructionLogVo.setFileList(ossVoList);
|
||||
}
|
||||
BeanUtils.copyProperties(qualityConstructionLog, qualityConstructionLogVo);
|
||||
return qualityConstructionLogVo;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package org.dromara.system.service;
|
||||
import org.dromara.common.core.domain.vo.SysProjectRolePermissionVo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.design.domain.DesUser;
|
||||
import org.dromara.system.domain.SysUserRole;
|
||||
import org.dromara.system.domain.bo.SysRoleBo;
|
||||
import org.dromara.system.domain.dto.role.SysRoleProjectDto;
|
||||
@ -208,4 +209,10 @@ public interface ISysRoleService {
|
||||
|
||||
void cleanOnlineUser(List<Long> userIds);
|
||||
|
||||
void insertUserRoleBatch(List<SysUserRole> list);
|
||||
|
||||
/**
|
||||
* 批量删除审核审定校审
|
||||
*/
|
||||
void deleteDesignUser(Long projectId);
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ public class SysRoleServiceImpl implements ISysRoleService, RoleService {
|
||||
.orderByAsc("r.role_sort").orderByAsc("r.create_time");
|
||||
// 添加部门ID或角色ID在2,3,4中的条件
|
||||
if (ObjectUtil.isNotNull(bo.getDeptId())) {
|
||||
wrapper.and(w -> w.eq("r.dept_id", bo.getDeptId()).or().in("r.role_id", Arrays.asList(2L, 3L, 4L)));
|
||||
wrapper.and(w -> w.eq("r.dept_id", bo.getDeptId()).or().eq("r.dept_id", 99L));
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
@ -627,4 +627,17 @@ public class SysRoleServiceImpl implements ISysRoleService, RoleService {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertUserRoleBatch(List<SysUserRole> list) {
|
||||
userRoleMapper.insertBatch(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteDesignUser(Long projectId) {
|
||||
List<Long> list1 = Arrays.asList(1961314792461586433L, 1961315028017893378L, 1961315147199041537L);
|
||||
userRoleMapper.delete(Wrappers.lambdaQuery(SysUserRole.class)
|
||||
.eq(SysUserRole::getProjectId, projectId)
|
||||
.in(SysUserRole::getRoleId, list1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,16 +87,8 @@ public class TenderSupplierInputController extends BaseController {
|
||||
@PostMapping("/import")
|
||||
public R<Void> importData(Long projectId,@RequestParam("file")MultipartFile file) throws IOException {
|
||||
List<TenderSupplierInputVo> tenderSupplierInputVos = ExcelUtil.importExcel(file.getInputStream(), TenderSupplierInputVo.class);
|
||||
List<TenderSupplierInput> tenderSupplierInputs = new ArrayList<>();
|
||||
|
||||
for (TenderSupplierInputVo tenderSupplierInputVo : tenderSupplierInputVos) {
|
||||
TenderSupplierInput newTenderSupplierInput = new TenderSupplierInput();
|
||||
BeanUtils.copyProperties(tenderSupplierInputVo, newTenderSupplierInput);
|
||||
newTenderSupplierInput.setProjectId(projectId);
|
||||
newTenderSupplierInput.setState("draft");
|
||||
tenderSupplierInputs.add(newTenderSupplierInput);
|
||||
}
|
||||
return toAjax(tenderSupplierInputService.saveOrUpdateBatch(tenderSupplierInputs));
|
||||
return toAjax(tenderSupplierInputService.importData(tenderSupplierInputVos,projectId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -72,4 +72,6 @@ ITenderSupplierInputService extends IService<TenderSupplierInput>{
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
List<TenderSupplierInputVo> getList(TenderSupplierInputBo bo);
|
||||
|
||||
boolean importData(List<TenderSupplierInputVo> tenderSupplierInputVos, Long projectId);
|
||||
}
|
||||
|
||||
@ -203,9 +203,9 @@ public class BusBillofquantitiesLimitListServiceImpl extends ServiceImpl<BusBill
|
||||
.forEach(item -> {
|
||||
item.setPrice(item.getUnitPrice().multiply(item.getQuantity()).setScale(4, RoundingMode.HALF_UP));
|
||||
});
|
||||
if (bo.getType().equals(LimitListTypeEnum.SPECIAL.getCode())) {
|
||||
return listVoList;
|
||||
}
|
||||
// if (bo.getType().equals(LimitListTypeEnum.SPECIAL.getCode())) {
|
||||
// return listVoList;
|
||||
// }
|
||||
|
||||
//构建父子映射
|
||||
Map<String, List<BusBillofquantitiesLimitListVo>> parentMap = listVoList.stream()
|
||||
|
||||
@ -3,11 +3,9 @@ package org.dromara.tender.service.impl;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.cailiaoshebei.controller.constant;
|
||||
import org.dromara.cailiaoshebei.domain.BusCailiaoshebeiPici;
|
||||
import org.dromara.common.core.domain.event.ProcessEvent;
|
||||
import org.dromara.common.core.enums.BusinessStatusEnum;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.service.OssService;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
@ -16,11 +14,9 @@ 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.dromara.formalities.enums.FormalitiesStatusEnum;
|
||||
import org.dromara.system.domain.vo.SysOssUploadVo;
|
||||
import org.dromara.system.domain.vo.SysOssVo;
|
||||
import org.dromara.system.service.ISysOssService;
|
||||
import org.dromara.tender.domain.BusBiddingPlan;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.dromara.tender.domain.bo.TenderSupplierInputBo;
|
||||
@ -35,7 +31,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.dromara.common.constant.MinioPathConstant.ContactNoticeTemplate;
|
||||
import static org.dromara.common.constant.MinioPathConstant.SupplierInput;
|
||||
|
||||
/**
|
||||
@ -222,6 +217,24 @@ public class TenderSupplierInputServiceImpl extends ServiceImpl<TenderSupplierIn
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean importData(List<TenderSupplierInputVo> tenderSupplierInputVos, Long projectId) {
|
||||
List<TenderSupplierInput> tenderSupplierInputs = new ArrayList<>();
|
||||
for (TenderSupplierInputVo tenderSupplierInputVo : tenderSupplierInputVos) {
|
||||
Long count = baseMapper.selectCount(new LambdaQueryWrapper<TenderSupplierInput>().eq(TenderSupplierInput::getSupplierCode, tenderSupplierInputVo.getSupplierCode()));
|
||||
if (count > 0) {
|
||||
continue;
|
||||
}
|
||||
TenderSupplierInput newTenderSupplierInput = new TenderSupplierInput();
|
||||
BeanUtils.copyProperties(tenderSupplierInputVo, newTenderSupplierInput);
|
||||
newTenderSupplierInput.setProjectId(projectId);
|
||||
newTenderSupplierInput.setState("draft");
|
||||
tenderSupplierInputs.add(newTenderSupplierInput);
|
||||
}
|
||||
|
||||
return baseMapper.insertBatch(tenderSupplierInputs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
|
||||
|
||||
@ -17,4 +17,29 @@
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="queryAppPageList" resultType="org.dromara.design.domain.vo.volumefile.DesVolumeFileAppVo">
|
||||
select f.id,
|
||||
f.volume_catalog_id,
|
||||
f.type,
|
||||
f.status,
|
||||
f.audit_status,
|
||||
f.version,
|
||||
f.file_id,
|
||||
c.design_subitem,
|
||||
c.specialty,
|
||||
c.principal,
|
||||
c.document_name,
|
||||
c.volume_number,
|
||||
o.url
|
||||
from des_volume_file f
|
||||
left join des_volume_catalog c on f.volume_catalog_id = c.design
|
||||
left join sys_oss o on f.file_id = o.oss_id
|
||||
where c.project_id = #{dto.projectId}
|
||||
and f.type = #{dto.type}
|
||||
<if test="dto.queryParam != null and dto.queryParam != '' ">
|
||||
and (c.document_name like concat('%',#{dto.queryParam},'%') or c.volume_number like concat('%',#{dto.queryParam},'%'))
|
||||
</if>
|
||||
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user