Commit 2672c24ebc52bee62b7e7e9e8f72a09f937b2cdd
1 parent
75cf993f
派单及人机材功能迁移
Showing
5 changed files
with
190 additions
and
42 deletions
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/costfee/CostFeeController.java
| @@ -2,6 +2,7 @@ package com.zteits.urbanops.module.garden.controller.admin.costfee; | @@ -2,6 +2,7 @@ package com.zteits.urbanops.module.garden.controller.admin.costfee; | ||
| 2 | 2 | ||
| 3 | import com.zteits.urbanops.framework.common.pojo.CommonResult; | 3 | import com.zteits.urbanops.framework.common.pojo.CommonResult; |
| 4 | import com.zteits.urbanops.framework.excel.core.util.ExcelUtils; | 4 | import com.zteits.urbanops.framework.excel.core.util.ExcelUtils; |
| 5 | +import com.zteits.urbanops.module.garden.controller.admin.costfee.vo.WaterFeeImport; | ||
| 5 | import com.zteits.urbanops.module.garden.enums.TemplateEnum; | 6 | import com.zteits.urbanops.module.garden.enums.TemplateEnum; |
| 6 | import com.zteits.urbanops.module.garden.service.costfee.CostFeeService; | 7 | import com.zteits.urbanops.module.garden.service.costfee.CostFeeService; |
| 7 | import io.swagger.v3.oas.annotations.Operation; | 8 | import io.swagger.v3.oas.annotations.Operation; |
| @@ -19,6 +20,7 @@ import org.springframework.web.multipart.MultipartFile; | @@ -19,6 +20,7 @@ import org.springframework.web.multipart.MultipartFile; | ||
| 19 | import java.io.IOException; | 20 | import java.io.IOException; |
| 20 | import java.io.InputStream; | 21 | import java.io.InputStream; |
| 21 | import java.io.OutputStream; | 22 | import java.io.OutputStream; |
| 23 | +import java.lang.reflect.Method; | ||
| 22 | import java.net.URLEncoder; | 24 | import java.net.URLEncoder; |
| 23 | import java.nio.charset.StandardCharsets; | 25 | import java.nio.charset.StandardCharsets; |
| 24 | import java.util.*; | 26 | import java.util.*; |
| @@ -277,6 +279,8 @@ public class CostFeeController{ | @@ -277,6 +279,8 @@ public class CostFeeController{ | ||
| 277 | if (dataList == null) { | 279 | if (dataList == null) { |
| 278 | dataList = Collections.emptyList(); | 280 | dataList = Collections.emptyList(); |
| 279 | } | 281 | } |
| 282 | + // 关键:移除最后一行(以“说明”开头的行) | ||
| 283 | + removeLastLineIfStartWithExplain(dataList, importClass); | ||
| 280 | // 基础数据校验(非空、格式等) | 284 | // 基础数据校验(非空、格式等) |
| 281 | costFeeService.validateImportData(dataList, template); | 285 | costFeeService.validateImportData(dataList, template); |
| 282 | 286 | ||
| @@ -285,7 +289,65 @@ public class CostFeeController{ | @@ -285,7 +289,65 @@ public class CostFeeController{ | ||
| 285 | } | 289 | } |
| 286 | return new ImportResult<>(dataList, template.isNeedPreview()); | 290 | return new ImportResult<>(dataList, template.isNeedPreview()); |
| 287 | } | 291 | } |
| 292 | + /** | ||
| 293 | + * 移除列表最后一行(若该行第一列内容以“说明”开头) | ||
| 294 | + * @param dataList Excel解析后的实体类列表 | ||
| 295 | + * @param clazz 实体类字节码(用于反射获取第一列字段值) | ||
| 296 | + * @param <T> 泛型:Excel对应的实体类 | ||
| 297 | + */ | ||
| 298 | + private <T> void removeLastLineIfStartWithExplain(List<T> dataList, Class<T> clazz) { | ||
| 299 | + // 1. 跳过空列表/元素数<1的情况,避免索引越界 | ||
| 300 | + if (CollectionUtils.isEmpty(dataList)) { | ||
| 301 | + return; | ||
| 302 | + } | ||
| 303 | + | ||
| 304 | + // 2. 获取最后一个元素(正确索引:size()-1) | ||
| 305 | + T lastItem = dataList.get(dataList.size() - 1); | ||
| 306 | + if (Objects.isNull(lastItem)) { | ||
| 307 | + return; | ||
| 308 | + } | ||
| 309 | + | ||
| 310 | + // 3. 反射获取「第一列字段的值」(核心:Excel列对应实体类的字段,假设第一列字段名是 firstColumn,需根据实际调整) | ||
| 311 | + String firstColumnValue = getFirstColumnValue(lastItem, clazz); | ||
| 312 | + if (Objects.isNull(firstColumnValue)) { | ||
| 313 | + return; | ||
| 314 | + } | ||
| 315 | + | ||
| 316 | + // 4. 匹配“说明”(trim() 避免空格干扰,如“ 说明:xxx”) | ||
| 317 | + if (firstColumnValue.trim().startsWith("说明")) { | ||
| 318 | + // 移除最后一个元素(正确索引:size()-1) | ||
| 319 | + dataList.remove(dataList.size() - 1); | ||
| 320 | + } | ||
| 321 | + } | ||
| 288 | 322 | ||
| 323 | + /** | ||
| 324 | + * 反射获取实体类的「第一列字段值」(需根据你的Excel列配置调整字段名) | ||
| 325 | + * @param item 实体类对象(Excel一行数据) | ||
| 326 | + * @param clazz 实体类字节码 | ||
| 327 | + * @return 第一列的字符串值(null 表示无值) | ||
| 328 | + */ | ||
| 329 | + private <T> String getFirstColumnValue(T item, Class<T> clazz) { | ||
| 330 | + try { | ||
| 331 | + String firstColumnFieldName = ""; | ||
| 332 | + if (WaterFeeImport.class.isAssignableFrom(clazz)) { | ||
| 333 | + firstColumnFieldName = "feeMonth"; | ||
| 334 | + } else { | ||
| 335 | + return null; | ||
| 336 | + } | ||
| 337 | + | ||
| 338 | + // 反射获取 getter 方法() | ||
| 339 | + String getterMethodName = "get" + firstColumnFieldName.substring(0, 1).toUpperCase() + firstColumnFieldName.substring(1); | ||
| 340 | + Method getterMethod = clazz.getDeclaredMethod(getterMethodName); | ||
| 341 | + | ||
| 342 | + // 执行 getter 方法获取字段值 | ||
| 343 | + Object value = getterMethod.invoke(item); | ||
| 344 | + return value == null ? null : value.toString(); | ||
| 345 | + } catch (Exception e) { | ||
| 346 | + // 反射失败(字段名错误、无getter方法),打印日志不抛异常,避免影响整体流程 | ||
| 347 | + log.warn("获取Excel第一列字段值失败,实体类:{}", clazz.getName(), e); | ||
| 348 | + return null; | ||
| 349 | + } | ||
| 350 | + } | ||
| 289 | 351 | ||
| 290 | /** | 352 | /** |
| 291 | * 导入结果封装 | 353 | * 导入结果封装 |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/costfee/CostFeeServiceImpl.java
| @@ -5,7 +5,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; | @@ -5,7 +5,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 5 | import com.zteits.urbanops.framework.security.core.LoginUser; | 5 | import com.zteits.urbanops.framework.security.core.LoginUser; |
| 6 | import com.zteits.urbanops.module.garden.controller.admin.costfee.CostFeeController; | 6 | import com.zteits.urbanops.module.garden.controller.admin.costfee.CostFeeController; |
| 7 | import com.zteits.urbanops.module.garden.controller.admin.costfee.vo.*; | 7 | import com.zteits.urbanops.module.garden.controller.admin.costfee.vo.*; |
| 8 | +import com.zteits.urbanops.module.garden.enums.AssignTasksConstants; | ||
| 9 | +import com.zteits.urbanops.module.garden.enums.CostFeeConstants; | ||
| 8 | import com.zteits.urbanops.module.garden.enums.TemplateEnum; | 10 | import com.zteits.urbanops.module.garden.enums.TemplateEnum; |
| 11 | +import com.zteits.urbanops.module.system.api.dept.DeptApi; | ||
| 12 | +import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO; | ||
| 9 | import jakarta.annotation.Resource; | 13 | import jakarta.annotation.Resource; |
| 10 | import jakarta.validation.ConstraintViolation; | 14 | import jakarta.validation.ConstraintViolation; |
| 11 | import jakarta.validation.ConstraintViolationException; | 15 | import jakarta.validation.ConstraintViolationException; |
| @@ -25,7 +29,9 @@ import java.util.concurrent.TimeUnit; | @@ -25,7 +29,9 @@ import java.util.concurrent.TimeUnit; | ||
| 25 | import java.util.stream.Collectors; | 29 | import java.util.stream.Collectors; |
| 26 | import java.util.stream.IntStream; | 30 | import java.util.stream.IntStream; |
| 27 | 31 | ||
| 32 | +import static com.zteits.urbanops.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; | ||
| 28 | import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; | 33 | import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 34 | +import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception0; | ||
| 29 | import static com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils.getLoginUser; | 35 | import static com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils.getLoginUser; |
| 30 | import static com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils.getLoginUserDeptId; | 36 | import static com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils.getLoginUserDeptId; |
| 31 | import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.COST_FEE_NOT_EXISTS_001; | 37 | import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.COST_FEE_NOT_EXISTS_001; |
| @@ -50,7 +56,8 @@ public class CostFeeServiceImpl implements CostFeeService { | @@ -50,7 +56,8 @@ public class CostFeeServiceImpl implements CostFeeService { | ||
| 50 | private ObjectMapper objectMapper; | 56 | private ObjectMapper objectMapper; |
| 51 | @Resource | 57 | @Resource |
| 52 | private Validator validator; | 58 | private Validator validator; |
| 53 | - | 59 | + @Resource |
| 60 | + private DeptApi deptApi; | ||
| 54 | 61 | ||
| 55 | @Override | 62 | @Override |
| 56 | /** | 63 | /** |
| @@ -229,14 +236,29 @@ public class CostFeeServiceImpl implements CostFeeService { | @@ -229,14 +236,29 @@ public class CostFeeServiceImpl implements CostFeeService { | ||
| 229 | if (CollectionUtils.isEmpty(dataList)) { | 236 | if (CollectionUtils.isEmpty(dataList)) { |
| 230 | return; // 空列表无需校验 | 237 | return; // 空列表无需校验 |
| 231 | } | 238 | } |
| 232 | - LoginUser user = getLoginUser(); | 239 | + //登录用户部门 |
| 233 | Long deptId = getLoginUserDeptId(); | 240 | Long deptId = getLoginUserDeptId(); |
| 241 | + //单位集合 | ||
| 242 | + List<DeptRespDTO> companyList = deptApi.getSubDeptList(); | ||
| 243 | + List<Long> deptIds = companyList.stream().map(DeptRespDTO::getId).collect(Collectors.toList()); | ||
| 244 | + Map<String, Long> nameToCompanyIdMap = CollectionUtils.isEmpty(companyList) | ||
| 245 | + ? Map.of() // 空列表返回空不可变 Map(避免 null) | ||
| 246 | + : companyList.stream() | ||
| 247 | + // 转 Map:key=companyId,value=companyName;key 冲突时保留最后一个(可调整) | ||
| 248 | + .collect(Collectors.toMap( | ||
| 249 | + dept -> dept.getName().trim(), // value 映射:取 companyName(去空格) | ||
| 250 | + DeptRespDTO::getId, // key 映射:取 companyId | ||
| 251 | + (oldValue, newValue) -> newValue | ||
| 252 | + )); | ||
| 253 | + //班组集合 | ||
| 254 | + Map<Long, List<String>> deptList = this.getDetpList(deptIds); | ||
| 234 | // 模板类型校验 | 255 | // 模板类型校验 |
| 235 | Class<?> importClass = template.getImportClass(); // 从枚举获取导入类,避免switch | 256 | Class<?> importClass = template.getImportClass(); // 从枚举获取导入类,避免switch |
| 236 | // 根据不同模板类型执行不同的处理逻辑 | 257 | // 根据不同模板类型执行不同的处理逻辑 |
| 237 | if (WaterFeeImport.class.isAssignableFrom(importClass)) { | 258 | if (WaterFeeImport.class.isAssignableFrom(importClass)) { |
| 238 | 259 | ||
| 239 | List<WaterFeeImport> importList = (List<WaterFeeImport>) dataList; | 260 | List<WaterFeeImport> importList = (List<WaterFeeImport>) dataList; |
| 261 | + | ||
| 240 | // 2. 遍历,逐个创建 | 262 | // 2. 遍历,逐个创建 |
| 241 | for (int i = 0; i < importList.size(); i++) { | 263 | for (int i = 0; i < importList.size(); i++) { |
| 242 | int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) | 264 | int rowNum = i + 1; // 第i条数据 → 第rowNum行(对应Excel导入的行号逻辑) |
| @@ -247,18 +269,20 @@ public class CostFeeServiceImpl implements CostFeeService { | @@ -247,18 +269,20 @@ public class CostFeeServiceImpl implements CostFeeService { | ||
| 247 | Set<ConstraintViolation<WaterFeeImport>> violations = validator.validate(importBean); | 269 | Set<ConstraintViolation<WaterFeeImport>> violations = validator.validate(importBean); |
| 248 | if (!violations.isEmpty()) { | 270 | if (!violations.isEmpty()) { |
| 249 | // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) | 271 | // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) |
| 250 | - StringBuilder errorMsg = new StringBuilder(); | 272 | + // StringBuilder errorMsg = new StringBuilder(); |
| 251 | for (ConstraintViolation<WaterFeeImport> violation : violations) { | 273 | for (ConstraintViolation<WaterFeeImport> violation : violations) { |
| 252 | - errorMsg.append(violation.getMessage()).append(";"); | 274 | + //errorMsg.append(violation.getMessage()).append(";"); |
| 275 | + throw exception0(BAD_REQUEST.getCode() ,String.format( | ||
| 276 | + "第[{}]条数据:"+ violation.getMessage() | ||
| 277 | + ), rowNum); | ||
| 253 | } | 278 | } |
| 254 | // 抛出包含行号和所有错误的异常 | 279 | // 抛出包含行号和所有错误的异常 |
| 255 | - throw new ConstraintViolationException(errorMsg.toString().trim(), violations); | 280 | + //throw exception0(BAD_REQUEST.getCode(), errorMsg.toString().trim(), violations); |
| 256 | } | 281 | } |
| 257 | 282 | ||
| 258 | - | ||
| 259 | } catch (ConstraintViolationException ex) { | 283 | } catch (ConstraintViolationException ex) { |
| 260 | // 5. 包装异常,明确行号 + 真实校验错误( | 284 | // 5. 包装异常,明确行号 + 真实校验错误( |
| 261 | - throw new RuntimeException(String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); | 285 | + throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); |
| 262 | } | 286 | } |
| 263 | } | 287 | } |
| 264 | } | 288 | } |
| @@ -275,17 +299,20 @@ public class CostFeeServiceImpl implements CostFeeService { | @@ -275,17 +299,20 @@ public class CostFeeServiceImpl implements CostFeeService { | ||
| 275 | Set<ConstraintViolation<PersonalCostImport>> violations = validator.validate(importBean); | 299 | Set<ConstraintViolation<PersonalCostImport>> violations = validator.validate(importBean); |
| 276 | if (!violations.isEmpty()) { | 300 | if (!violations.isEmpty()) { |
| 277 | // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) | 301 | // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) |
| 278 | - StringBuilder errorMsg = new StringBuilder(); | 302 | + //StringBuilder errorMsg = new StringBuilder(); |
| 279 | for (ConstraintViolation<PersonalCostImport> violation : violations) { | 303 | for (ConstraintViolation<PersonalCostImport> violation : violations) { |
| 280 | - errorMsg.append(violation.getMessage()).append(";"); | 304 | + // errorMsg.append(violation.getMessage()).append(";"); |
| 305 | + throw exception0(BAD_REQUEST.getCode() ,String.format( | ||
| 306 | + "第[{}]条数据:"+ violation.getMessage() | ||
| 307 | + ), rowNum); | ||
| 281 | } | 308 | } |
| 282 | // 抛出包含行号和所有错误的异常 | 309 | // 抛出包含行号和所有错误的异常 |
| 283 | - throw new ConstraintViolationException(errorMsg.toString().trim(), violations); | 310 | + // throw exception0(BAD_REQUEST.getCode(), errorMsg.toString().trim(), violations); |
| 284 | } | 311 | } |
| 285 | 312 | ||
| 286 | } catch (ConstraintViolationException ex) { | 313 | } catch (ConstraintViolationException ex) { |
| 287 | // 5. 包装异常,明确行号 + 真实校验错误( | 314 | // 5. 包装异常,明确行号 + 真实校验错误( |
| 288 | - throw new RuntimeException(String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); | 315 | + throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); |
| 289 | } | 316 | } |
| 290 | } | 317 | } |
| 291 | } | 318 | } |
| @@ -302,18 +329,20 @@ public class CostFeeServiceImpl implements CostFeeService { | @@ -302,18 +329,20 @@ public class CostFeeServiceImpl implements CostFeeService { | ||
| 302 | Set<ConstraintViolation<GardenWasteRecordImport>> violations = validator.validate(importBean); | 329 | Set<ConstraintViolation<GardenWasteRecordImport>> violations = validator.validate(importBean); |
| 303 | if (!violations.isEmpty()) { | 330 | if (!violations.isEmpty()) { |
| 304 | // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) | 331 | // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) |
| 305 | - StringBuilder errorMsg = new StringBuilder(); | 332 | + //StringBuilder errorMsg = new StringBuilder(); |
| 306 | for (ConstraintViolation<GardenWasteRecordImport> violation : violations) { | 333 | for (ConstraintViolation<GardenWasteRecordImport> violation : violations) { |
| 307 | - errorMsg.append(violation.getMessage()).append(";"); | 334 | + //errorMsg.append(violation.getMessage()).append(";"); |
| 335 | + throw exception0(BAD_REQUEST.getCode() ,String.format( | ||
| 336 | + "第[{}]条数据:"+ violation.getMessage() | ||
| 337 | + ), rowNum); | ||
| 308 | } | 338 | } |
| 309 | // 抛出包含行号和所有错误的异常 | 339 | // 抛出包含行号和所有错误的异常 |
| 310 | - throw new ConstraintViolationException(errorMsg.toString().trim(), violations); | 340 | + //throw exception0(BAD_REQUEST.getCode(), errorMsg.toString().trim(), violations); |
| 311 | } | 341 | } |
| 312 | 342 | ||
| 313 | 343 | ||
| 314 | } catch (ConstraintViolationException ex) { | 344 | } catch (ConstraintViolationException ex) { |
| 315 | - // 5. 包装异常,明确行号 + 真实校验错误( | ||
| 316 | - throw new RuntimeException(String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); | 345 | + throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); |
| 317 | } | 346 | } |
| 318 | } | 347 | } |
| 319 | } | 348 | } |
| @@ -330,18 +359,45 @@ public class CostFeeServiceImpl implements CostFeeService { | @@ -330,18 +359,45 @@ public class CostFeeServiceImpl implements CostFeeService { | ||
| 330 | Set<ConstraintViolation<MechanicalCostImport>> violations = validator.validate(importBean); | 359 | Set<ConstraintViolation<MechanicalCostImport>> violations = validator.validate(importBean); |
| 331 | if (!violations.isEmpty()) { | 360 | if (!violations.isEmpty()) { |
| 332 | // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) | 361 | // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) |
| 333 | - StringBuilder errorMsg = new StringBuilder(); | 362 | + //StringBuilder errorMsg = new StringBuilder(); |
| 334 | for (ConstraintViolation<MechanicalCostImport> violation : violations) { | 363 | for (ConstraintViolation<MechanicalCostImport> violation : violations) { |
| 335 | - errorMsg.append(violation.getMessage()).append(";"); | 364 | + //errorMsg.append(violation.getMessage()).append(";"); |
| 365 | + throw exception0(BAD_REQUEST.getCode() ,String.format( | ||
| 366 | + "第[{}]条数据:"+ violation.getMessage() | ||
| 367 | + ), rowNum); | ||
| 336 | } | 368 | } |
| 337 | // 抛出包含行号和所有错误的异常 | 369 | // 抛出包含行号和所有错误的异常 |
| 338 | - throw new ConstraintViolationException(errorMsg.toString().trim(), violations); | 370 | + //throw new ConstraintViolationException(errorMsg.toString().trim(), violations); |
| 339 | } | 371 | } |
| 372 | + Long companyId = nameToCompanyIdMap.get(importBean.getCompanyName()); | ||
| 373 | + //单位校验 | ||
| 374 | + validatecompany(rowNum, importBean.getCompanyName(), companyId, deptId); | ||
| 375 | + //部门名称校验 | ||
| 376 | + validateTeams(rowNum, deptList.get(companyId), importBean.getTeamIds()); | ||
| 377 | + | ||
| 378 | + //车辆校验 | ||
| 379 | + if (CostFeeConstants.MECH_TYPE.equals(importBean.getMechType())) { | ||
| 380 | + if (StringUtils.isEmpty(importBean.getLicensePlate())) { | ||
| 381 | + throw exception0(BAD_REQUEST.getCode() ,String.format( | ||
| 382 | + "第[{}]条数据:车牌号不能为空" | ||
| 383 | + ), rowNum); | ||
| 384 | + } | ||
| 385 | + if (StringUtils.isEmpty(importBean.getVehicleType())) { | ||
| 386 | + throw exception0(BAD_REQUEST.getCode() ,String.format( | ||
| 387 | + "第[{}]条数据:车辆类型不能为空" | ||
| 388 | + ), rowNum); | ||
| 340 | 389 | ||
| 390 | + } | ||
| 391 | + if (StringUtils.isEmpty(importBean.getVehicleCategory())) { | ||
| 392 | + throw exception0(BAD_REQUEST.getCode() ,String.format( | ||
| 393 | + "第%d条数据:车辆类别不能为空" | ||
| 394 | + ), rowNum); | ||
| 395 | + } | ||
| 396 | + } | ||
| 341 | 397 | ||
| 342 | } catch (ConstraintViolationException ex) { | 398 | } catch (ConstraintViolationException ex) { |
| 343 | // 5. 包装异常,明确行号 + 真实校验错误( | 399 | // 5. 包装异常,明确行号 + 真实校验错误( |
| 344 | - throw new RuntimeException(String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); | 400 | + throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); |
| 345 | } | 401 | } |
| 346 | } | 402 | } |
| 347 | } | 403 | } |
| @@ -358,12 +414,15 @@ public class CostFeeServiceImpl implements CostFeeService { | @@ -358,12 +414,15 @@ public class CostFeeServiceImpl implements CostFeeService { | ||
| 358 | Set<ConstraintViolation<RentalMechanicalCostImport>> violations = validator.validate(importBean); | 414 | Set<ConstraintViolation<RentalMechanicalCostImport>> violations = validator.validate(importBean); |
| 359 | if (!violations.isEmpty()) { | 415 | if (!violations.isEmpty()) { |
| 360 | // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) | 416 | // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) |
| 361 | - StringBuilder errorMsg = new StringBuilder(); | 417 | + // StringBuilder errorMsg = new StringBuilder(); |
| 362 | for (ConstraintViolation<RentalMechanicalCostImport> violation : violations) { | 418 | for (ConstraintViolation<RentalMechanicalCostImport> violation : violations) { |
| 363 | - errorMsg.append(violation.getMessage()).append(";"); | 419 | + // errorMsg.append(violation.getMessage()).append(";"); |
| 420 | + throw exception0(BAD_REQUEST.getCode() ,String.format( | ||
| 421 | + "第[{}]条数据:"+violation.getMessage() | ||
| 422 | + ), rowNum); | ||
| 364 | } | 423 | } |
| 365 | // 抛出包含行号和所有错误的异常 | 424 | // 抛出包含行号和所有错误的异常 |
| 366 | - throw new ConstraintViolationException(errorMsg.toString().trim(), violations); | 425 | + //throw new ConstraintViolationException(errorMsg.toString().trim(), violations); |
| 367 | } | 426 | } |
| 368 | // 处理可能的空值 | 427 | // 处理可能的空值 |
| 369 | String teamIdsStr = StringUtils.defaultString(importBean.getTeamIds()); | 428 | String teamIdsStr = StringUtils.defaultString(importBean.getTeamIds()); |
| @@ -375,22 +434,20 @@ public class CostFeeServiceImpl implements CostFeeService { | @@ -375,22 +434,20 @@ public class CostFeeServiceImpl implements CostFeeService { | ||
| 375 | 434 | ||
| 376 | // 校验数组长度是否一致 | 435 | // 校验数组长度是否一致 |
| 377 | if (teamIds.length != weights.length) { | 436 | if (teamIds.length != weights.length) { |
| 378 | - throw new IllegalArgumentException(String.format( | 437 | + throw exception0(BAD_REQUEST.getCode(), String.format( |
| 379 | "第%d条数据:权重值和所选班组数量不符(班组:%d个,权重:%d个)", | 438 | "第%d条数据:权重值和所选班组数量不符(班组:%d个,权重:%d个)", |
| 380 | rowNum, teamIds.length, weights.length | 439 | rowNum, teamIds.length, weights.length |
| 381 | )); | 440 | )); |
| 382 | } | 441 | } |
| 383 | - | 442 | + Long companyId = nameToCompanyIdMap.get(importBean.getCompanyName()); |
| 384 | //单位校验 | 443 | //单位校验 |
| 385 | - // validatecompany(rowNum, importBean.getCompanyName(), deptId); | 444 | + validatecompany(rowNum, importBean.getCompanyName(), companyId, deptId); |
| 386 | //部门名称校验 | 445 | //部门名称校验 |
| 387 | - //validateTeams(rowNum, depts.get(data.getCompanyName()), data.getTeamIds()); | ||
| 388 | - | ||
| 389 | - | 446 | + validateTeams(rowNum, deptList.get(companyId), importBean.getTeamIds()); |
| 390 | 447 | ||
| 391 | } catch (ConstraintViolationException ex) { | 448 | } catch (ConstraintViolationException ex) { |
| 392 | // 5. 包装异常,明确行号 + 真实校验错误( | 449 | // 5. 包装异常,明确行号 + 真实校验错误( |
| 393 | - throw new RuntimeException(String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); | 450 | + throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); |
| 394 | } | 451 | } |
| 395 | } | 452 | } |
| 396 | } | 453 | } |
| @@ -407,36 +464,37 @@ public class CostFeeServiceImpl implements CostFeeService { | @@ -407,36 +464,37 @@ public class CostFeeServiceImpl implements CostFeeService { | ||
| 407 | Set<ConstraintViolation<DepartmentCostImport>> violations = validator.validate(importBean); | 464 | Set<ConstraintViolation<DepartmentCostImport>> violations = validator.validate(importBean); |
| 408 | if (!violations.isEmpty()) { | 465 | if (!violations.isEmpty()) { |
| 409 | // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) | 466 | // 收集所有校验错误信息(比如“用水量不能为空”“格式应为两位小数”) |
| 410 | - StringBuilder errorMsg = new StringBuilder(); | 467 | + //StringBuilder errorMsg = new StringBuilder(); |
| 411 | for (ConstraintViolation<DepartmentCostImport> violation : violations) { | 468 | for (ConstraintViolation<DepartmentCostImport> violation : violations) { |
| 412 | - errorMsg.append(violation.getMessage()).append(";"); | 469 | + //errorMsg.append(violation.getMessage()).append(";"); |
| 470 | + throw exception0(BAD_REQUEST.getCode() ,String.format( | ||
| 471 | + "第[{}]条数据:"+violation.getMessage() | ||
| 472 | + ), rowNum); | ||
| 413 | } | 473 | } |
| 414 | // 抛出包含行号和所有错误的异常 | 474 | // 抛出包含行号和所有错误的异常 |
| 415 | - throw new ConstraintViolationException(errorMsg.toString().trim(), violations); | 475 | + //throw new ConstraintViolationException(errorMsg.toString().trim(), violations); |
| 416 | } | 476 | } |
| 417 | 477 | ||
| 418 | 478 | ||
| 419 | } catch (ConstraintViolationException ex) { | 479 | } catch (ConstraintViolationException ex) { |
| 420 | // 5. 包装异常,明确行号 + 真实校验错误( | 480 | // 5. 包装异常,明确行号 + 真实校验错误( |
| 421 | - throw new RuntimeException(String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); | 481 | + throw exception0(BAD_REQUEST.getCode(), String.format("第%d条数据校验失败:%s", rowNum, ex.getMessage()), ex); |
| 422 | } | 482 | } |
| 423 | } | 483 | } |
| 424 | } | 484 | } |
| 425 | } | 485 | } |
| 426 | 486 | ||
| 427 | - private void validatecompany(int rowNum, String companyName, Long deptId){ | ||
| 428 | - //根据单位名称获取单位id | ||
| 429 | - Long companyId = null ; | 487 | + private void validatecompany(int rowNum, String companyName, Long companyId, Long deptId){ |
| 430 | // 校验数组长度是否一致 | 488 | // 校验数组长度是否一致 |
| 431 | if (companyId == null) { | 489 | if (companyId == null) { |
| 432 | - throw new IllegalArgumentException(String.format( | 490 | + throw exception0(BAD_REQUEST.getCode(), String.format( |
| 433 | "第%d条数据:单位名称不正确(%s)", | 491 | "第%d条数据:单位名称不正确(%s)", |
| 434 | rowNum, companyName | 492 | rowNum, companyName |
| 435 | )); | 493 | )); |
| 436 | } | 494 | } |
| 437 | // 校验导入单位 | 495 | // 校验导入单位 |
| 438 | - if (deptId != 100 && !companyId.equals(deptId)) { | ||
| 439 | - throw new IllegalArgumentException(String.format( | 496 | + if (deptId != 100 && !deptId.equals(companyId)) { |
| 497 | + throw exception0(BAD_REQUEST.getCode(), String.format( | ||
| 440 | "第%d条数据:导入单位%s与当前操作员单位不一致", | 498 | "第%d条数据:导入单位%s与当前操作员单位不一致", |
| 441 | rowNum, companyName | 499 | rowNum, companyName |
| 442 | )); | 500 | )); |
| @@ -451,7 +509,7 @@ public class CostFeeServiceImpl implements CostFeeService { | @@ -451,7 +509,7 @@ public class CostFeeServiceImpl implements CostFeeService { | ||
| 451 | 509 | ||
| 452 | // 重复校验:如果Set中已存在该团队名称,说明重复 | 510 | // 重复校验:如果Set中已存在该团队名称,说明重复 |
| 453 | if (checkedTeams.contains(trimmedTeamName)) { | 511 | if (checkedTeams.contains(trimmedTeamName)) { |
| 454 | - throw new IllegalArgumentException(String.format( | 512 | + throw exception0(BAD_REQUEST.getCode(), String.format( |
| 455 | "第%d条数据:%s名称重复", | 513 | "第%d条数据:%s名称重复", |
| 456 | rowNum, teamName | 514 | rowNum, teamName |
| 457 | )); | 515 | )); |
| @@ -459,7 +517,7 @@ public class CostFeeServiceImpl implements CostFeeService { | @@ -459,7 +517,7 @@ public class CostFeeServiceImpl implements CostFeeService { | ||
| 459 | 517 | ||
| 460 | // 存在性校验:检查团队是否在dept中存在 | 518 | // 存在性校验:检查团队是否在dept中存在 |
| 461 | if (!dept.contains(trimmedTeamName)) { | 519 | if (!dept.contains(trimmedTeamName)) { |
| 462 | - throw new IllegalArgumentException(String.format( | 520 | + throw exception0(BAD_REQUEST.getCode(), String.format( |
| 463 | "第%d条数据:%s名称不正确", | 521 | "第%d条数据:%s名称不正确", |
| 464 | rowNum, teamName | 522 | rowNum, teamName |
| 465 | )); | 523 | )); |
| @@ -469,4 +527,15 @@ public class CostFeeServiceImpl implements CostFeeService { | @@ -469,4 +527,15 @@ public class CostFeeServiceImpl implements CostFeeService { | ||
| 469 | checkedTeams.add(trimmedTeamName); | 527 | checkedTeams.add(trimmedTeamName); |
| 470 | } | 528 | } |
| 471 | } | 529 | } |
| 530 | + | ||
| 531 | + //查询单位下的班组信息 | ||
| 532 | + private Map<Long,List<String>> getDetpList (List<Long> deptIds) { | ||
| 533 | + Map<Long,List<String>> listMap = new HashMap<>(); | ||
| 534 | + for (Long depId : deptIds) { | ||
| 535 | + List<DeptRespDTO> deptList = deptApi.getChildDeptList(depId); | ||
| 536 | + List<String> names = deptList.stream().map(DeptRespDTO::getName).collect(Collectors.toList()); | ||
| 537 | + listMap.put(depId,names); | ||
| 538 | + } | ||
| 539 | + return listMap; | ||
| 540 | + } | ||
| 472 | } | 541 | } |
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/api/dept/DeptApi.java
| @@ -58,4 +58,11 @@ public interface DeptApi { | @@ -58,4 +58,11 @@ public interface DeptApi { | ||
| 58 | */ | 58 | */ |
| 59 | List<DeptRespDTO> getChildDeptList(Long id); | 59 | List<DeptRespDTO> getChildDeptList(Long id); |
| 60 | 60 | ||
| 61 | + /** | ||
| 62 | + * 获取二级部门 | ||
| 63 | + * | ||
| 64 | + * @return 子部门列表 | ||
| 65 | + */ | ||
| 66 | + List<DeptRespDTO> getSubDeptList(); | ||
| 67 | + | ||
| 61 | } | 68 | } |
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/api/dept/DeptApiImpl.java
| @@ -2,6 +2,7 @@ package com.zteits.urbanops.module.system.api.dept; | @@ -2,6 +2,7 @@ package com.zteits.urbanops.module.system.api.dept; | ||
| 2 | 2 | ||
| 3 | import com.zteits.urbanops.framework.common.util.object.BeanUtils; | 3 | import com.zteits.urbanops.framework.common.util.object.BeanUtils; |
| 4 | import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO; | 4 | import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO; |
| 5 | +import com.zteits.urbanops.module.system.controller.admin.dept.vo.dept.DeptRespVO; | ||
| 5 | import com.zteits.urbanops.module.system.dal.dataobject.dept.DeptDO; | 6 | import com.zteits.urbanops.module.system.dal.dataobject.dept.DeptDO; |
| 6 | import com.zteits.urbanops.module.system.service.dept.DeptService; | 7 | import com.zteits.urbanops.module.system.service.dept.DeptService; |
| 7 | import org.springframework.stereotype.Service; | 8 | import org.springframework.stereotype.Service; |
| @@ -10,6 +11,8 @@ import jakarta.annotation.Resource; | @@ -10,6 +11,8 @@ import jakarta.annotation.Resource; | ||
| 10 | import java.util.Collection; | 11 | import java.util.Collection; |
| 11 | import java.util.List; | 12 | import java.util.List; |
| 12 | 13 | ||
| 14 | +import static com.zteits.urbanops.framework.common.pojo.CommonResult.success; | ||
| 15 | + | ||
| 13 | /** | 16 | /** |
| 14 | * 部门 API 实现类 | 17 | * 部门 API 实现类 |
| 15 | * | 18 | * |
| @@ -44,4 +47,10 @@ public class DeptApiImpl implements DeptApi { | @@ -44,4 +47,10 @@ public class DeptApiImpl implements DeptApi { | ||
| 44 | return BeanUtils.toBean(childDeptList, DeptRespDTO.class); | 47 | return BeanUtils.toBean(childDeptList, DeptRespDTO.class); |
| 45 | } | 48 | } |
| 46 | 49 | ||
| 50 | + @Override | ||
| 51 | + public List<DeptRespDTO> getSubDeptList() { | ||
| 52 | + List<DeptDO> list = deptService.getSubDeptList(); | ||
| 53 | + return BeanUtils.toBean(list, DeptRespDTO.class); | ||
| 54 | + } | ||
| 55 | + | ||
| 47 | } | 56 | } |
urbanops-module-system/src/main/java/com/zteits/urbanops/module/system/controller/admin/dept/DeptController.java