From f461431bb42fda0f05633996bd9f716c889b0249 Mon Sep 17 00:00:00 2001 From: wangfs <15029758498@163.com> Date: Tue, 2 Dec 2025 21:50:18 +0800 Subject: [PATCH] 巡查计划明细及巡查计划创建优化 --- urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/costfee/CostFeeServiceImpl.java | 1962 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java | 7 +++++++ 2 files changed, 988 insertions(+), 981 deletions(-) diff --git a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/costfee/CostFeeServiceImpl.java b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/costfee/CostFeeServiceImpl.java index ce2a9fb..2746e06 100644 --- a/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/costfee/CostFeeServiceImpl.java +++ b/urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/costfee/CostFeeServiceImpl.java @@ -1,982 +1,982 @@ -package com.zteits.urbanops.module.garden.service.costfee; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.zteits.urbanops.framework.security.core.LoginUser; -import com.zteits.urbanops.module.garden.controller.admin.costfee.CostFeeController; -import com.zteits.urbanops.module.garden.controller.admin.costfee.vo.*; -import com.zteits.urbanops.module.garden.dal.dataobject.departmentcost.DepartmentCostDO; -import com.zteits.urbanops.module.garden.dal.dataobject.mechanicalcost.MechanicalCostDO; -import com.zteits.urbanops.module.garden.dal.dataobject.personalcost.PersonalCostDO; -import com.zteits.urbanops.module.garden.dal.dataobject.rentalmechanicalcost.RentalMechanicalCostDO; -import com.zteits.urbanops.module.garden.dal.dataobject.wasterecord.WasteRecordDO; -import com.zteits.urbanops.module.garden.dal.dataobject.waterfee.WaterFeeDO; -import com.zteits.urbanops.module.garden.dal.mysql.departmentcost.DepartmentCostMapper; -import com.zteits.urbanops.module.garden.dal.mysql.mechanicalcost.MechanicalCostMapper; -import com.zteits.urbanops.module.garden.dal.mysql.personalcost.PersonalCostMapper; -import com.zteits.urbanops.module.garden.dal.mysql.rentalmechanicalcost.RentalMechanicalCostMapper; -import com.zteits.urbanops.module.garden.dal.mysql.wasterecord.WasteRecordMapper; -import com.zteits.urbanops.module.garden.dal.mysql.waterfee.WaterFeeMapper; -import com.zteits.urbanops.module.garden.enums.AssignTasksConstants; -import com.zteits.urbanops.module.garden.enums.CostFeeConstants; -import com.zteits.urbanops.module.garden.enums.TemplateEnum; -import com.zteits.urbanops.module.system.api.dept.DeptApi; -import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO; -import jakarta.annotation.Resource; -import jakarta.validation.ConstraintViolation; -import jakarta.validation.ConstraintViolationException; -import jakarta.validation.Validator; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.BoundHashOperations; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; - -import java.io.IOException; -import java.time.LocalDate; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import static com.zteits.urbanops.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; -import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; -import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception0; -import static com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils.*; -import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.COST_FEE_NOT_EXISTS_001; - -/** - * @Classname CostFeeService - * @Description 模板导入公共实现 - * @Date 2025/7/20 15:12 - * @Created by wangqian - */ -@Service -@Slf4j -public class CostFeeServiceImpl implements CostFeeService { - - // Redis相关配置 - private static final String REDIS_KEY_PREFIX = "excel:import:"; - private static final long EXPIRE_TIME = 30; // 预览数据过期时间:30分钟 - private static final TimeUnit EXPIRE_UNIT = TimeUnit.MINUTES; - @Autowired - private RedisTemplate redisTemplate; - @Autowired - private ObjectMapper objectMapper; - @Resource - private Validator validator; - @Resource - private DeptApi deptApi; - - @Autowired - private WaterFeeMapper waterFeeMapper; - @Autowired - private PersonalCostMapper personalCostMapper; - @Autowired - private DepartmentCostMapper departmentCostMapper; - @Autowired - private MechanicalCostMapper mechanicalCostMapper; - @Autowired - private RentalMechanicalCostMapper rentalMechanicalCostMapper; - @Autowired - private WasteRecordMapper wasteRecordMapper; - - - @Override - /** - * 保存数据到Redis - */ - public String saveDataToRedis(List dataList, String templateName){ - String batchId = UUID.randomUUID().toString().replace("-", ""); - String redisKey = REDIS_KEY_PREFIX + templateName + ":" + batchId; - - // 存储总记录数 - redisTemplate.opsForValue().set( - redisKey + ":total", - String.valueOf(dataList.size()), - EXPIRE_TIME, - EXPIRE_UNIT - ); - - // 使用Hash存储每条数据(key:索引,value:JSON字符串) - BoundHashOperations hashOps = redisTemplate.boundHashOps(redisKey + ":items"); - try { - for (int i = 0; i < dataList.size(); i++) { - String jsonData = objectMapper.writeValueAsString(dataList.get(i)); - hashOps.put(String.valueOf(i), jsonData); - } - } catch (JsonProcessingException e) { - log.error(e.getMessage()); - } - // 设置Hash过期时间 - hashOps.expire(EXPIRE_TIME, EXPIRE_UNIT); - - log.info("数据保存到Redis成功,批次ID:{},记录数:{}", batchId, dataList.size()); - return batchId; - } - - @Override - @Transactional - public int submitImport(String batchId, String templateName, String operator){ - // 模板类型校验 - TemplateEnum template = TemplateEnum.getByCode(templateName); - Class importClass = template.getImportClass(); - if (importClass == null) { - throw exception0(BAD_REQUEST.getCode(),"导入模板配置异常"); - } - - // 分页参数设置 - int pageNum = 1; - final int pageSize = 100000; // 每页处理条数,可根据实际情况调整 - int totalImported = 0; // 总导入数量累计 - - try { - while (true) { - // 分页从Redis获取数据 - CostFeeController.PageResult pageResult = getPagedDataFromRedis( - batchId, templateName, pageNum, pageSize, importClass); - List dataList = pageResult.getData(); - - // 如果当前页无数据,说明已处理完毕 - if (dataList == null || dataList.isEmpty()) { - // 首次分页就无数据,抛出异常 - if (pageNum == 1) { - throw exception0(BAD_REQUEST.getCode(),"没有可导入的数据或数据已过期"); - } - break; - } - - // 业务校验(每页单独校验) - //validateBusinessData(dataList, template); - - // 调用业务服务执行本页数据导入 - int currentPageCount = dataList.size(); - insertData(template, dataList, operator); - totalImported += currentPageCount; - - // 打印分页处理日志(可选) - log.info("批次[{}]第{}页导入完成,本页{}条,累计{}条", - batchId, pageNum, currentPageCount, totalImported); - - // 准备下一页 - pageNum++; - - // 如果当前页数据小于页大小,说明已到最后一页 - if (dataList.size() < pageSize) { - break; - } - } - } catch (IOException e) { - log.error(e.getMessage()); - } finally { - // 无论导入成功与否,都清理Redis临时数据 - deleteRedisTempData(batchId, templateName); - } - - return totalImported; - } - /** - * @Author wangqian - * @Description 保存数据 - * @Date 2025/7/20 11:30 - * @Param template - * @param dataList - * @param operator - * @Return void - */ - private void insertData(TemplateEnum template, List dataList, String operator) { - if (CollectionUtils.isEmpty(dataList)) { - log.info("数据列表为空,跳过插入操作"); - return; - } - //单位集合 - List companyList = deptApi.getSubDeptList(); - // 1. 预加载部门映射(循环外加载,避免重复查询) - List deptIds = companyList.stream().map(DeptRespDTO::getId).collect(Collectors.toList()); - Map nameToCompanyIdMap = CollectionUtils.isEmpty(companyList) ? Map.of() - : companyList.stream() - // 转 Map:key=companyId,value=companyName;key 冲突时保留最后一个(可调整) - .collect(Collectors.toMap( - dept -> dept.getName().trim(), // value 映射:取 companyName(去空格) - DeptRespDTO::getId, // key 映射:取 companyId - (oldValue, newValue) -> newValue - )); - - - // 模板类型校验 - Class importClass = template.getImportClass(); // 从枚举获取导入类,避免switch - // 根据不同模板类型执行不同的处理逻辑 - if (WaterFeeImport.class.isAssignableFrom(importClass)) { - Map companyIdToNamedMap = CollectionUtils.isEmpty(companyList) ? Map.of() - : companyList.stream() - // 转 Map:key=companyId,value=companyName;key 冲突时保留最后一个(可调整) - .collect(Collectors.toMap( - DeptRespDTO::getId, // key 映射:取 companyId - dept -> dept.getName().trim(), // value 映射:取 companyName(去空格) - (oldValue, newValue) -> newValue - )); - - // 处理水费数据 - List feeList = ((List) dataList).stream() - .map(importObj -> { - WaterFeeDO fee = new WaterFeeDO(); - BeanUtils.copyProperties(importObj, fee); - fee.setCompanyId(String.valueOf(getCompanyId())); - if (getCompanyId() == 100) { - fee.setCompanyName("蓟城山水"); - } else { - // 设置单位id - fee.setCompanyName(String.valueOf(companyIdToNamedMap.get(fee.getCompanyId()))); - } - return fee; - }) - .collect(Collectors.toMap( - // 生成唯一键:feeMonth + 分隔符 + meterCode(避免不同组合拼接后重复) - fee -> fee.getFeeMonth() + "_" + fee.getMeterCode(), - // 值为对象本身 - Function.identity(), - // 当键重复时,保留第一个出现的对象(可根据需求改为保留最后一个:(existing, replacement) -> replacement) - (existing, replacement) -> replacement - )) - .values() - .stream() - .collect(Collectors.toList()); - - if (!CollectionUtils.isEmpty(feeList)) { - //查询重复项,进行删除 - List ids = waterFeeMapper.selectDuplicateIds(feeList); - if (!CollectionUtils.isEmpty(ids)) { - waterFeeMapper.deleteByIds(ids); - } - // 调用批量插入方法 - waterFeeMapper.insertBatch(feeList); - } - log.info("成功插入 {} 条水费数据", feeList.size()); - } else if (PersonalCostImport.class.isAssignableFrom(importClass)) { - //去重 - dataList = personalFeeReplacement((List) dataList); - //获取班组对象 - Map teamIdMap = this.getDeptListAll(deptIds); - - // 3. 转换导入数据为PersonalCost列表(Stream优化+空指针防护) - List feeList = (List)dataList; - List saveFeeList = new ArrayList<>(CollectionUtils.isEmpty(feeList) ? 0 : feeList.size()); - if (!CollectionUtils.isEmpty(feeList)) { - for (PersonalCostImport importObj : feeList) { - PersonalCostDO fee = new PersonalCostDO(); - BeanUtils.copyProperties(importObj, fee); - // 设置单位id - fee.setCompanyId(String.valueOf(nameToCompanyIdMap.get(fee.getCompanyName()))); - //设置班组id - fee.setDeptId(getDeptList(teamIdMap, importObj.getTeamIds())); - saveFeeList.add(fee); - } - } - // 4. 处理重复数据(删除+插入原子性) - if (!feeList.isEmpty()) { - // 4.1 查询并删除重复项 - -// List duplicateIds = personalCostMapper.selectDuplicateIds(saveFeeList); -// if (!duplicateIds.isEmpty()) { -// personalCostMapper.deleteByIds(duplicateIds); +//package com.zteits.urbanops.module.garden.service.costfee; +// +//import com.fasterxml.jackson.core.JsonProcessingException; +//import com.fasterxml.jackson.databind.ObjectMapper; +//import com.zteits.urbanops.framework.security.core.LoginUser; +//import com.zteits.urbanops.module.garden.controller.admin.costfee.CostFeeController; +//import com.zteits.urbanops.module.garden.controller.admin.costfee.vo.*; +//import com.zteits.urbanops.module.garden.dal.dataobject.departmentcost.DepartmentCostDO; +//import com.zteits.urbanops.module.garden.dal.dataobject.mechanicalcost.MechanicalCostDO; +//import com.zteits.urbanops.module.garden.dal.dataobject.personalcost.PersonalCostDO; +//import com.zteits.urbanops.module.garden.dal.dataobject.rentalmechanicalcost.RentalMechanicalCostDO; +//import com.zteits.urbanops.module.garden.dal.dataobject.wasterecord.WasteRecordDO; +//import com.zteits.urbanops.module.garden.dal.dataobject.waterfee.WaterFeeDO; +//import com.zteits.urbanops.module.garden.dal.mysql.departmentcost.DepartmentCostMapper; +//import com.zteits.urbanops.module.garden.dal.mysql.mechanicalcost.MechanicalCostMapper; +//import com.zteits.urbanops.module.garden.dal.mysql.personalcost.PersonalCostMapper; +//import com.zteits.urbanops.module.garden.dal.mysql.rentalmechanicalcost.RentalMechanicalCostMapper; +//import com.zteits.urbanops.module.garden.dal.mysql.wasterecord.WasteRecordMapper; +//import com.zteits.urbanops.module.garden.dal.mysql.waterfee.WaterFeeMapper; +//import com.zteits.urbanops.module.garden.enums.AssignTasksConstants; +//import com.zteits.urbanops.module.garden.enums.CostFeeConstants; +//import com.zteits.urbanops.module.garden.enums.TemplateEnum; +//import com.zteits.urbanops.module.system.api.dept.DeptApi; +//import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO; +//import jakarta.annotation.Resource; +//import jakarta.validation.ConstraintViolation; +//import jakarta.validation.ConstraintViolationException; +//import jakarta.validation.Validator; +//import lombok.extern.slf4j.Slf4j; +//import org.apache.commons.lang3.StringUtils; +//import org.springframework.beans.BeanUtils; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.data.redis.core.BoundHashOperations; +//import org.springframework.data.redis.core.RedisTemplate; +//import org.springframework.stereotype.Service; +//import org.springframework.transaction.annotation.Transactional; +//import org.springframework.util.CollectionUtils; +// +//import java.io.IOException; +//import java.time.LocalDate; +//import java.util.*; +//import java.util.concurrent.TimeUnit; +//import java.util.function.Function; +//import java.util.stream.Collectors; +//import java.util.stream.IntStream; +// +//import static com.zteits.urbanops.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +//import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; +//import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception0; +//import static com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils.*; +//import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.COST_FEE_NOT_EXISTS_001; +// +///** +// * @Classname CostFeeService +// * @Description 模板导入公共实现 +// * @Date 2025/7/20 15:12 +// * @Created by wangqian +// */ +//@Service +//@Slf4j +//public class CostFeeServiceImpl implements CostFeeService { +// +// // Redis相关配置 +// private static final String REDIS_KEY_PREFIX = "excel:import:"; +// private static final long EXPIRE_TIME = 30; // 预览数据过期时间:30分钟 +// private static final TimeUnit EXPIRE_UNIT = TimeUnit.MINUTES; +// @Autowired +// private RedisTemplate redisTemplate; +// @Autowired +// private ObjectMapper objectMapper; +// @Resource +// private Validator validator; +// @Resource +// private DeptApi deptApi; +// +// @Autowired +// private WaterFeeMapper waterFeeMapper; +// @Autowired +// private PersonalCostMapper personalCostMapper; +// @Autowired +// private DepartmentCostMapper departmentCostMapper; +// @Autowired +// private MechanicalCostMapper mechanicalCostMapper; +// @Autowired +// private RentalMechanicalCostMapper rentalMechanicalCostMapper; +// @Autowired +// private WasteRecordMapper wasteRecordMapper; +// +// +// @Override +// /** +// * 保存数据到Redis +// */ +// public String saveDataToRedis(List dataList, String templateName){ +// String batchId = UUID.randomUUID().toString().replace("-", ""); +// String redisKey = REDIS_KEY_PREFIX + templateName + ":" + batchId; +// +// // 存储总记录数 +// redisTemplate.opsForValue().set( +// redisKey + ":total", +// String.valueOf(dataList.size()), +// EXPIRE_TIME, +// EXPIRE_UNIT +// ); +// +// // 使用Hash存储每条数据(key:索引,value:JSON字符串) +// BoundHashOperations hashOps = redisTemplate.boundHashOps(redisKey + ":items"); +// try { +// for (int i = 0; i < dataList.size(); i++) { +// String jsonData = objectMapper.writeValueAsString(dataList.get(i)); +// hashOps.put(String.valueOf(i), jsonData); +// } +// } catch (JsonProcessingException e) { +// log.error(e.getMessage()); +// } +// // 设置Hash过期时间 +// hashOps.expire(EXPIRE_TIME, EXPIRE_UNIT); +// +// log.info("数据保存到Redis成功,批次ID:{},记录数:{}", batchId, dataList.size()); +// return batchId; +// } +// +// @Override +// @Transactional +// public int submitImport(String batchId, String templateName, String operator){ +// // 模板类型校验 +// TemplateEnum template = TemplateEnum.getByCode(templateName); +// Class importClass = template.getImportClass(); +// if (importClass == null) { +// throw exception0(BAD_REQUEST.getCode(),"导入模板配置异常"); +// } +// +// // 分页参数设置 +// int pageNum = 1; +// final int pageSize = 100000; // 每页处理条数,可根据实际情况调整 +// int totalImported = 0; // 总导入数量累计 +// +// try { +// while (true) { +// // 分页从Redis获取数据 +// CostFeeController.PageResult pageResult = getPagedDataFromRedis( +// batchId, templateName, pageNum, pageSize, importClass); +// List dataList = pageResult.getData(); +// +// // 如果当前页无数据,说明已处理完毕 +// if (dataList == null || dataList.isEmpty()) { +// // 首次分页就无数据,抛出异常 +// if (pageNum == 1) { +// throw exception0(BAD_REQUEST.getCode(),"没有可导入的数据或数据已过期"); +// } +// break; // } - - // 4.2 批量插入主表 - personalCostMapper.insertBatch(saveFeeList); - } - log.info("成功插入 {} 人员费用数据", dataList.size()); - } else if (DepartmentCostImport.class.isAssignableFrom(importClass)) { - //去重 - dataList = deptFeeReplacement((List)dataList); - List feeList = ((List) dataList).stream() - .map(importObj -> { - DepartmentCostDO fee = new DepartmentCostDO(); - BeanUtils.copyProperties(importObj, fee); - // 设置单位id - fee.setCompanyId(String.valueOf(nameToCompanyIdMap.get(fee.getCompanyName()))); - return fee; - }) - .collect(Collectors.toList()); - if (!CollectionUtils.isEmpty(feeList)) { - //查询重复项,进行删除 - List ids = departmentCostMapper.selectDuplicateIds(feeList); - if (!CollectionUtils.isEmpty(ids)) { - departmentCostMapper.deleteByIds(ids); - } - // 调用批量插入方法 - departmentCostMapper.insertBatch(feeList); - } - log.info("成功插入 {} 综合费用数据", feeList.size()); - } else if (MechanicalCostImport.class.isAssignableFrom(importClass)) { - List feeList = (List) dataList; - List saveFeeList = new ArrayList<>(CollectionUtils.isEmpty(feeList) ? 0 : feeList.size()); - if (!CollectionUtils.isEmpty(feeList)) { - //获取班组对象 - Map teamIdMap = this.getDeptListAll(deptIds); - for (MechanicalCostImport importObj : feeList) { - MechanicalCostDO fee = new MechanicalCostDO(); - BeanUtils.copyProperties(importObj, fee); - // 设置单位id - fee.setCompanyId(String.valueOf(nameToCompanyIdMap.get(fee.getCompanyName()))); - //设置班组id - fee.setDeptId(getDeptList(teamIdMap, importObj.getTeamIds())); - // 3.3 计算结束时间(空指针防护) - Optional.ofNullable(fee.getStartUseTime()) - .ifPresent(startTime -> { - int useDuration = Optional.ofNullable(fee.getServiceLife()) - .map(Math::toIntExact) // 处理可能的溢出 - .orElse(0); - fee.setEndUseTime(this.getEndLocalDateForYears(startTime, useDuration)); - }); - - saveFeeList.add(fee); - } - } - // 4. 批量插入主表(空集合直接跳过) - if (!feeList.isEmpty()) { - //查询重复项,进行删除 - List ids = mechanicalCostMapper.selectDuplicateIds(saveFeeList); - if (!CollectionUtils.isEmpty(ids)) { - mechanicalCostMapper.deleteByIds(ids); - } - mechanicalCostMapper.insertBatch(saveFeeList); - } - log.info("成功插入 {} 自有机械费用数据", dataList.size()); - } else if (RentalMechanicalCostImport.class.isAssignableFrom(importClass)) { - List feeList = (List)dataList; - List saveFeeList = new ArrayList<>(CollectionUtils.isEmpty(feeList) ? 0 : feeList.size()); - if (!CollectionUtils.isEmpty(feeList)) { - //获取班组对象 - Map teamIdMap = this.getDeptListAll(deptIds); - for (RentalMechanicalCostImport importObj : feeList) { - RentalMechanicalCostDO fee = new RentalMechanicalCostDO(); - BeanUtils.copyProperties(importObj, fee); - // 设置单位id - fee.setCompanyId(String.valueOf(nameToCompanyIdMap.get(fee.getCompanyName()))); - //设置班组id - List teamRels = new ArrayList<>(); - String teamIdsStr = StringUtils.defaultString(importObj.getTeamIds()).replace(",", ","); - String weightsStr = StringUtils.defaultString(importObj.getWeight()).replace(",", ","); - - String[] teamIds = teamIdsStr.split(","); - String[] weights = weightsStr.split(","); - for (int i = 0; i < teamIds.length; i++) { - TeamBizdomainRelVo rel = new TeamBizdomainRelVo(); - rel.setTeamName(teamIds[i].trim()); - // 提前处理部门ID映射(复用deptMap) - rel.setTeamId(Optional.ofNullable(teamIdMap.get(teamIds[i].trim())).map(String::valueOf).orElse(null)); - rel.setWeight(Long.valueOf(weights[i].trim())); - teamRels.add(rel); - } - fee.setTeamIds(teamRels); - - // 3.3 计算结束时间(空指针防护) - Optional.ofNullable(fee.getStartUseTime()) - .ifPresent(startTime -> { - int useDuration = Optional.ofNullable(fee.getUseDuration()) - .map(Math::toIntExact) // 处理可能的溢出 - .orElse(0); - fee.setEndUseTime(getEndLocalDateForYears(startTime, useDuration)); - }); - - saveFeeList.add(fee); - } - } - if (!feeList.isEmpty()) { - rentalMechanicalCostMapper.insertBatch(saveFeeList); - } - log.info("成功插入 {} 租赁机械费用数据", dataList.size()); - } else if (GardenWasteRecordImport.class.isAssignableFrom(importClass)) { - //获取班组对象 - List feeList = (List)dataList; - List saveFeeList = new ArrayList<>(CollectionUtils.isEmpty(feeList) ? 0 : feeList.size()); - if (!CollectionUtils.isEmpty(feeList)) { - Map teamIdMap = this.getDeptListAll(deptIds); - for (GardenWasteRecordImport importObj : feeList) { - WasteRecordDO fee = new WasteRecordDO(); - BeanUtils.copyProperties(importObj, fee); - // 设置单位id - fee.setCompanyId(String.valueOf(nameToCompanyIdMap.get(fee.getCompanyName()))); - //设置班组id - fee.setDeptId(getDeptList(teamIdMap, importObj.getTeamIds())); - - saveFeeList.add(fee); - } - } - // 4. 批量插入主表(若主表插入失败,事务回滚) - if (!feeList.isEmpty()) { - wasteRecordMapper.insertBatch(saveFeeList); - } - - log.info("成功插入 {} 园林废弃物费用数据", dataList.size()); - } - - } - - /** - * 从Redis获取分页数据 - */ - @Override - public CostFeeController.PageResult < T > getPagedDataFromRedis(String batchId, String templateName, - int page, int size, Class clazz) throws IOException { - String redisKey = REDIS_KEY_PREFIX + templateName + ":" + batchId; - - // 获取总记录数 - String totalStr = redisTemplate.opsForValue().get(redisKey + ":total"); - int total = totalStr != null ? Integer.parseInt(totalStr) : 0; - - // 计算分页范围 - int start = (page - 1) * size; - int end = Math.min(start + size - 1, total - 1); - - // 分页查询数据 - List pageData = new ArrayList<>(); - if (start <= end && total > 0) { - BoundHashOperations hashOps = redisTemplate.boundHashOps(redisKey + ":items"); - - // 批量获取指定范围的索引对应的数据 - List indexes = IntStream.rangeClosed(start, end) - .mapToObj(String::valueOf) - .collect(Collectors.toList()); - List jsonList = hashOps.multiGet(indexes); - - // 反序列化为对象 - for (String json : jsonList) { - if (json != null) { - pageData.add(objectMapper.readValue(json, clazz)); - } - } - } - - return new CostFeeController.PageResult<>(page, size, total, pageData); - } - - - /** - * 从Redis获取全部数据 - */ - private List < T > getAllDataFromRedis(String batchId, String templateName, Class < T > clazz) throws - IOException { - String redisKey = REDIS_KEY_PREFIX + templateName + ":" + batchId; - BoundHashOperations hashOps = redisTemplate.boundHashOps(redisKey + ":items"); - - // 获取所有数据的JSON字符串 - List jsonList = hashOps.values(); - List dataList = new ArrayList<>(jsonList.size()); - - // 反序列化为对象 - for (String json : jsonList) { - if (json != null) { - dataList.add(objectMapper.readValue(json, clazz)); - } - } - - return dataList; - } - - - /** - * 删除Redis临时数据 - */ - private void deleteRedisTempData (String batchId, String templateName){ - String redisKey = REDIS_KEY_PREFIX + templateName + ":" + batchId; - redisTemplate.delete(redisKey + ":total"); - redisTemplate.delete(redisKey + ":items"); - log.info("Redis临时数据已删除,批次ID:{}", batchId); - } - /** - * @Author wangqian - * @Description 导入内容校验 - * @Date 2025/11/24 8:40 - * @Param dataList - * @param template - * @Return void - */ - public void validateImportData(List dataList, TemplateEnum template) { - if (CollectionUtils.isEmpty(dataList)) { - return; // 空列表无需校验 - } - //登录用户单位 - Long belongCompanyId = getCompanyId(); - //单位集合 - List companyList = deptApi.getSubDeptList(); - List deptIds = companyList.stream().map(DeptRespDTO::getId).collect(Collectors.toList()); - Map nameToCompanyIdMap = CollectionUtils.isEmpty(companyList) - ? Map.of() // 空列表返回空不可变 Map(避免 null) - : companyList.stream() - // 转 Map:key=companyId,value=companyName;key 冲突时保留最后一个(可调整) - .collect(Collectors.toMap( - dept -> dept.getName().trim(), // value 映射:取 companyName(去空格) - DeptRespDTO::getId, // key 映射:取 companyId - (oldValue, newValue) -> newValue - )); - //班组集合 - Map> deptList = this.getDetpList(deptIds); - // 模板类型校验 - Class importClass = template.getImportClass(); // 从枚举获取导入类,避免switch - // 根据不同模板类型执行不同的处理逻辑 - if (WaterFeeImport.class.isAssignableFrom(importClass)) { - - List importList = (List) dataList; - - // 2. 遍历,逐个创建 - for (int i = 0; i < importList.size(); i++) { - int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) - WaterFeeImport importBean = importList.get(i); - - try { - // 2.1 执行校验(替换原 ValidationUtils,直接用 Validator 校验,确保抛出 ConstraintViolationException) - Set> violations = validator.validate(importBean); - if (!violations.isEmpty()) { - // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) - // StringBuilder errorMsg = new StringBuilder(); - for (ConstraintViolation violation : violations) { - //errorMsg.append(violation.getMessage()).append(";"); - throw exception0(BAD_REQUEST.getCode() ,String.format( - "第[{}]条数据:"+ violation.getMessage() - ), rowNum); - } - // 抛出包含行号和所有错误的异常 - //throw exception0(BAD_REQUEST.getCode(), errorMsg.toString().trim(), violations); - } - - } catch (ConstraintViolationException ex) { - // 5. 包装异常,明确行号 + 真实校验错误( - throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); - } - } - } - else if (PersonalCostImport.class.isAssignableFrom(importClass)) { - - List importList = (List) dataList; - // 2. 遍历,逐个创建 - for (int i = 0; i < importList.size(); i++) { - int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) - PersonalCostImport importBean = importList.get(i); - - try { - // 2.1 执行校验(替换原 ValidationUtils,直接用 Validator 校验,确保抛出 ConstraintViolationException) - Set> violations = validator.validate(importBean); - if (!violations.isEmpty()) { - // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) - //StringBuilder errorMsg = new StringBuilder(); - for (ConstraintViolation violation : violations) { - // errorMsg.append(violation.getMessage()).append(";"); - throw exception0(BAD_REQUEST.getCode() ,String.format( - "第[{}]条数据:"+ violation.getMessage() - ), rowNum); - } - // 抛出包含行号和所有错误的异常 - // throw exception0(BAD_REQUEST.getCode(), errorMsg.toString().trim(), violations); - } - Long companyId = nameToCompanyIdMap.get(importBean.getCompanyName()); - //单位校验 - validatecompany(rowNum, importBean.getCompanyName(), companyId, belongCompanyId); - //部门名称校验 - validateTeams(rowNum, deptList.get(companyId), importBean.getTeamIds()); - - } catch (ConstraintViolationException ex) { - // 5. 包装异常,明确行号 + 真实校验错误( - throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); - } - } - } - else if (GardenWasteRecordImport.class.isAssignableFrom(importClass)) { - - List importList = (List) dataList; - // 2. 遍历,逐个创建 - for (int i = 0; i < importList.size(); i++) { - int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) - GardenWasteRecordImport importBean = importList.get(i); - - try { - // 2.1 执行校验(替换原 ValidationUtils,直接用 Validator 校验,确保抛出 ConstraintViolationException) - Set> violations = validator.validate(importBean); - if (!violations.isEmpty()) { - // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) - //StringBuilder errorMsg = new StringBuilder(); - for (ConstraintViolation violation : violations) { - //errorMsg.append(violation.getMessage()).append(";"); - throw exception0(BAD_REQUEST.getCode() ,String.format( - "第[{}]条数据:"+ violation.getMessage() - ), rowNum); - } - // 抛出包含行号和所有错误的异常 - //throw exception0(BAD_REQUEST.getCode(), errorMsg.toString().trim(), violations); - } - Long companyId = nameToCompanyIdMap.get(importBean.getCompanyName()); - //单位校验 - validatecompany(rowNum, importBean.getCompanyName(), companyId, belongCompanyId); - //部门名称校验 - validateTeams(rowNum, deptList.get(companyId), importBean.getTeamIds()); - - } catch (ConstraintViolationException ex) { - throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); - } - } - } - else if (MechanicalCostImport.class.isAssignableFrom(importClass)) { - - List importList = (List) dataList; - // 2. 遍历,逐个创建 - for (int i = 0; i < importList.size(); i++) { - int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) - MechanicalCostImport importBean = importList.get(i); - - try { - // 2.1 执行校验(替换原 ValidationUtils,直接用 Validator 校验,确保抛出 ConstraintViolationException) - Set> violations = validator.validate(importBean); - if (!violations.isEmpty()) { - // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) - //StringBuilder errorMsg = new StringBuilder(); - for (ConstraintViolation violation : violations) { - //errorMsg.append(violation.getMessage()).append(";"); - throw exception0(BAD_REQUEST.getCode() ,String.format( - "第[{}]条数据:"+ violation.getMessage() - ), rowNum); - } - // 抛出包含行号和所有错误的异常 - //throw new ConstraintViolationException(errorMsg.toString().trim(), violations); - } - Long companyId = nameToCompanyIdMap.get(importBean.getCompanyName()); - //单位校验 - validatecompany(rowNum, importBean.getCompanyName(), companyId, belongCompanyId); - //部门名称校验 - validateTeams(rowNum, deptList.get(companyId), importBean.getTeamIds()); - - //车辆校验 - if (CostFeeConstants.MECH_TYPE.equals(importBean.getMechType())) { - if (StringUtils.isEmpty(importBean.getLicensePlate())) { - throw exception0(BAD_REQUEST.getCode() ,String.format( - "第[{}]条数据:车牌号不能为空" - ), rowNum); - } - if (StringUtils.isEmpty(importBean.getVehicleType())) { - throw exception0(BAD_REQUEST.getCode() ,String.format( - "第[{}]条数据:车辆类型不能为空" - ), rowNum); - - } - if (StringUtils.isEmpty(importBean.getVehicleCategory())) { - throw exception0(BAD_REQUEST.getCode() ,String.format( - "第%d条数据:车辆类别不能为空" - ), rowNum); - } - } - - } catch (ConstraintViolationException ex) { - // 5. 包装异常,明确行号 + 真实校验错误( - throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); - } - } - } - else if (RentalMechanicalCostImport.class.isAssignableFrom(importClass)) { - - List importList = (List) dataList; - // 2. 遍历,逐个创建 - for (int i = 0; i < importList.size(); i++) { - int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) - RentalMechanicalCostImport importBean = importList.get(i); - - try { - // 2.1 执行校验(替换原 ValidationUtils,直接用 Validator 校验,确保抛出 ConstraintViolationException) - Set> violations = validator.validate(importBean); - if (!violations.isEmpty()) { - // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) - // StringBuilder errorMsg = new StringBuilder(); - for (ConstraintViolation violation : violations) { - // errorMsg.append(violation.getMessage()).append(";"); - throw exception0(BAD_REQUEST.getCode() ,String.format( - "第[{}]条数据:"+violation.getMessage() - ), rowNum); - } - // 抛出包含行号和所有错误的异常 - //throw new ConstraintViolationException(errorMsg.toString().trim(), violations); - } - // 处理可能的空值 - String teamIdsStr = StringUtils.defaultString(importBean.getTeamIds()); - String weightsStr = StringUtils.defaultString(importBean.getWeight()); - - // 统一替换中文逗号并分割 - String[] teamIds = teamIdsStr.replace(",", ",").split(","); - String[] weights = weightsStr.replace(",", ",").split(","); - - // 校验数组长度是否一致 - if (teamIds.length != weights.length) { - throw exception0(BAD_REQUEST.getCode(), String.format( - "第%d条数据:权重值和所选班组数量不符(班组:%d个,权重:%d个)", - rowNum, teamIds.length, weights.length - )); - } - Long companyId = nameToCompanyIdMap.get(importBean.getCompanyName()); - //单位校验 - validatecompany(rowNum, importBean.getCompanyName(), companyId, belongCompanyId); - //部门名称校验 - validateTeams(rowNum, deptList.get(companyId), importBean.getTeamIds()); - - } catch (ConstraintViolationException ex) { - // 5. 包装异常,明确行号 + 真实校验错误( - throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); - } - } - } - else if (DepartmentCostImport.class.isAssignableFrom(importClass)) { - - List importList = (List) dataList; - // 2. 遍历,逐个创建 - for (int i = 0; i < importList.size(); i++) { - int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) - DepartmentCostImport importBean = importList.get(i); - - try { - // 2.1 执行校验(替换原 ValidationUtils,直接用 Validator 校验,确保抛出 ConstraintViolationException) - Set> violations = validator.validate(importBean); - if (!violations.isEmpty()) { - // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) - //StringBuilder errorMsg = new StringBuilder(); - for (ConstraintViolation violation : violations) { - //errorMsg.append(violation.getMessage()).append(";"); - throw exception0(BAD_REQUEST.getCode() ,String.format( - "第[{}]条数据:"+violation.getMessage() - ), rowNum); - } - // 抛出包含行号和所有错误的异常 - //throw new ConstraintViolationException(errorMsg.toString().trim(), violations); - } - - Long companyId = nameToCompanyIdMap.get(importBean.getCompanyName()); - //单位校验 - validatecompany(rowNum, importBean.getCompanyName(), companyId, belongCompanyId); - } catch (ConstraintViolationException ex) { - // 5. 包装异常,明确行号 + 真实校验错误( - throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); - } - } - } - } - - private void validatecompany(int rowNum, String companyName, Long companyId, Long belongCompanyId){ - // 校验数组长度是否一致 - if (companyId == null) { - throw exception0(BAD_REQUEST.getCode(), String.format( - "第%d条数据:单位名称不正确(%s)", - rowNum, companyName - )); - } - // 校验导入单位 - if (belongCompanyId != 100 && !belongCompanyId.equals(companyId)) { - throw exception0(BAD_REQUEST.getCode(), String.format( - "第%d条数据:导入单位%s与当前操作员单位不一致", - rowNum, companyName - )); - } - } - private void validateTeams(int rowNum, List dept, String teamIds) { - if (StringUtils.isNotEmpty(teamIds)) { - String[] teamNames = teamIds.split(","); - Set checkedTeams = new HashSet<>(); // 用于存储已校验的团队名称,检测重复 - - for (String teamName : teamNames) { - String trimmedTeamName = teamName.trim(); // 处理前后空格 - - // 重复校验:如果Set中已存在该团队名称,说明重复 - if (checkedTeams.contains(trimmedTeamName)) { - throw exception0(BAD_REQUEST.getCode(), String.format( - "第%d条数据:%s名称重复", - rowNum, teamName - )); - } - - // 存在性校验:检查团队是否在dept中存在 - if (!dept.contains(trimmedTeamName)) { - throw exception0(BAD_REQUEST.getCode(), String.format( - "第%d条数据:%s名称不正确", - rowNum, teamName - )); - } - - // 将校验通过的团队名称加入Set,用于后续重复判断 - checkedTeams.add(trimmedTeamName); - } - } - } - - //查询单位下的班组信息 - private Map> getDetpList (List deptIds) { - Map> listMap = new HashMap<>(); - for (Long depId : deptIds) { - List deptList = deptApi.getChildDeptList(depId); - List names = deptList.stream().map(DeptRespDTO::getName).collect(Collectors.toList()); - listMap.put(depId,names); - } - return listMap; - } - - /** - * 按salaryMonth、expenseName、companyId三个字段去重 - * @param costList 原始部门成本列表 - * @return 去重后的列表 - */ - public List deptFeeReplacement(List costList) { - if (costList == null || costList.isEmpty()) { - return new ArrayList<>(); - } - - // 1. 以三个字段的组合作为键(使用分隔符避免不同组合产生相同键) - // 2. 遇到重复键时保留第一条记录 - Map uniqueMap = costList.stream() - .collect(Collectors.toMap( - // 生成唯一键:salaryMonth|expenseName|companyId - cost -> buildUniqueKey(cost), - // 键不存在时存入当前对象 - cost -> cost, - // 键已存在时保留最后一个 - (existing, replacement) -> replacement - )); - - // 将去重后的结果转为List返回 - return new ArrayList<>(uniqueMap.values()); - } - - /** - * 构建三个字段的唯一组合键(处理null值) - */ - private String buildUniqueKey(DepartmentCostImport cost) { - // 使用Objects.toString处理可能的null值,避免NullPointerException - return Objects.toString(cost.getSalaryMonth(), "") + "|" + - Objects.toString(cost.getExpenseName(), "") + "|" + - Objects.toString(cost.getCompanyName(), ""); - } - - /** - * 按salaryMonth、name、companyId、teamIdList四个字段去重 - * @param costList 原始个人成本列表 - * @return 去重后的列表 - */ - public List personalFeeReplacement(List costList) { - if (costList == null || costList.isEmpty()) { - return new ArrayList<>(); - } - - // 1. 以四个字段的组合作为键(特别处理集合类型的teamIdList) - // 2. 遇到重复键时保留第一条记录 - Map uniqueMap = costList.stream() - .collect(Collectors.toMap( - // 生成唯一键:salaryMonth|name|companyId|teamIdListStr - this::buildUniqueKey, - // 键不存在时存入当前对象 - cost -> cost, - // 键已存在时保留第一个对象(可改为replacement保留最后一个) - (existing, replacement) -> replacement - )); - - // 将去重后的结果转为List返回 - return new ArrayList<>(uniqueMap.values()); - } - - /** - * 构建四个字段的唯一组合键(处理null值和集合类型) - */ - private String buildUniqueKey(PersonalCostImport cost) { - // 处理普通字段的null值 - String salaryMonth = Objects.toString(cost.getSalaryMonth(), ""); - String name = Objects.toString(cost.getName(), ""); - String companyId = Objects.toString(cost.getCompanyName(), ""); - String teamIds = Objects.toString(cost.getTeamIds(), ""); - // 拼接唯一键 - return salaryMonth + "|" + name + "|" + companyId + "|" + teamIds; - } - - - public static LocalDate getEndLocalDateForYears(LocalDate startDate, int years) { - if (startDate == null) { - throw new IllegalArgumentException("开始日期不能为null"); - } - if (years < 0) { - throw new IllegalArgumentException("年数不能为负数"); - } - return startDate.plusYears(years); - } - - /** - * @Author wangqian - * @Description 根据班组名称获取班组id - * @Date 2025/11/26 19:38 - */ - /** - * 根据部门ID列表获取「部门名称→部门ID」的映射(含空值防护) - */ - private Map getDeptListAll(List deptIds) { - Map deptNameMap = new HashMap<>(); - - // 1. 空值安全:避免 deptIds 为 null/空列表导致 NPE - if (CollectionUtils.isEmpty(deptIds)) { - return deptNameMap; - } - - for (Long deptId : deptIds) { - // 2. 跳过 null 的部门ID - if (deptId == null) { - continue; - } - - // 3. 获取子部门列表(防护接口返回 null) - List deptList = deptApi.getChildDeptList(deptId); - if (CollectionUtils.isEmpty(deptList)) { - continue; - } - - // 4. 遍历子部门:过滤无效名称,避免 Map 出现 null/空字符串键 - for (DeptRespDTO dept : deptList) { - if (dept == null) { - continue; - } - String deptName = dept.getName(); - // 过滤 null/空白名称(避免 Map 键为 null 或空字符串) - if (deptName == null || deptName.trim().isEmpty()) { - continue; - } - // 若名称重复,后遍历的部门会覆盖先遍历的(可根据业务调整规则) - deptNameMap.put(deptName.trim(), dept.getId()); - } - } - - return deptNameMap; - } - /** - * @Author wangqian - * @Description 根据班组名称获取班组id集合 - * @Date 2025/11/26 20:07 - */ - private List getDeptList(Map teamIdMap, String teamId) { - List list = new ArrayList<>(); - - // 1. 处理 teamId 为空的情况,直接返回空列表 - if (StringUtils.isEmpty(teamId)) { - return list; - } - - // 2. 分割字符串,处理空元素 - String[] teamArray = teamId.split(","); - for (String teamName : teamArray) { - // 3. 去除首尾空格,避免因空格导致匹配不到 - String trimTeamName = teamName.trim(); - if (StringUtils.isEmpty(trimTeamName)) { - continue; // 跳过空字符串元素 - } - - // 4. 从Map中获取ID,处理null值(避免添加null到列表) - Long deptId = teamIdMap.get(trimTeamName); - if (deptId != null) { - list.add(String.valueOf(deptId)); // 直接添加Long类型,修正原String类型错误 - } - } - - return list; - } -} +// +// // 业务校验(每页单独校验) +// //validateBusinessData(dataList, template); +// +// // 调用业务服务执行本页数据导入 +// int currentPageCount = dataList.size(); +// insertData(template, dataList, operator); +// totalImported += currentPageCount; +// +// // 打印分页处理日志(可选) +// log.info("批次[{}]第{}页导入完成,本页{}条,累计{}条", +// batchId, pageNum, currentPageCount, totalImported); +// +// // 准备下一页 +// pageNum++; +// +// // 如果当前页数据小于页大小,说明已到最后一页 +// if (dataList.size() < pageSize) { +// break; +// } +// } +// } catch (IOException e) { +// log.error(e.getMessage()); +// } finally { +// // 无论导入成功与否,都清理Redis临时数据 +// deleteRedisTempData(batchId, templateName); +// } +// +// return totalImported; +// } +// /** +// * @Author wangqian +// * @Description 保存数据 +// * @Date 2025/7/20 11:30 +// * @Param template +// * @param dataList +// * @param operator +// * @Return void +// */ +// private void insertData(TemplateEnum template, List dataList, String operator) { +// if (CollectionUtils.isEmpty(dataList)) { +// log.info("数据列表为空,跳过插入操作"); +// return; +// } +// //单位集合 +// List companyList = deptApi.getSubDeptList(); +// // 1. 预加载部门映射(循环外加载,避免重复查询) +// List deptIds = companyList.stream().map(DeptRespDTO::getId).collect(Collectors.toList()); +// Map nameToCompanyIdMap = CollectionUtils.isEmpty(companyList) ? Map.of() +// : companyList.stream() +// // 转 Map:key=companyId,value=companyName;key 冲突时保留最后一个(可调整) +// .collect(Collectors.toMap( +// dept -> dept.getName().trim(), // value 映射:取 companyName(去空格) +// DeptRespDTO::getId, // key 映射:取 companyId +// (oldValue, newValue) -> newValue +// )); +// +// +// // 模板类型校验 +// Class importClass = template.getImportClass(); // 从枚举获取导入类,避免switch +// // 根据不同模板类型执行不同的处理逻辑 +// if (WaterFeeImport.class.isAssignableFrom(importClass)) { +// Map companyIdToNamedMap = CollectionUtils.isEmpty(companyList) ? Map.of() +// : companyList.stream() +// // 转 Map:key=companyId,value=companyName;key 冲突时保留最后一个(可调整) +// .collect(Collectors.toMap( +// DeptRespDTO::getId, // key 映射:取 companyId +// dept -> dept.getName().trim(), // value 映射:取 companyName(去空格) +// (oldValue, newValue) -> newValue +// )); +// +// // 处理水费数据 +// List feeList = ((List) dataList).stream() +// .map(importObj -> { +// WaterFeeDO fee = new WaterFeeDO(); +// BeanUtils.copyProperties(importObj, fee); +// fee.setCompanyId(String.valueOf(getCompanyId())); +// if (getCompanyId() == 100) { +// fee.setCompanyName("蓟城山水"); +// } else { +// // 设置单位id +// fee.setCompanyName(String.valueOf(companyIdToNamedMap.get(fee.getCompanyId()))); +// } +// return fee; +// }) +// .collect(Collectors.toMap( +// // 生成唯一键:feeMonth + 分隔符 + meterCode(避免不同组合拼接后重复) +// fee -> fee.getFeeMonth() + "_" + fee.getMeterCode(), +// // 值为对象本身 +// Function.identity(), +// // 当键重复时,保留第一个出现的对象(可根据需求改为保留最后一个:(existing, replacement) -> replacement) +// (existing, replacement) -> replacement +// )) +// .values() +// .stream() +// .collect(Collectors.toList()); +// +// if (!CollectionUtils.isEmpty(feeList)) { +// //查询重复项,进行删除 +// List ids = waterFeeMapper.selectDuplicateIds(feeList); +// if (!CollectionUtils.isEmpty(ids)) { +// waterFeeMapper.deleteByIds(ids); +// } +// // 调用批量插入方法 +// waterFeeMapper.insertBatch(feeList); +// } +// log.info("成功插入 {} 条水费数据", feeList.size()); +// } else if (PersonalCostImport.class.isAssignableFrom(importClass)) { +// //去重 +// dataList = personalFeeReplacement((List) dataList); +// //获取班组对象 +// Map teamIdMap = this.getDeptListAll(deptIds); +// +// // 3. 转换导入数据为PersonalCost列表(Stream优化+空指针防护) +// List feeList = (List)dataList; +// List saveFeeList = new ArrayList<>(CollectionUtils.isEmpty(feeList) ? 0 : feeList.size()); +// if (!CollectionUtils.isEmpty(feeList)) { +// for (PersonalCostImport importObj : feeList) { +// PersonalCostDO fee = new PersonalCostDO(); +// BeanUtils.copyProperties(importObj, fee); +// // 设置单位id +// fee.setCompanyId(String.valueOf(nameToCompanyIdMap.get(fee.getCompanyName()))); +// //设置班组id +// //fee.setDeptId(getDeptList(teamIdMap, importObj.getTeamIds())); +// saveFeeList.add(fee); +// } +// } +// // 4. 处理重复数据(删除+插入原子性) +// if (!feeList.isEmpty()) { +// // 4.1 查询并删除重复项 +// +//// List duplicateIds = personalCostMapper.selectDuplicateIds(saveFeeList); +//// if (!duplicateIds.isEmpty()) { +//// personalCostMapper.deleteByIds(duplicateIds); +//// } +// +// // 4.2 批量插入主表 +// personalCostMapper.insertBatch(saveFeeList); +// } +// log.info("成功插入 {} 人员费用数据", dataList.size()); +// } else if (DepartmentCostImport.class.isAssignableFrom(importClass)) { +// //去重 +// dataList = deptFeeReplacement((List)dataList); +// List feeList = ((List) dataList).stream() +// .map(importObj -> { +// DepartmentCostDO fee = new DepartmentCostDO(); +// BeanUtils.copyProperties(importObj, fee); +// // 设置单位id +// fee.setCompanyId(String.valueOf(nameToCompanyIdMap.get(fee.getCompanyName()))); +// return fee; +// }) +// .collect(Collectors.toList()); +// if (!CollectionUtils.isEmpty(feeList)) { +// //查询重复项,进行删除 +// List ids = departmentCostMapper.selectDuplicateIds(feeList); +// if (!CollectionUtils.isEmpty(ids)) { +// departmentCostMapper.deleteByIds(ids); +// } +// // 调用批量插入方法 +// departmentCostMapper.insertBatch(feeList); +// } +// log.info("成功插入 {} 综合费用数据", feeList.size()); +// } else if (MechanicalCostImport.class.isAssignableFrom(importClass)) { +// List feeList = (List) dataList; +// List saveFeeList = new ArrayList<>(CollectionUtils.isEmpty(feeList) ? 0 : feeList.size()); +// if (!CollectionUtils.isEmpty(feeList)) { +// //获取班组对象 +// Map teamIdMap = this.getDeptListAll(deptIds); +// for (MechanicalCostImport importObj : feeList) { +// MechanicalCostDO fee = new MechanicalCostDO(); +// BeanUtils.copyProperties(importObj, fee); +// // 设置单位id +// fee.setCompanyId(String.valueOf(nameToCompanyIdMap.get(fee.getCompanyName()))); +// //设置班组id +// fee.setDeptId(getDeptList(teamIdMap, importObj.getTeamIds())); +// // 3.3 计算结束时间(空指针防护) +// Optional.ofNullable(fee.getStartUseTime()) +// .ifPresent(startTime -> { +// int useDuration = Optional.ofNullable(fee.getServiceLife()) +// .map(Math::toIntExact) // 处理可能的溢出 +// .orElse(0); +// fee.setEndUseTime(this.getEndLocalDateForYears(startTime, useDuration)); +// }); +// +// saveFeeList.add(fee); +// } +// } +// // 4. 批量插入主表(空集合直接跳过) +// if (!feeList.isEmpty()) { +// //查询重复项,进行删除 +// List ids = mechanicalCostMapper.selectDuplicateIds(saveFeeList); +// if (!CollectionUtils.isEmpty(ids)) { +// mechanicalCostMapper.deleteByIds(ids); +// } +// mechanicalCostMapper.insertBatch(saveFeeList); +// } +// log.info("成功插入 {} 自有机械费用数据", dataList.size()); +// } else if (RentalMechanicalCostImport.class.isAssignableFrom(importClass)) { +// List feeList = (List)dataList; +// List saveFeeList = new ArrayList<>(CollectionUtils.isEmpty(feeList) ? 0 : feeList.size()); +// if (!CollectionUtils.isEmpty(feeList)) { +// //获取班组对象 +// Map teamIdMap = this.getDeptListAll(deptIds); +// for (RentalMechanicalCostImport importObj : feeList) { +// RentalMechanicalCostDO fee = new RentalMechanicalCostDO(); +// BeanUtils.copyProperties(importObj, fee); +// // 设置单位id +// fee.setCompanyId(String.valueOf(nameToCompanyIdMap.get(fee.getCompanyName()))); +// //设置班组id +// List teamRels = new ArrayList<>(); +// String teamIdsStr = StringUtils.defaultString(importObj.getTeamIds()).replace(",", ","); +// String weightsStr = StringUtils.defaultString(importObj.getWeight()).replace(",", ","); +// +// String[] teamIds = teamIdsStr.split(","); +// String[] weights = weightsStr.split(","); +// for (int i = 0; i < teamIds.length; i++) { +// TeamBizdomainRelVo rel = new TeamBizdomainRelVo(); +// rel.setTeamName(teamIds[i].trim()); +// // 提前处理部门ID映射(复用deptMap) +// rel.setTeamId(Optional.ofNullable(teamIdMap.get(teamIds[i].trim())).map(String::valueOf).orElse(null)); +// rel.setWeight(Long.valueOf(weights[i].trim())); +// teamRels.add(rel); +// } +// fee.setTeamIds(teamRels); +// +// // 3.3 计算结束时间(空指针防护) +// Optional.ofNullable(fee.getStartUseTime()) +// .ifPresent(startTime -> { +// int useDuration = Optional.ofNullable(fee.getUseDuration()) +// .map(Math::toIntExact) // 处理可能的溢出 +// .orElse(0); +// fee.setEndUseTime(getEndLocalDateForYears(startTime, useDuration)); +// }); +// +// saveFeeList.add(fee); +// } +// } +// if (!feeList.isEmpty()) { +// rentalMechanicalCostMapper.insertBatch(saveFeeList); +// } +// log.info("成功插入 {} 租赁机械费用数据", dataList.size()); +// } else if (GardenWasteRecordImport.class.isAssignableFrom(importClass)) { +// //获取班组对象 +// List feeList = (List)dataList; +// List saveFeeList = new ArrayList<>(CollectionUtils.isEmpty(feeList) ? 0 : feeList.size()); +// if (!CollectionUtils.isEmpty(feeList)) { +// Map teamIdMap = this.getDeptListAll(deptIds); +// for (GardenWasteRecordImport importObj : feeList) { +// WasteRecordDO fee = new WasteRecordDO(); +// BeanUtils.copyProperties(importObj, fee); +// // 设置单位id +// fee.setCompanyId(String.valueOf(nameToCompanyIdMap.get(fee.getCompanyName()))); +// //设置班组id +// fee.setDeptId(getDeptList(teamIdMap, importObj.getTeamIds())); +// +// saveFeeList.add(fee); +// } +// } +// // 4. 批量插入主表(若主表插入失败,事务回滚) +// if (!feeList.isEmpty()) { +// wasteRecordMapper.insertBatch(saveFeeList); +// } +// +// log.info("成功插入 {} 园林废弃物费用数据", dataList.size()); +// } +// +// } +// +// /** +// * 从Redis获取分页数据 +// */ +// @Override +// public CostFeeController.PageResult < T > getPagedDataFromRedis(String batchId, String templateName, +// int page, int size, Class clazz) throws IOException { +// String redisKey = REDIS_KEY_PREFIX + templateName + ":" + batchId; +// +// // 获取总记录数 +// String totalStr = redisTemplate.opsForValue().get(redisKey + ":total"); +// int total = totalStr != null ? Integer.parseInt(totalStr) : 0; +// +// // 计算分页范围 +// int start = (page - 1) * size; +// int end = Math.min(start + size - 1, total - 1); +// +// // 分页查询数据 +// List pageData = new ArrayList<>(); +// if (start <= end && total > 0) { +// BoundHashOperations hashOps = redisTemplate.boundHashOps(redisKey + ":items"); +// +// // 批量获取指定范围的索引对应的数据 +// List indexes = IntStream.rangeClosed(start, end) +// .mapToObj(String::valueOf) +// .collect(Collectors.toList()); +// List jsonList = hashOps.multiGet(indexes); +// +// // 反序列化为对象 +// for (String json : jsonList) { +// if (json != null) { +// pageData.add(objectMapper.readValue(json, clazz)); +// } +// } +// } +// +// return new CostFeeController.PageResult<>(page, size, total, pageData); +// } +// +// +// /** +// * 从Redis获取全部数据 +// */ +// private List < T > getAllDataFromRedis(String batchId, String templateName, Class < T > clazz) throws +// IOException { +// String redisKey = REDIS_KEY_PREFIX + templateName + ":" + batchId; +// BoundHashOperations hashOps = redisTemplate.boundHashOps(redisKey + ":items"); +// +// // 获取所有数据的JSON字符串 +// List jsonList = hashOps.values(); +// List dataList = new ArrayList<>(jsonList.size()); +// +// // 反序列化为对象 +// for (String json : jsonList) { +// if (json != null) { +// dataList.add(objectMapper.readValue(json, clazz)); +// } +// } +// +// return dataList; +// } +// +// +// /** +// * 删除Redis临时数据 +// */ +// private void deleteRedisTempData (String batchId, String templateName){ +// String redisKey = REDIS_KEY_PREFIX + templateName + ":" + batchId; +// redisTemplate.delete(redisKey + ":total"); +// redisTemplate.delete(redisKey + ":items"); +// log.info("Redis临时数据已删除,批次ID:{}", batchId); +// } +// /** +// * @Author wangqian +// * @Description 导入内容校验 +// * @Date 2025/11/24 8:40 +// * @Param dataList +// * @param template +// * @Return void +// */ +// public void validateImportData(List dataList, TemplateEnum template) { +// if (CollectionUtils.isEmpty(dataList)) { +// return; // 空列表无需校验 +// } +// //登录用户单位 +// Long belongCompanyId = getCompanyId(); +// //单位集合 +// List companyList = deptApi.getSubDeptList(); +// List deptIds = companyList.stream().map(DeptRespDTO::getId).collect(Collectors.toList()); +// Map nameToCompanyIdMap = CollectionUtils.isEmpty(companyList) +// ? Map.of() // 空列表返回空不可变 Map(避免 null) +// : companyList.stream() +// // 转 Map:key=companyId,value=companyName;key 冲突时保留最后一个(可调整) +// .collect(Collectors.toMap( +// dept -> dept.getName().trim(), // value 映射:取 companyName(去空格) +// DeptRespDTO::getId, // key 映射:取 companyId +// (oldValue, newValue) -> newValue +// )); +// //班组集合 +// Map> deptList = this.getDetpList(deptIds); +// // 模板类型校验 +// Class importClass = template.getImportClass(); // 从枚举获取导入类,避免switch +// // 根据不同模板类型执行不同的处理逻辑 +// if (WaterFeeImport.class.isAssignableFrom(importClass)) { +// +// List importList = (List) dataList; +// +// // 2. 遍历,逐个创建 +// for (int i = 0; i < importList.size(); i++) { +// int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) +// WaterFeeImport importBean = importList.get(i); +// +// try { +// // 2.1 执行校验(替换原 ValidationUtils,直接用 Validator 校验,确保抛出 ConstraintViolationException) +// Set> violations = validator.validate(importBean); +// if (!violations.isEmpty()) { +// // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) +// // StringBuilder errorMsg = new StringBuilder(); +// for (ConstraintViolation violation : violations) { +// //errorMsg.append(violation.getMessage()).append(";"); +// throw exception0(BAD_REQUEST.getCode() ,String.format( +// "第[{}]条数据:"+ violation.getMessage() +// ), rowNum); +// } +// // 抛出包含行号和所有错误的异常 +// //throw exception0(BAD_REQUEST.getCode(), errorMsg.toString().trim(), violations); +// } +// +// } catch (ConstraintViolationException ex) { +// // 5. 包装异常,明确行号 + 真实校验错误( +// throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); +// } +// } +// } +// else if (PersonalCostImport.class.isAssignableFrom(importClass)) { +// +// List importList = (List) dataList; +// // 2. 遍历,逐个创建 +// for (int i = 0; i < importList.size(); i++) { +// int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) +// PersonalCostImport importBean = importList.get(i); +// +// try { +// // 2.1 执行校验(替换原 ValidationUtils,直接用 Validator 校验,确保抛出 ConstraintViolationException) +// Set> violations = validator.validate(importBean); +// if (!violations.isEmpty()) { +// // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) +// //StringBuilder errorMsg = new StringBuilder(); +// for (ConstraintViolation violation : violations) { +// // errorMsg.append(violation.getMessage()).append(";"); +// throw exception0(BAD_REQUEST.getCode() ,String.format( +// "第[{}]条数据:"+ violation.getMessage() +// ), rowNum); +// } +// // 抛出包含行号和所有错误的异常 +// // throw exception0(BAD_REQUEST.getCode(), errorMsg.toString().trim(), violations); +// } +// Long companyId = nameToCompanyIdMap.get(importBean.getCompanyName()); +// //单位校验 +// validatecompany(rowNum, importBean.getCompanyName(), companyId, belongCompanyId); +// //部门名称校验 +// validateTeams(rowNum, deptList.get(companyId), importBean.getTeamIds()); +// +// } catch (ConstraintViolationException ex) { +// // 5. 包装异常,明确行号 + 真实校验错误( +// throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); +// } +// } +// } +// else if (GardenWasteRecordImport.class.isAssignableFrom(importClass)) { +// +// List importList = (List) dataList; +// // 2. 遍历,逐个创建 +// for (int i = 0; i < importList.size(); i++) { +// int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) +// GardenWasteRecordImport importBean = importList.get(i); +// +// try { +// // 2.1 执行校验(替换原 ValidationUtils,直接用 Validator 校验,确保抛出 ConstraintViolationException) +// Set> violations = validator.validate(importBean); +// if (!violations.isEmpty()) { +// // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) +// //StringBuilder errorMsg = new StringBuilder(); +// for (ConstraintViolation violation : violations) { +// //errorMsg.append(violation.getMessage()).append(";"); +// throw exception0(BAD_REQUEST.getCode() ,String.format( +// "第[{}]条数据:"+ violation.getMessage() +// ), rowNum); +// } +// // 抛出包含行号和所有错误的异常 +// //throw exception0(BAD_REQUEST.getCode(), errorMsg.toString().trim(), violations); +// } +// Long companyId = nameToCompanyIdMap.get(importBean.getCompanyName()); +// //单位校验 +// validatecompany(rowNum, importBean.getCompanyName(), companyId, belongCompanyId); +// //部门名称校验 +// validateTeams(rowNum, deptList.get(companyId), importBean.getTeamIds()); +// +// } catch (ConstraintViolationException ex) { +// throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); +// } +// } +// } +// else if (MechanicalCostImport.class.isAssignableFrom(importClass)) { +// +// List importList = (List) dataList; +// // 2. 遍历,逐个创建 +// for (int i = 0; i < importList.size(); i++) { +// int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) +// MechanicalCostImport importBean = importList.get(i); +// +// try { +// // 2.1 执行校验(替换原 ValidationUtils,直接用 Validator 校验,确保抛出 ConstraintViolationException) +// Set> violations = validator.validate(importBean); +// if (!violations.isEmpty()) { +// // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) +// //StringBuilder errorMsg = new StringBuilder(); +// for (ConstraintViolation violation : violations) { +// //errorMsg.append(violation.getMessage()).append(";"); +// throw exception0(BAD_REQUEST.getCode() ,String.format( +// "第[{}]条数据:"+ violation.getMessage() +// ), rowNum); +// } +// // 抛出包含行号和所有错误的异常 +// //throw new ConstraintViolationException(errorMsg.toString().trim(), violations); +// } +// Long companyId = nameToCompanyIdMap.get(importBean.getCompanyName()); +// //单位校验 +// validatecompany(rowNum, importBean.getCompanyName(), companyId, belongCompanyId); +// //部门名称校验 +// validateTeams(rowNum, deptList.get(companyId), importBean.getTeamIds()); +// +// //车辆校验 +// if (CostFeeConstants.MECH_TYPE.equals(importBean.getMechType())) { +// if (StringUtils.isEmpty(importBean.getLicensePlate())) { +// throw exception0(BAD_REQUEST.getCode() ,String.format( +// "第[{}]条数据:车牌号不能为空" +// ), rowNum); +// } +// if (StringUtils.isEmpty(importBean.getVehicleType())) { +// throw exception0(BAD_REQUEST.getCode() ,String.format( +// "第[{}]条数据:车辆类型不能为空" +// ), rowNum); +// +// } +// if (StringUtils.isEmpty(importBean.getVehicleCategory())) { +// throw exception0(BAD_REQUEST.getCode() ,String.format( +// "第%d条数据:车辆类别不能为空" +// ), rowNum); +// } +// } +// +// } catch (ConstraintViolationException ex) { +// // 5. 包装异常,明确行号 + 真实校验错误( +// throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); +// } +// } +// } +// else if (RentalMechanicalCostImport.class.isAssignableFrom(importClass)) { +// +// List importList = (List) dataList; +// // 2. 遍历,逐个创建 +// for (int i = 0; i < importList.size(); i++) { +// int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) +// RentalMechanicalCostImport importBean = importList.get(i); +// +// try { +// // 2.1 执行校验(替换原 ValidationUtils,直接用 Validator 校验,确保抛出 ConstraintViolationException) +// Set> violations = validator.validate(importBean); +// if (!violations.isEmpty()) { +// // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) +// // StringBuilder errorMsg = new StringBuilder(); +// for (ConstraintViolation violation : violations) { +// // errorMsg.append(violation.getMessage()).append(";"); +// throw exception0(BAD_REQUEST.getCode() ,String.format( +// "第[{}]条数据:"+violation.getMessage() +// ), rowNum); +// } +// // 抛出包含行号和所有错误的异常 +// //throw new ConstraintViolationException(errorMsg.toString().trim(), violations); +// } +// // 处理可能的空值 +// String teamIdsStr = StringUtils.defaultString(importBean.getTeamIds()); +// String weightsStr = StringUtils.defaultString(importBean.getWeight()); +// +// // 统一替换中文逗号并分割 +// String[] teamIds = teamIdsStr.replace(",", ",").split(","); +// String[] weights = weightsStr.replace(",", ",").split(","); +// +// // 校验数组长度是否一致 +// if (teamIds.length != weights.length) { +// throw exception0(BAD_REQUEST.getCode(), String.format( +// "第%d条数据:权重值和所选班组数量不符(班组:%d个,权重:%d个)", +// rowNum, teamIds.length, weights.length +// )); +// } +// Long companyId = nameToCompanyIdMap.get(importBean.getCompanyName()); +// //单位校验 +// validatecompany(rowNum, importBean.getCompanyName(), companyId, belongCompanyId); +// //部门名称校验 +// validateTeams(rowNum, deptList.get(companyId), importBean.getTeamIds()); +// +// } catch (ConstraintViolationException ex) { +// // 5. 包装异常,明确行号 + 真实校验错误( +// throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); +// } +// } +// } +// else if (DepartmentCostImport.class.isAssignableFrom(importClass)) { +// +// List importList = (List) dataList; +// // 2. 遍历,逐个创建 +// for (int i = 0; i < importList.size(); i++) { +// int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) +// DepartmentCostImport importBean = importList.get(i); +// +// try { +// // 2.1 执行校验(替换原 ValidationUtils,直接用 Validator 校验,确保抛出 ConstraintViolationException) +// Set> violations = validator.validate(importBean); +// if (!violations.isEmpty()) { +// // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) +// //StringBuilder errorMsg = new StringBuilder(); +// for (ConstraintViolation violation : violations) { +// //errorMsg.append(violation.getMessage()).append(";"); +// throw exception0(BAD_REQUEST.getCode() ,String.format( +// "第[{}]条数据:"+violation.getMessage() +// ), rowNum); +// } +// // 抛出包含行号和所有错误的异常 +// //throw new ConstraintViolationException(errorMsg.toString().trim(), violations); +// } +// +// Long companyId = nameToCompanyIdMap.get(importBean.getCompanyName()); +// //单位校验 +// validatecompany(rowNum, importBean.getCompanyName(), companyId, belongCompanyId); +// } catch (ConstraintViolationException ex) { +// // 5. 包装异常,明确行号 + 真实校验错误( +// throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); +// } +// } +// } +// } +// +// private void validatecompany(int rowNum, String companyName, Long companyId, Long belongCompanyId){ +// // 校验数组长度是否一致 +// if (companyId == null) { +// throw exception0(BAD_REQUEST.getCode(), String.format( +// "第%d条数据:单位名称不正确(%s)", +// rowNum, companyName +// )); +// } +// // 校验导入单位 +// if (belongCompanyId != 100 && !belongCompanyId.equals(companyId)) { +// throw exception0(BAD_REQUEST.getCode(), String.format( +// "第%d条数据:导入单位%s与当前操作员单位不一致", +// rowNum, companyName +// )); +// } +// } +// private void validateTeams(int rowNum, List dept, String teamIds) { +// if (StringUtils.isNotEmpty(teamIds)) { +// String[] teamNames = teamIds.split(","); +// Set checkedTeams = new HashSet<>(); // 用于存储已校验的团队名称,检测重复 +// +// for (String teamName : teamNames) { +// String trimmedTeamName = teamName.trim(); // 处理前后空格 +// +// // 重复校验:如果Set中已存在该团队名称,说明重复 +// if (checkedTeams.contains(trimmedTeamName)) { +// throw exception0(BAD_REQUEST.getCode(), String.format( +// "第%d条数据:%s名称重复", +// rowNum, teamName +// )); +// } +// +// // 存在性校验:检查团队是否在dept中存在 +// if (!dept.contains(trimmedTeamName)) { +// throw exception0(BAD_REQUEST.getCode(), String.format( +// "第%d条数据:%s名称不正确", +// rowNum, teamName +// )); +// } +// +// // 将校验通过的团队名称加入Set,用于后续重复判断 +// checkedTeams.add(trimmedTeamName); +// } +// } +// } +// +// //查询单位下的班组信息 +// private Map> getDetpList (List deptIds) { +// Map> listMap = new HashMap<>(); +// for (Long depId : deptIds) { +// List deptList = deptApi.getChildDeptList(depId); +// List names = deptList.stream().map(DeptRespDTO::getName).collect(Collectors.toList()); +// listMap.put(depId,names); +// } +// return listMap; +// } +// +// /** +// * 按salaryMonth、expenseName、companyId三个字段去重 +// * @param costList 原始部门成本列表 +// * @return 去重后的列表 +// */ +// public List deptFeeReplacement(List costList) { +// if (costList == null || costList.isEmpty()) { +// return new ArrayList<>(); +// } +// +// // 1. 以三个字段的组合作为键(使用分隔符避免不同组合产生相同键) +// // 2. 遇到重复键时保留第一条记录 +// Map uniqueMap = costList.stream() +// .collect(Collectors.toMap( +// // 生成唯一键:salaryMonth|expenseName|companyId +// cost -> buildUniqueKey(cost), +// // 键不存在时存入当前对象 +// cost -> cost, +// // 键已存在时保留最后一个 +// (existing, replacement) -> replacement +// )); +// +// // 将去重后的结果转为List返回 +// return new ArrayList<>(uniqueMap.values()); +// } +// +// /** +// * 构建三个字段的唯一组合键(处理null值) +// */ +// private String buildUniqueKey(DepartmentCostImport cost) { +// // 使用Objects.toString处理可能的null值,避免NullPointerException +// return Objects.toString(cost.getSalaryMonth(), "") + "|" + +// Objects.toString(cost.getExpenseName(), "") + "|" + +// Objects.toString(cost.getCompanyName(), ""); +// } +// +// /** +// * 按salaryMonth、name、companyId、teamIdList四个字段去重 +// * @param costList 原始个人成本列表 +// * @return 去重后的列表 +// */ +// public List personalFeeReplacement(List costList) { +// if (costList == null || costList.isEmpty()) { +// return new ArrayList<>(); +// } +// +// // 1. 以四个字段的组合作为键(特别处理集合类型的teamIdList) +// // 2. 遇到重复键时保留第一条记录 +// Map uniqueMap = costList.stream() +// .collect(Collectors.toMap( +// // 生成唯一键:salaryMonth|name|companyId|teamIdListStr +// this::buildUniqueKey, +// // 键不存在时存入当前对象 +// cost -> cost, +// // 键已存在时保留第一个对象(可改为replacement保留最后一个) +// (existing, replacement) -> replacement +// )); +// +// // 将去重后的结果转为List返回 +// return new ArrayList<>(uniqueMap.values()); +// } +// +// /** +// * 构建四个字段的唯一组合键(处理null值和集合类型) +// */ +// private String buildUniqueKey(PersonalCostImport cost) { +// // 处理普通字段的null值 +// String salaryMonth = Objects.toString(cost.getSalaryMonth(), ""); +// String name = Objects.toString(cost.getName(), ""); +// String companyId = Objects.toString(cost.getCompanyName(), ""); +// String teamIds = Objects.toString(cost.getTeamIds(), ""); +// // 拼接唯一键 +// return salaryMonth + "|" + name + "|" + companyId + "|" + teamIds; +// } +// +// +// public static LocalDate getEndLocalDateForYears(LocalDate startDate, int years) { +// if (startDate == null) { +// throw new IllegalArgumentException("开始日期不能为null"); +// } +// if (years < 0) { +// throw new IllegalArgumentException("年数不能为负数"); +// } +// return startDate.plusYears(years); +// } +// +// /** +// * @Author wangqian +// * @Description 根据班组名称获取班组id +// * @Date 2025/11/26 19:38 +// */ +// /** +// * 根据部门ID列表获取「部门名称→部门ID」的映射(含空值防护) +// */ +// private Map getDeptListAll(List deptIds) { +// Map deptNameMap = new HashMap<>(); +// +// // 1. 空值安全:避免 deptIds 为 null/空列表导致 NPE +// if (CollectionUtils.isEmpty(deptIds)) { +// return deptNameMap; +// } +// +// for (Long deptId : deptIds) { +// // 2. 跳过 null 的部门ID +// if (deptId == null) { +// continue; +// } +// +// // 3. 获取子部门列表(防护接口返回 null) +// List deptList = deptApi.getChildDeptList(deptId); +// if (CollectionUtils.isEmpty(deptList)) { +// continue; +// } +// +// // 4. 遍历子部门:过滤无效名称,避免 Map 出现 null/空字符串键 +// for (DeptRespDTO dept : deptList) { +// if (dept == null) { +// continue; +// } +// String deptName = dept.getName(); +// // 过滤 null/空白名称(避免 Map 键为 null 或空字符串) +// if (deptName == null || deptName.trim().isEmpty()) { +// continue; +// } +// // 若名称重复,后遍历的部门会覆盖先遍历的(可根据业务调整规则) +// deptNameMap.put(deptName.trim(), dept.getId()); +// } +// } +// +// return deptNameMap; +// } +// /** +// * @Author wangqian +// * @Description 根据班组名称获取班组id集合 +// * @Date 2025/11/26 20:07 +// */ +// private List getDeptList(Map teamIdMap, String teamId) { +// List list = new ArrayList<>(); +// +// // 1. 处理 teamId 为空的情况,直接返回空列表 +// if (StringUtils.isEmpty(teamId)) { +// return list; +// } +// +// // 2. 分割字符串,处理空元素 +// String[] teamArray = teamId.split(","); +// for (String teamName : teamArray) { +// // 3. 去除首尾空格,避免因空格导致匹配不到 +// String trimTeamName = teamName.trim(); +// if (StringUtils.isEmpty(trimTeamName)) { +// continue; // 跳过空字符串元素 +// } +// +// // 4. 从Map中获取ID,处理null值(避免添加null到列表) +// Long deptId = teamIdMap.get(trimTeamName); +// if (deptId != null) { +// list.add(String.valueOf(deptId)); // 直接添加Long类型,修正原String类型错误 +// } +// } +// +// return list; +// } +//} diff --git a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java index 9a15c0c..9aabd57 100644 --- a/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java +++ b/urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java @@ -44,6 +44,13 @@ public class AuthPermissionInfoRespVO { @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.jpg") private String avatar; + @Schema(description = "公司ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1001") + private Long companyId; + + @Schema(description = "业务线", requiredMode = Schema.RequiredMode.REQUIRED, example = "1001") + private String busiLine; + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") private Long deptId; -- libgit2 0.21.4