feat:完善计量单位管理
This commit is contained in:
@@ -38,7 +38,6 @@ import com.zt.plat.module.unitmanagement.service.UnitConversion.UnitConversionSe
|
||||
@Validated
|
||||
public class UnitConversionController implements BusinessControllerMarker {
|
||||
|
||||
|
||||
@Resource
|
||||
private UnitConversionService unitConversionService;
|
||||
|
||||
@@ -105,4 +104,54 @@ public class UnitConversionController implements BusinessControllerMarker {
|
||||
BeanUtils.toBean(list, UnitConversionRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/convert")
|
||||
@Operation(summary = "单位转换")
|
||||
@PreAuthorize("@ss.hasPermission('unitmanagement:unit-conversion:query')")
|
||||
public CommonResult<UnitConvertRespVO> convert(@Valid @RequestBody UnitConvertReqVO convertReqVO) {
|
||||
return success(unitConversionService.convert(convertReqVO));
|
||||
}
|
||||
|
||||
@PostMapping("/batch-convert")
|
||||
@Operation(summary = "批量单位转换")
|
||||
@PreAuthorize("@ss.hasPermission('unitmanagement:unit-conversion:query')")
|
||||
public CommonResult<BatchUnitConvertRespVO> batchConvert(@Valid @RequestBody BatchUnitConvertReqVO batchReqVO) {
|
||||
return success(unitConversionService.batchConvert(batchReqVO));
|
||||
}
|
||||
|
||||
@PostMapping("/convert-by-symbol")
|
||||
@Operation(summary = "按单位符号转换")
|
||||
@PreAuthorize("@ss.hasPermission('unitmanagement:unit-conversion:query')")
|
||||
public CommonResult<UnitConvertRespVO> convertBySymbol(@Valid @RequestBody UnitConvertBySymbolReqVO reqVO) {
|
||||
return success(unitConversionService.convertBySymbol(reqVO));
|
||||
}
|
||||
|
||||
@PostMapping("/convert-by-name")
|
||||
@Operation(summary = "按单位名称转换")
|
||||
@PreAuthorize("@ss.hasPermission('unitmanagement:unit-conversion:query')")
|
||||
public CommonResult<UnitConvertRespVO> convertByName(@Valid @RequestBody UnitConvertByNameReqVO reqVO) {
|
||||
return success(unitConversionService.convertByName(reqVO));
|
||||
}
|
||||
|
||||
@PostMapping("/batch-convert-by-symbol")
|
||||
@Operation(summary = "批量按单位符号转换")
|
||||
@PreAuthorize("@ss.hasPermission('unitmanagement:unit-conversion:query')")
|
||||
public CommonResult<BatchUnitConvertRespVO> batchConvertBySymbol(@Valid @RequestBody BatchUnitConvertBySymbolReqVO reqVO) {
|
||||
return success(unitConversionService.batchConvertBySymbol(reqVO));
|
||||
}
|
||||
|
||||
@PostMapping("/batch-convert-by-name")
|
||||
@Operation(summary = "批量按单位名称转换")
|
||||
@PreAuthorize("@ss.hasPermission('unitmanagement:unit-conversion:query')")
|
||||
public CommonResult<BatchUnitConvertRespVO> batchConvertByName(@Valid @RequestBody BatchUnitConvertByNameReqVO reqVO) {
|
||||
return success(unitConversionService.batchConvertByName(reqVO));
|
||||
}
|
||||
|
||||
@GetMapping("/validate-paths")
|
||||
@Operation(summary = "校验量纲的转换路径")
|
||||
@Parameter(name = "quantityId", description = "量纲ID", required = true, example = "1")
|
||||
@PreAuthorize("@ss.hasPermission('unitmanagement:unit-conversion:query')")
|
||||
public CommonResult<UnitConversionValidationRespVO> validateConversionPaths(@RequestParam("quantityId") Long quantityId) {
|
||||
return success(unitConversionService.validateConversionPaths(quantityId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.zt.plat.module.unitmanagement.controller.admin.UnitConversion.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 批量按名称单位转换 Request VO")
|
||||
@Data
|
||||
public class BatchUnitConvertByNameReqVO {
|
||||
|
||||
@Schema(description = "源单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "千克")
|
||||
@NotBlank(message = "源单位名称不能为空")
|
||||
private String srcUnitName;
|
||||
|
||||
@Schema(description = "目标单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "吨")
|
||||
@NotBlank(message = "目标单位名称不能为空")
|
||||
private String tgtUnitName;
|
||||
|
||||
@Schema(description = "待转换的值列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "待转换的值列表不能为空")
|
||||
private List<BigDecimal> values;
|
||||
|
||||
@Schema(description = "精度(小数位数)", example = "6")
|
||||
private Integer precision = 6;
|
||||
|
||||
@Schema(description = "是否忽略错误(true:遇到错误继续执行, false:遇到错误立即停止)", example = "false")
|
||||
private Boolean ignoreErrors = false;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.zt.plat.module.unitmanagement.controller.admin.UnitConversion.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 批量按符号单位转换 Request VO")
|
||||
@Data
|
||||
public class BatchUnitConvertBySymbolReqVO {
|
||||
|
||||
@Schema(description = "源单位符号", requiredMode = Schema.RequiredMode.REQUIRED, example = "m")
|
||||
@NotBlank(message = "源单位符号不能为空")
|
||||
private String srcUnitSymbol;
|
||||
|
||||
@Schema(description = "目标单位符号", requiredMode = Schema.RequiredMode.REQUIRED, example = "km")
|
||||
@NotBlank(message = "目标单位符号不能为空")
|
||||
private String tgtUnitSymbol;
|
||||
|
||||
@Schema(description = "待转换的值列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "待转换的值列表不能为空")
|
||||
private List<BigDecimal> values;
|
||||
|
||||
@Schema(description = "精度(小数位数)", example = "6")
|
||||
private Integer precision = 6;
|
||||
|
||||
@Schema(description = "是否忽略错误(true:遇到错误继续执行, false:遇到错误立即停止)", example = "false")
|
||||
private Boolean ignoreErrors = false;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.zt.plat.module.unitmanagement.controller.admin.UnitConversion.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 批量单位转换 Request VO")
|
||||
@Data
|
||||
public class BatchUnitConvertReqVO {
|
||||
|
||||
@Schema(description = "转换项列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "转换项列表不能为空")
|
||||
private List<UnitConvertReqVO> items;
|
||||
|
||||
@Schema(description = "是否忽略错误(true:遇到错误继续执行, false:遇到错误立即停止)", example = "false")
|
||||
private Boolean ignoreErrors = false;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.zt.plat.module.unitmanagement.controller.admin.UnitConversion.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.Builder;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 批量单位转换 Response VO")
|
||||
@Data
|
||||
@Builder
|
||||
public class BatchUnitConvertRespVO {
|
||||
|
||||
@Schema(description = "转换结果列表")
|
||||
private List<UnitConvertResultItem> results;
|
||||
|
||||
@Schema(description = "成功数量", example = "10")
|
||||
private Integer successCount;
|
||||
|
||||
@Schema(description = "失败数量", example = "0")
|
||||
private Integer failureCount;
|
||||
|
||||
@Schema(description = "总数量", example = "10")
|
||||
private Integer totalCount;
|
||||
|
||||
@Schema(description = "转换结果项")
|
||||
@Data
|
||||
@Builder
|
||||
public static class UnitConvertResultItem {
|
||||
|
||||
@Schema(description = "是否成功", example = "true")
|
||||
private Boolean success;
|
||||
|
||||
@Schema(description = "转换结果(成功时返回)")
|
||||
private UnitConvertRespVO data;
|
||||
|
||||
@Schema(description = "错误信息(失败时返回)", example = "找不到转换规则")
|
||||
private String errorMessage;
|
||||
|
||||
@Schema(description = "原始请求")
|
||||
private UnitConvertReqVO request;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.zt.plat.module.unitmanagement.controller.admin.UnitConversion.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 单位转换路径校验响应 VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class UnitConversionValidationRespVO {
|
||||
|
||||
@Schema(description = "量纲ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long quantityId;
|
||||
|
||||
@Schema(description = "量纲名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "长度")
|
||||
private String quantityName;
|
||||
|
||||
@Schema(description = "量纲符号", example = "L")
|
||||
private String quantitySymbol;
|
||||
|
||||
@Schema(description = "总单位数", requiredMode = Schema.RequiredMode.REQUIRED, example = "8")
|
||||
private Integer totalUnits;
|
||||
|
||||
@Schema(description = "可转换单位数", requiredMode = Schema.RequiredMode.REQUIRED, example = "8")
|
||||
private Integer convertibleUnits;
|
||||
|
||||
@Schema(description = "不可转换单位数", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer unconvertibleUnits;
|
||||
|
||||
@Schema(description = "是否全部可转换", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean allConvertible;
|
||||
|
||||
@Schema(description = "基准单位信息")
|
||||
private BaseUnitInfo baseUnit;
|
||||
|
||||
@Schema(description = "不可转换的单位列表")
|
||||
private List<UnconvertibleUnitInfo> unconvertibleUnitList;
|
||||
|
||||
@Schema(description = "转换路径详情")
|
||||
private List<ConversionPathInfo> conversionPaths;
|
||||
|
||||
@Schema(description = "基准单位信息")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class BaseUnitInfo {
|
||||
@Schema(description = "单位ID", example = "1")
|
||||
private Long unitId;
|
||||
|
||||
@Schema(description = "单位名称", example = "米")
|
||||
private String unitName;
|
||||
|
||||
@Schema(description = "单位符号", example = "m")
|
||||
private String unitSymbol;
|
||||
}
|
||||
|
||||
@Schema(description = "不可转换单位信息")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class UnconvertibleUnitInfo {
|
||||
@Schema(description = "单位ID", example = "1")
|
||||
private Long unitId;
|
||||
|
||||
@Schema(description = "单位名称", example = "光年")
|
||||
private String unitName;
|
||||
|
||||
@Schema(description = "单位符号", example = "ly")
|
||||
private String unitSymbol;
|
||||
|
||||
@Schema(description = "原因", example = "缺少到基准单位的转换规则")
|
||||
private String reason;
|
||||
}
|
||||
|
||||
@Schema(description = "转换路径信息")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class ConversionPathInfo {
|
||||
@Schema(description = "源单位ID", example = "1")
|
||||
private Long srcUnitId;
|
||||
|
||||
@Schema(description = "源单位名称", example = "千米")
|
||||
private String srcUnitName;
|
||||
|
||||
@Schema(description = "目标单位ID", example = "2")
|
||||
private Long tgtUnitId;
|
||||
|
||||
@Schema(description = "目标单位名称", example = "米")
|
||||
private String tgtUnitName;
|
||||
|
||||
@Schema(description = "是否有直接转换", example = "true")
|
||||
private Boolean hasDirect;
|
||||
|
||||
@Schema(description = "是否可通过基准单位转换", example = "true")
|
||||
private Boolean hasViaBase;
|
||||
|
||||
@Schema(description = "转换路径描述", example = "千米 → 米 (直接转换)")
|
||||
private String pathDescription;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.zt.plat.module.unitmanagement.controller.admin.UnitConversion.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 按名称单位转换 Request VO")
|
||||
@Data
|
||||
public class UnitConvertByNameReqVO {
|
||||
|
||||
@Schema(description = "源单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "千克")
|
||||
@NotBlank(message = "源单位名称不能为空")
|
||||
private String srcUnitName;
|
||||
|
||||
@Schema(description = "目标单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "吨")
|
||||
@NotBlank(message = "目标单位名称不能为空")
|
||||
private String tgtUnitName;
|
||||
|
||||
@Schema(description = "待转换的值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
|
||||
@NotNull(message = "待转换的值不能为空")
|
||||
private BigDecimal value;
|
||||
|
||||
@Schema(description = "精度(小数位数)", example = "6")
|
||||
private Integer precision = 6;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.zt.plat.module.unitmanagement.controller.admin.UnitConversion.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 按符号单位转换 Request VO")
|
||||
@Data
|
||||
public class UnitConvertBySymbolReqVO {
|
||||
|
||||
@Schema(description = "源单位符号", requiredMode = Schema.RequiredMode.REQUIRED, example = "kg")
|
||||
@NotBlank(message = "源单位符号不能为空")
|
||||
private String srcUnitSymbol;
|
||||
|
||||
@Schema(description = "目标单位符号", requiredMode = Schema.RequiredMode.REQUIRED, example = "t")
|
||||
@NotBlank(message = "目标单位符号不能为空")
|
||||
private String tgtUnitSymbol;
|
||||
|
||||
@Schema(description = "待转换的值", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
|
||||
@NotNull(message = "待转换的值不能为空")
|
||||
private BigDecimal value;
|
||||
|
||||
@Schema(description = "精度(小数位数)", example = "6")
|
||||
private Integer precision = 6;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.zt.plat.module.unitmanagement.controller.admin.UnitConversion.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 单位转换 Request VO")
|
||||
@Data
|
||||
public class UnitConvertReqVO {
|
||||
|
||||
@Schema(description = "源单位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "源单位ID不能为空")
|
||||
private Long srcUntId;
|
||||
|
||||
@Schema(description = "目标单位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@NotNull(message = "目标单位ID不能为空")
|
||||
private Long tgtUntId;
|
||||
|
||||
@Schema(description = "待转换的值", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
|
||||
@NotNull(message = "待转换的值不能为空")
|
||||
private BigDecimal value;
|
||||
|
||||
@Schema(description = "精度(小数位数)", example = "6")
|
||||
private Integer precision = 6;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.zt.plat.module.unitmanagement.controller.admin.UnitConversion.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.Builder;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 单位转换 Response VO")
|
||||
@Data
|
||||
@Builder
|
||||
public class UnitConvertRespVO {
|
||||
|
||||
@Schema(description = "源单位ID", example = "1")
|
||||
private Long srcUntId;
|
||||
|
||||
@Schema(description = "源单位名称", example = "米")
|
||||
private String srcUntName;
|
||||
|
||||
@Schema(description = "源单位符号", example = "m")
|
||||
private String srcUntSmb;
|
||||
|
||||
@Schema(description = "目标单位ID", example = "2")
|
||||
private Long tgtUntId;
|
||||
|
||||
@Schema(description = "目标单位名称", example = "千米")
|
||||
private String tgtUntName;
|
||||
|
||||
@Schema(description = "目标单位符号", example = "km")
|
||||
private String tgtUntSmb;
|
||||
|
||||
@Schema(description = "原始值", example = "1000")
|
||||
private BigDecimal originalValue;
|
||||
|
||||
@Schema(description = "转换后的值", example = "1")
|
||||
private BigDecimal convertedValue;
|
||||
|
||||
@Schema(description = "转换因子", example = "0.001")
|
||||
private BigDecimal factor;
|
||||
|
||||
@Schema(description = "转换公式", example = "1000m = 1km")
|
||||
private String formula;
|
||||
|
||||
@Schema(description = "转换策略", example = "DIRECT")
|
||||
private String strategy;
|
||||
}
|
||||
@@ -105,4 +105,11 @@ public class UnitQuantityController implements BusinessControllerMarker {
|
||||
BeanUtils.toBean(list, UnitQuantityRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/tree")
|
||||
@Operation(summary = "获取量纲及单位树")
|
||||
@PreAuthorize("@ss.hasPermission('unitmanagement:unit-quantity:query')")
|
||||
public CommonResult<List<UnitQuantityTreeRespVO>> getUnitQuantityTree() {
|
||||
return success(unitQuantityService.getUnitQuantityTree());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.zt.plat.module.unitmanagement.controller.admin.UnitQuantity.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 量纲及单位树 Response VO")
|
||||
@Data
|
||||
public class UnitQuantityTreeRespVO {
|
||||
|
||||
@Schema(description = "量纲ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "量纲名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "长度")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "量纲符号", requiredMode = Schema.RequiredMode.REQUIRED, example = "L")
|
||||
private String symbol;
|
||||
|
||||
@Schema(description = "量纲描述", example = "用于测量物体长短、距离的物理量")
|
||||
private String dsp;
|
||||
|
||||
@Schema(description = "下属单位列表")
|
||||
private List<UnitItemVO> units;
|
||||
|
||||
@Schema(description = "单位项")
|
||||
@Data
|
||||
public static class UnitItemVO {
|
||||
|
||||
@Schema(description = "单位ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "米")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "单位符号", requiredMode = Schema.RequiredMode.REQUIRED, example = "m")
|
||||
private String smb;
|
||||
|
||||
@Schema(description = "是否基准单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer isBse;
|
||||
|
||||
@Schema(description = "关联关系ID", example = "1")
|
||||
private Long relationId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
package com.zt.plat.module.unitmanagement.service.UnitConversion;
|
||||
|
||||
import com.zt.plat.module.unitmanagement.dal.dao.UnitConversion.UnitConversionMapper;
|
||||
import com.zt.plat.module.unitmanagement.dal.dao.QuantityUnitRelation.QuantityUnitRelationMapper;
|
||||
import com.zt.plat.module.unitmanagement.dal.dao.UntInfo.UntInfoMapper;
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.UnitConversion.UnitConversionDO;
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.QuantityUnitRelation.QuantityUnitRelationDO;
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.UntInfo.UntInfoDO;
|
||||
import com.zt.plat.module.unitmanagement.util.UnitConversionUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 单位转换辅助服务
|
||||
*
|
||||
* 为其他模块提供简单易用的单位转换方法
|
||||
* 支持按单位符号和单位名称进行转换
|
||||
*
|
||||
* @author 系统
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class UnitConversionHelperService {
|
||||
|
||||
@Resource
|
||||
private UnitConversionMapper unitConversionMapper;
|
||||
|
||||
@Resource
|
||||
private QuantityUnitRelationMapper quantityUnitRelationMapper;
|
||||
|
||||
@Resource
|
||||
private UntInfoMapper untInfoMapper;
|
||||
|
||||
/**
|
||||
* 按单位符号转换(推荐使用)
|
||||
*
|
||||
* @param value 待转换的值
|
||||
* @param srcSymbol 源单位符号(如: "kg", "m", "km")
|
||||
* @param tgtSymbol 目标单位符号
|
||||
* @return 转换后的值
|
||||
*/
|
||||
public BigDecimal convertBySymbol(BigDecimal value, String srcSymbol, String tgtSymbol) {
|
||||
return convertBySymbol(value, srcSymbol, tgtSymbol, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位符号转换(推荐使用)
|
||||
*
|
||||
* @param value 待转换的值
|
||||
* @param srcSymbol 源单位符号(如: "kg", "m", "km")
|
||||
* @param tgtSymbol 目标单位符号
|
||||
* @param precision 精度(小数位数)
|
||||
* @return 转换后的值
|
||||
*/
|
||||
public BigDecimal convertBySymbol(BigDecimal value, String srcSymbol, String tgtSymbol, int precision) {
|
||||
log.debug("按符号转换: {} {} → {}", value, srcSymbol, tgtSymbol);
|
||||
|
||||
// 加载数据
|
||||
List<UnitConversionDO> conversions = unitConversionMapper.selectList();
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
|
||||
List<UntInfoDO> units = untInfoMapper.selectList();
|
||||
|
||||
// 调用工具类
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convertBySymbol(
|
||||
value, srcSymbol, tgtSymbol, conversions, relations, units, precision
|
||||
);
|
||||
|
||||
log.debug("转换结果: {} (策略: {})", result.getValue(), result.getStrategy());
|
||||
return result.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位名称转换
|
||||
*
|
||||
* @param value 待转换的值
|
||||
* @param srcName 源单位名称(如: "千克", "米", "千米")
|
||||
* @param tgtName 目标单位名称
|
||||
* @return 转换后的值
|
||||
*/
|
||||
public BigDecimal convertByName(BigDecimal value, String srcName, String tgtName) {
|
||||
return convertByName(value, srcName, tgtName, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位名称转换
|
||||
*
|
||||
* @param value 待转换的值
|
||||
* @param srcName 源单位名称(如: "千克", "米", "千米")
|
||||
* @param tgtName 目标单位名称
|
||||
* @param precision 精度(小数位数)
|
||||
* @return 转换后的值
|
||||
*/
|
||||
public BigDecimal convertByName(BigDecimal value, String srcName, String tgtName, int precision) {
|
||||
log.debug("按名称转换: {} {} → {}", value, srcName, tgtName);
|
||||
|
||||
// 加载数据
|
||||
List<UnitConversionDO> conversions = unitConversionMapper.selectList();
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
|
||||
List<UntInfoDO> units = untInfoMapper.selectList();
|
||||
|
||||
// 调用工具类
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convertByName(
|
||||
value, srcName, tgtName, conversions, relations, units, precision
|
||||
);
|
||||
|
||||
log.debug("转换结果: {} (策略: {})", result.getValue(), result.getStrategy());
|
||||
return result.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位符号批量转换
|
||||
*
|
||||
* @param values 待转换的值列表
|
||||
* @param srcSymbol 源单位符号
|
||||
* @param tgtSymbol 目标单位符号
|
||||
* @return 转换后的值列表
|
||||
*/
|
||||
public List<BigDecimal> batchConvertBySymbol(List<BigDecimal> values, String srcSymbol, String tgtSymbol) {
|
||||
return batchConvertBySymbol(values, srcSymbol, tgtSymbol, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位符号批量转换
|
||||
*
|
||||
* @param values 待转换的值列表
|
||||
* @param srcSymbol 源单位符号
|
||||
* @param tgtSymbol 目标单位符号
|
||||
* @param precision 精度(小数位数)
|
||||
* @return 转换后的值列表
|
||||
*/
|
||||
public List<BigDecimal> batchConvertBySymbol(List<BigDecimal> values, String srcSymbol, String tgtSymbol, int precision) {
|
||||
log.debug("批量按符号转换: {} 个值, {} → {}", values.size(), srcSymbol, tgtSymbol);
|
||||
|
||||
// 加载数据
|
||||
List<UnitConversionDO> conversions = unitConversionMapper.selectList();
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
|
||||
List<UntInfoDO> units = untInfoMapper.selectList();
|
||||
|
||||
// 调用工具类
|
||||
List<UnitConversionUtil.ConversionResult> results = UnitConversionUtil.batchConvertBySymbol(
|
||||
values, srcSymbol, tgtSymbol, conversions, relations, units, precision
|
||||
);
|
||||
|
||||
// 提取转换后的值
|
||||
return results.stream()
|
||||
.map(UnitConversionUtil.ConversionResult::getValue)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位名称批量转换
|
||||
*
|
||||
* @param values 待转换的值列表
|
||||
* @param srcName 源单位名称
|
||||
* @param tgtName 目标单位名称
|
||||
* @return 转换后的值列表
|
||||
*/
|
||||
public List<BigDecimal> batchConvertByName(List<BigDecimal> values, String srcName, String tgtName) {
|
||||
return batchConvertByName(values, srcName, tgtName, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位名称批量转换
|
||||
*
|
||||
* @param values 待转换的值列表
|
||||
* @param srcName 源单位名称
|
||||
* @param tgtName 目标单位名称
|
||||
* @param precision 精度(小数位数)
|
||||
* @return 转换后的值列表
|
||||
*/
|
||||
public List<BigDecimal> batchConvertByName(List<BigDecimal> values, String srcName, String tgtName, int precision) {
|
||||
log.debug("批量按名称转换: {} 个值, {} → {}", values.size(), srcName, tgtName);
|
||||
|
||||
// 加载数据
|
||||
List<UnitConversionDO> conversions = unitConversionMapper.selectList();
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
|
||||
List<UntInfoDO> units = untInfoMapper.selectList();
|
||||
|
||||
// 调用工具类
|
||||
List<UnitConversionUtil.ConversionResult> results = UnitConversionUtil.batchConvertByName(
|
||||
values, srcName, tgtName, conversions, relations, units, precision
|
||||
);
|
||||
|
||||
// 提取转换后的值
|
||||
return results.stream()
|
||||
.map(UnitConversionUtil.ConversionResult::getValue)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位符号转换(返回完整结果)
|
||||
*
|
||||
* @param value 待转换的值
|
||||
* @param srcSymbol 源单位符号
|
||||
* @param tgtSymbol 目标单位符号
|
||||
* @param precision 精度(小数位数)
|
||||
* @return 转换结果(包含值、因子、策略等)
|
||||
*/
|
||||
public UnitConversionUtil.ConversionResult convertBySymbolWithDetails(
|
||||
BigDecimal value, String srcSymbol, String tgtSymbol, int precision) {
|
||||
|
||||
// 加载数据
|
||||
List<UnitConversionDO> conversions = unitConversionMapper.selectList();
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
|
||||
List<UntInfoDO> units = untInfoMapper.selectList();
|
||||
|
||||
// 调用工具类
|
||||
return UnitConversionUtil.convertBySymbol(
|
||||
value, srcSymbol, tgtSymbol, conversions, relations, units, precision
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位名称转换(返回完整结果)
|
||||
*
|
||||
* @param value 待转换的值
|
||||
* @param srcName 源单位名称
|
||||
* @param tgtName 目标单位名称
|
||||
* @param precision 精度(小数位数)
|
||||
* @return 转换结果(包含值、因子、策略等)
|
||||
*/
|
||||
public UnitConversionUtil.ConversionResult convertByNameWithDetails(
|
||||
BigDecimal value, String srcName, String tgtName, int precision) {
|
||||
|
||||
// 加载数据
|
||||
List<UnitConversionDO> conversions = unitConversionMapper.selectList();
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
|
||||
List<UntInfoDO> units = untInfoMapper.selectList();
|
||||
|
||||
// 调用工具类
|
||||
return UnitConversionUtil.convertByName(
|
||||
value, srcName, tgtName, conversions, relations, units, precision
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -59,4 +59,60 @@ public interface UnitConversionService {
|
||||
*/
|
||||
PageResult<UnitConversionDO> getUnitConversionPage(UnitConversionPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 单位转换
|
||||
*
|
||||
* @param convertReqVO 转换请求
|
||||
* @return 转换结果
|
||||
*/
|
||||
UnitConvertRespVO convert(@Valid UnitConvertReqVO convertReqVO);
|
||||
|
||||
/**
|
||||
* 批量单位转换
|
||||
*
|
||||
* @param batchReqVO 批量转换请求
|
||||
* @return 批量转换结果
|
||||
*/
|
||||
BatchUnitConvertRespVO batchConvert(@Valid BatchUnitConvertReqVO batchReqVO);
|
||||
|
||||
/**
|
||||
* 按单位符号转换
|
||||
*
|
||||
* @param reqVO 转换请求
|
||||
* @return 转换结果
|
||||
*/
|
||||
UnitConvertRespVO convertBySymbol(@Valid UnitConvertBySymbolReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 按单位名称转换
|
||||
*
|
||||
* @param reqVO 转换请求
|
||||
* @return 转换结果
|
||||
*/
|
||||
UnitConvertRespVO convertByName(@Valid UnitConvertByNameReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 批量按单位符号转换
|
||||
*
|
||||
* @param reqVO 批量转换请求
|
||||
* @return 批量转换结果
|
||||
*/
|
||||
BatchUnitConvertRespVO batchConvertBySymbol(@Valid BatchUnitConvertBySymbolReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 批量按单位名称转换
|
||||
*
|
||||
* @param reqVO 批量转换请求
|
||||
* @return 批量转换结果
|
||||
*/
|
||||
BatchUnitConvertRespVO batchConvertByName(@Valid BatchUnitConvertByNameReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 校验量纲内所有单位的转换路径
|
||||
*
|
||||
* @param quantityId 量纲ID
|
||||
* @return 校验结果
|
||||
*/
|
||||
UnitConversionValidationRespVO validateConversionPaths(Long quantityId);
|
||||
|
||||
}
|
||||
@@ -14,6 +14,18 @@ import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
|
||||
import com.zt.plat.module.unitmanagement.dal.dao.UnitConversion.UnitConversionMapper;
|
||||
import com.zt.plat.module.unitmanagement.dal.dao.QuantityUnitRelation.QuantityUnitRelationMapper;
|
||||
import com.zt.plat.module.unitmanagement.dal.dao.UntInfo.UntInfoMapper;
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.QuantityUnitRelation.QuantityUnitRelationDO;
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.UntInfo.UntInfoDO;
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.UnitQuantity.UnitQuantityDO;
|
||||
import com.zt.plat.module.unitmanagement.service.UnitQuantity.UnitQuantityService;
|
||||
import com.zt.plat.module.unitmanagement.util.UnitConversionUtil;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.zt.plat.framework.common.util.collection.CollectionUtils.convertList;
|
||||
@@ -27,11 +39,21 @@ import static com.zt.plat.module.unitmanagement.enums.UnitErrorCodeConstants.*;
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class UnitConversionServiceImpl implements UnitConversionService {
|
||||
|
||||
@Resource
|
||||
private UnitConversionMapper unitConversionMapper;
|
||||
|
||||
@Resource
|
||||
private QuantityUnitRelationMapper quantityUnitRelationMapper;
|
||||
|
||||
@Resource
|
||||
private UntInfoMapper untInfoMapper;
|
||||
|
||||
@Resource
|
||||
private UnitQuantityService unitQuantityService;
|
||||
|
||||
@Override
|
||||
public UnitConversionRespVO createUnitConversion(UnitConversionSaveReqVO createReqVO) {
|
||||
// 插入
|
||||
@@ -89,4 +111,508 @@ public class UnitConversionServiceImpl implements UnitConversionService {
|
||||
return unitConversionMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnitConvertRespVO convert(UnitConvertReqVO convertReqVO) {
|
||||
log.info("开始单位转换: 源单位ID={}, 目标单位ID={}, 值={}",
|
||||
convertReqVO.getSrcUntId(), convertReqVO.getTgtUntId(), convertReqVO.getValue());
|
||||
|
||||
// 1. 查询所有转换规则和关联关系
|
||||
List<UnitConversionDO> conversions = unitConversionMapper.selectList();
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
|
||||
|
||||
// 2. 使用工具类进行转换
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convert(
|
||||
convertReqVO.getValue(),
|
||||
convertReqVO.getSrcUntId(),
|
||||
convertReqVO.getTgtUntId(),
|
||||
conversions,
|
||||
relations,
|
||||
convertReqVO.getPrecision() != null ? convertReqVO.getPrecision() : 6
|
||||
);
|
||||
|
||||
// 3. 查询单位信息
|
||||
UntInfoDO srcUnit = untInfoMapper.selectById(convertReqVO.getSrcUntId());
|
||||
UntInfoDO tgtUnit = untInfoMapper.selectById(convertReqVO.getTgtUntId());
|
||||
|
||||
// 4. 构建响应
|
||||
return UnitConvertRespVO.builder()
|
||||
.srcUntId(convertReqVO.getSrcUntId())
|
||||
.srcUntName(srcUnit != null ? srcUnit.getName() : null)
|
||||
.srcUntSmb(srcUnit != null ? srcUnit.getSmb() : null)
|
||||
.tgtUntId(convertReqVO.getTgtUntId())
|
||||
.tgtUntName(tgtUnit != null ? tgtUnit.getName() : null)
|
||||
.tgtUntSmb(tgtUnit != null ? tgtUnit.getSmb() : null)
|
||||
.originalValue(convertReqVO.getValue())
|
||||
.convertedValue(result.getValue())
|
||||
.factor(result.getFactor())
|
||||
.formula(result.getFormula())
|
||||
.strategy(result.getStrategy().name())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BatchUnitConvertRespVO batchConvert(BatchUnitConvertReqVO batchReqVO) {
|
||||
log.info("开始批量单位转换: 转换项数量={}, 忽略错误={}",
|
||||
batchReqVO.getItems().size(), batchReqVO.getIgnoreErrors());
|
||||
|
||||
List<BatchUnitConvertRespVO.UnitConvertResultItem> results = new ArrayList<>();
|
||||
int successCount = 0;
|
||||
int failureCount = 0;
|
||||
|
||||
for (UnitConvertReqVO item : batchReqVO.getItems()) {
|
||||
try {
|
||||
// 执行转换
|
||||
UnitConvertRespVO convertResult = convert(item);
|
||||
|
||||
// 构建成功结果
|
||||
results.add(BatchUnitConvertRespVO.UnitConvertResultItem.builder()
|
||||
.success(true)
|
||||
.data(convertResult)
|
||||
.request(item)
|
||||
.build());
|
||||
|
||||
successCount++;
|
||||
} catch (Exception e) {
|
||||
log.warn("单位转换失败: 源单位ID={}, 目标单位ID={}, 错误={}",
|
||||
item.getSrcUntId(), item.getTgtUntId(), e.getMessage());
|
||||
|
||||
// 构建失败结果
|
||||
results.add(BatchUnitConvertRespVO.UnitConvertResultItem.builder()
|
||||
.success(false)
|
||||
.errorMessage(e.getMessage())
|
||||
.request(item)
|
||||
.build());
|
||||
|
||||
failureCount++;
|
||||
|
||||
// 如果不忽略错误,直接抛出异常
|
||||
if (!Boolean.TRUE.equals(batchReqVO.getIgnoreErrors())) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BatchUnitConvertRespVO.builder()
|
||||
.results(results)
|
||||
.successCount(successCount)
|
||||
.failureCount(failureCount)
|
||||
.totalCount(batchReqVO.getItems().size())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnitConvertRespVO convertBySymbol(UnitConvertBySymbolReqVO reqVO) {
|
||||
log.info("开始按符号转换: 源单位符号={}, 目标单位符号={}, 值={}",
|
||||
reqVO.getSrcUnitSymbol(), reqVO.getTgtUnitSymbol(), reqVO.getValue());
|
||||
|
||||
// 1. 查询所有转换规则、关联关系和单位信息
|
||||
List<UnitConversionDO> conversions = unitConversionMapper.selectList();
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
|
||||
List<UntInfoDO> units = untInfoMapper.selectList();
|
||||
|
||||
// 2. 使用工具类进行转换
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convertBySymbol(
|
||||
reqVO.getValue(),
|
||||
reqVO.getSrcUnitSymbol(),
|
||||
reqVO.getTgtUnitSymbol(),
|
||||
conversions,
|
||||
relations,
|
||||
units,
|
||||
reqVO.getPrecision() != null ? reqVO.getPrecision() : 6
|
||||
);
|
||||
|
||||
// 3. 构建响应
|
||||
return UnitConvertRespVO.builder()
|
||||
.srcUntName(reqVO.getSrcUnitSymbol())
|
||||
.srcUntSmb(reqVO.getSrcUnitSymbol())
|
||||
.tgtUntName(reqVO.getTgtUnitSymbol())
|
||||
.tgtUntSmb(reqVO.getTgtUnitSymbol())
|
||||
.originalValue(reqVO.getValue())
|
||||
.convertedValue(result.getValue())
|
||||
.factor(result.getFactor())
|
||||
.formula(result.getFormula())
|
||||
.strategy(result.getStrategy().name())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnitConvertRespVO convertByName(UnitConvertByNameReqVO reqVO) {
|
||||
log.info("开始按名称转换: 源单位名称={}, 目标单位名称={}, 值={}",
|
||||
reqVO.getSrcUnitName(), reqVO.getTgtUnitName(), reqVO.getValue());
|
||||
|
||||
// 1. 查询所有转换规则、关联关系和单位信息
|
||||
List<UnitConversionDO> conversions = unitConversionMapper.selectList();
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
|
||||
List<UntInfoDO> units = untInfoMapper.selectList();
|
||||
|
||||
// 2. 使用工具类进行转换
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convertByName(
|
||||
reqVO.getValue(),
|
||||
reqVO.getSrcUnitName(),
|
||||
reqVO.getTgtUnitName(),
|
||||
conversions,
|
||||
relations,
|
||||
units,
|
||||
reqVO.getPrecision() != null ? reqVO.getPrecision() : 6
|
||||
);
|
||||
|
||||
// 3. 构建响应
|
||||
return UnitConvertRespVO.builder()
|
||||
.srcUntName(reqVO.getSrcUnitName())
|
||||
.tgtUntName(reqVO.getTgtUnitName())
|
||||
.originalValue(reqVO.getValue())
|
||||
.convertedValue(result.getValue())
|
||||
.factor(result.getFactor())
|
||||
.formula(result.getFormula())
|
||||
.strategy(result.getStrategy().name())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BatchUnitConvertRespVO batchConvertBySymbol(BatchUnitConvertBySymbolReqVO reqVO) {
|
||||
log.info("开始批量按符号转换: 源单位符号={}, 目标单位符号={}, 值数量={}",
|
||||
reqVO.getSrcUnitSymbol(), reqVO.getTgtUnitSymbol(), reqVO.getValues().size());
|
||||
|
||||
List<BatchUnitConvertRespVO.UnitConvertResultItem> results = new ArrayList<>();
|
||||
int successCount = 0;
|
||||
int failureCount = 0;
|
||||
|
||||
// 1. 查询所有转换规则、关联关系和单位信息(只查询一次)
|
||||
List<UnitConversionDO> conversions = unitConversionMapper.selectList();
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
|
||||
List<UntInfoDO> units = untInfoMapper.selectList();
|
||||
|
||||
for (BigDecimal value : reqVO.getValues()) {
|
||||
try {
|
||||
// 2. 使用工具类进行转换
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convertBySymbol(
|
||||
value,
|
||||
reqVO.getSrcUnitSymbol(),
|
||||
reqVO.getTgtUnitSymbol(),
|
||||
conversions,
|
||||
relations,
|
||||
units,
|
||||
reqVO.getPrecision() != null ? reqVO.getPrecision() : 6
|
||||
);
|
||||
|
||||
// 3. 构建成功结果
|
||||
results.add(BatchUnitConvertRespVO.UnitConvertResultItem.builder()
|
||||
.success(true)
|
||||
.data(UnitConvertRespVO.builder()
|
||||
.srcUntSmb(reqVO.getSrcUnitSymbol())
|
||||
.tgtUntSmb(reqVO.getTgtUnitSymbol())
|
||||
.originalValue(value)
|
||||
.convertedValue(result.getValue())
|
||||
.factor(result.getFactor())
|
||||
.strategy(result.getStrategy().name())
|
||||
.build())
|
||||
.build());
|
||||
successCount++;
|
||||
} catch (Exception e) {
|
||||
log.warn("按符号转换失败: 源单位符号={}, 目标单位符号={}, 值={}, 错误={}",
|
||||
reqVO.getSrcUnitSymbol(), reqVO.getTgtUnitSymbol(), value, e.getMessage());
|
||||
|
||||
// 4. 构建失败结果
|
||||
results.add(BatchUnitConvertRespVO.UnitConvertResultItem.builder()
|
||||
.success(false)
|
||||
.errorMessage(e.getMessage())
|
||||
.build());
|
||||
failureCount++;
|
||||
|
||||
// 5. 如果不忽略错误,直接抛出异常
|
||||
if (!Boolean.TRUE.equals(reqVO.getIgnoreErrors())) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BatchUnitConvertRespVO.builder()
|
||||
.results(results)
|
||||
.successCount(successCount)
|
||||
.failureCount(failureCount)
|
||||
.totalCount(reqVO.getValues().size())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BatchUnitConvertRespVO batchConvertByName(BatchUnitConvertByNameReqVO reqVO) {
|
||||
log.info("开始批量按名称转换: 源单位名称={}, 目标单位名称={}, 值数量={}",
|
||||
reqVO.getSrcUnitName(), reqVO.getTgtUnitName(), reqVO.getValues().size());
|
||||
|
||||
List<BatchUnitConvertRespVO.UnitConvertResultItem> results = new ArrayList<>();
|
||||
int successCount = 0;
|
||||
int failureCount = 0;
|
||||
|
||||
// 1. 查询所有转换规则、关联关系和单位信息(只查询一次)
|
||||
List<UnitConversionDO> conversions = unitConversionMapper.selectList();
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
|
||||
List<UntInfoDO> units = untInfoMapper.selectList();
|
||||
|
||||
for (BigDecimal value : reqVO.getValues()) {
|
||||
try {
|
||||
// 2. 使用工具类进行转换
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convertByName(
|
||||
value,
|
||||
reqVO.getSrcUnitName(),
|
||||
reqVO.getTgtUnitName(),
|
||||
conversions,
|
||||
relations,
|
||||
units,
|
||||
reqVO.getPrecision() != null ? reqVO.getPrecision() : 6
|
||||
);
|
||||
|
||||
// 3. 构建成功结果
|
||||
results.add(BatchUnitConvertRespVO.UnitConvertResultItem.builder()
|
||||
.success(true)
|
||||
.data(UnitConvertRespVO.builder()
|
||||
.srcUntName(reqVO.getSrcUnitName())
|
||||
.tgtUntName(reqVO.getTgtUnitName())
|
||||
.originalValue(value)
|
||||
.convertedValue(result.getValue())
|
||||
.factor(result.getFactor())
|
||||
.strategy(result.getStrategy().name())
|
||||
.build())
|
||||
.build());
|
||||
successCount++;
|
||||
} catch (Exception e) {
|
||||
log.warn("按名称转换失败: 源单位名称={}, 目标单位名称={}, 值={}, 错误={}",
|
||||
reqVO.getSrcUnitName(), reqVO.getTgtUnitName(), value, e.getMessage());
|
||||
|
||||
// 4. 构建失败结果
|
||||
results.add(BatchUnitConvertRespVO.UnitConvertResultItem.builder()
|
||||
.success(false)
|
||||
.errorMessage(e.getMessage())
|
||||
.build());
|
||||
failureCount++;
|
||||
|
||||
// 5. 如果不忽略错误,直接抛出异常
|
||||
if (!Boolean.TRUE.equals(reqVO.getIgnoreErrors())) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BatchUnitConvertRespVO.builder()
|
||||
.results(results)
|
||||
.successCount(successCount)
|
||||
.failureCount(failureCount)
|
||||
.totalCount(reqVO.getValues().size())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnitConversionValidationRespVO validateConversionPaths(Long quantityId) {
|
||||
log.info("开始校验量纲 {} 的转换路径", quantityId);
|
||||
|
||||
// 1. 查询量纲信息
|
||||
UnitQuantityDO quantity = unitQuantityService.getUnitQuantity(quantityId);
|
||||
if (quantity == null) {
|
||||
throw exception(UNIT_QUANTITY_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 2. 查询该量纲下的所有单位
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList(
|
||||
new LambdaQueryWrapperX<QuantityUnitRelationDO>()
|
||||
.eq(QuantityUnitRelationDO::getUntQtyId, quantityId)
|
||||
);
|
||||
|
||||
if (CollUtil.isEmpty(relations)) {
|
||||
return buildEmptyValidationResult(quantityId, quantity);
|
||||
}
|
||||
|
||||
// 3. 获取单位详细信息
|
||||
List<Long> unitIds = relations.stream()
|
||||
.map(QuantityUnitRelationDO::getUntId)
|
||||
.collect(Collectors.toList());
|
||||
List<UntInfoDO> units = untInfoMapper.selectByIds(unitIds);
|
||||
Map<Long, UntInfoDO> unitMap = units.stream()
|
||||
.collect(Collectors.toMap(UntInfoDO::getId, u -> u));
|
||||
|
||||
// 4. 找到基准单位
|
||||
QuantityUnitRelationDO baseRelation = relations.stream()
|
||||
.filter(r -> r.getIsBse() == 1)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
UnitConversionValidationRespVO.BaseUnitInfo baseUnitInfo = null;
|
||||
Long baseUnitId = null;
|
||||
if (baseRelation != null) {
|
||||
UntInfoDO baseUnit = unitMap.get(baseRelation.getUntId());
|
||||
baseUnitId = baseRelation.getUntId();
|
||||
if (baseUnit != null) {
|
||||
baseUnitInfo = UnitConversionValidationRespVO.BaseUnitInfo.builder()
|
||||
.unitId(baseUnit.getId())
|
||||
.unitName(baseUnit.getName())
|
||||
.unitSymbol(baseUnit.getSmb())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 查询该量纲下的所有转换规则
|
||||
List<UnitConversionDO> conversions = unitConversionMapper.selectList(
|
||||
new LambdaQueryWrapperX<UnitConversionDO>()
|
||||
.eq(UnitConversionDO::getUntQtyId, quantityId)
|
||||
);
|
||||
|
||||
// 6. 检查所有单位对之间的转换路径(两两互相转换)
|
||||
List<UnitConversionValidationRespVO.UnconvertibleUnitInfo> unconvertibleUnits = new ArrayList<>();
|
||||
List<UnitConversionValidationRespVO.ConversionPathInfo> conversionPaths = new ArrayList<>();
|
||||
|
||||
// 统计:能够互相转换的单位数量
|
||||
Set<Long> fullyConvertibleUnits = new HashSet<>();
|
||||
|
||||
// 遍历所有单位对
|
||||
for (int i = 0; i < units.size(); i++) {
|
||||
UntInfoDO srcUnit = units.get(i);
|
||||
boolean canConvertToAll = true;
|
||||
|
||||
for (int j = 0; j < units.size(); j++) {
|
||||
if (i == j) continue; // 跳过自己
|
||||
|
||||
UntInfoDO tgtUnit = units.get(j);
|
||||
|
||||
// 尝试转换(使用工具类)
|
||||
boolean canConvert = canConvert(srcUnit.getId(), tgtUnit.getId(), conversions, relations, baseUnitId);
|
||||
|
||||
if (!canConvert) {
|
||||
canConvertToAll = false;
|
||||
// 只记录第一个方向的失败(避免重复:A→B 和 B→A)
|
||||
if (i < j) {
|
||||
unconvertibleUnits.add(UnitConversionValidationRespVO.UnconvertibleUnitInfo.builder()
|
||||
.unitId(srcUnit.getId())
|
||||
.unitName(srcUnit.getName())
|
||||
.unitSymbol(srcUnit.getSmb())
|
||||
.reason(String.format("无法转换到 %s", tgtUnit.getName()))
|
||||
.build());
|
||||
}
|
||||
} else {
|
||||
// 记录转换路径(只记录到基准单位的路径,避免太多)
|
||||
if (baseUnitId != null && tgtUnit.getId().equals(baseUnitId)) {
|
||||
String strategy = getConversionStrategy(srcUnit.getId(), tgtUnit.getId(), conversions, baseUnitId);
|
||||
conversionPaths.add(UnitConversionValidationRespVO.ConversionPathInfo.builder()
|
||||
.srcUnitId(srcUnit.getId())
|
||||
.srcUnitName(srcUnit.getName())
|
||||
.tgtUnitId(tgtUnit.getId())
|
||||
.tgtUnitName(tgtUnit.getName())
|
||||
.hasDirect(strategy.equals("DIRECT"))
|
||||
.hasViaBase(strategy.equals("VIA_BASE_UNIT"))
|
||||
.pathDescription(srcUnit.getName() + " → " + tgtUnit.getName() +
|
||||
(strategy.equals("DIRECT") ? " (直接转换)" : " (通过基准单位)"))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canConvertToAll) {
|
||||
fullyConvertibleUnits.add(srcUnit.getId());
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 构建响应
|
||||
return UnitConversionValidationRespVO.builder()
|
||||
.quantityId(quantityId)
|
||||
.quantityName(quantity.getName())
|
||||
.quantitySymbol(quantity.getSymbol())
|
||||
.totalUnits(units.size())
|
||||
.convertibleUnits(fullyConvertibleUnits.size())
|
||||
.unconvertibleUnits(units.size() - fullyConvertibleUnits.size())
|
||||
.allConvertible(fullyConvertibleUnits.size() == units.size())
|
||||
.baseUnit(baseUnitInfo)
|
||||
.unconvertibleUnitList(unconvertibleUnits)
|
||||
.conversionPaths(conversionPaths)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查两个单位是否能够转换(考虑反向推导)
|
||||
*/
|
||||
private boolean canConvert(Long srcUnitId, Long tgtUnitId,
|
||||
List<UnitConversionDO> conversions,
|
||||
List<QuantityUnitRelationDO> relations,
|
||||
Long baseUnitId) {
|
||||
// 1. 检查直接转换(正向)
|
||||
boolean hasDirectForward = conversions.stream()
|
||||
.anyMatch(c -> c.getSrcUntId().equals(srcUnitId) && c.getTgtUntId().equals(tgtUnitId));
|
||||
if (hasDirectForward) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. 检查直接转换(反向,可以推导)
|
||||
boolean hasDirectReverse = conversions.stream()
|
||||
.anyMatch(c -> c.getSrcUntId().equals(tgtUnitId) && c.getTgtUntId().equals(srcUnitId));
|
||||
if (hasDirectReverse) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 3. 检查通过基准单位的间接转换
|
||||
if (baseUnitId == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果源单位是基准单位
|
||||
if (srcUnitId.equals(baseUnitId)) {
|
||||
// 检查是否有 基准 → 目标 的转换规则(正向或反向)
|
||||
boolean hasBaseToTgt = conversions.stream()
|
||||
.anyMatch(c -> c.getSrcUntId().equals(baseUnitId) && c.getTgtUntId().equals(tgtUnitId));
|
||||
boolean hasTgtToBase = conversions.stream()
|
||||
.anyMatch(c -> c.getSrcUntId().equals(tgtUnitId) && c.getTgtUntId().equals(baseUnitId));
|
||||
return hasBaseToTgt || hasTgtToBase;
|
||||
}
|
||||
|
||||
// 如果目标单位是基准单位
|
||||
if (tgtUnitId.equals(baseUnitId)) {
|
||||
// 检查是否有 源 → 基准 的转换规则(正向或反向)
|
||||
boolean hasSrcToBase = conversions.stream()
|
||||
.anyMatch(c -> c.getSrcUntId().equals(srcUnitId) && c.getTgtUntId().equals(baseUnitId));
|
||||
boolean hasBaseToSrc = conversions.stream()
|
||||
.anyMatch(c -> c.getSrcUntId().equals(baseUnitId) && c.getTgtUntId().equals(srcUnitId));
|
||||
return hasSrcToBase || hasBaseToSrc;
|
||||
}
|
||||
|
||||
// 两者都不是基准单位,需要两步转换:源 → 基准 → 目标
|
||||
// 检查 源 → 基准(正向或反向)
|
||||
boolean srcToBase = conversions.stream()
|
||||
.anyMatch(c -> c.getSrcUntId().equals(srcUnitId) && c.getTgtUntId().equals(baseUnitId));
|
||||
boolean baseToSrc = conversions.stream()
|
||||
.anyMatch(c -> c.getSrcUntId().equals(baseUnitId) && c.getTgtUntId().equals(srcUnitId));
|
||||
|
||||
// 检查 基准 → 目标(正向或反向)
|
||||
boolean baseToTgt = conversions.stream()
|
||||
.anyMatch(c -> c.getSrcUntId().equals(baseUnitId) && c.getTgtUntId().equals(tgtUnitId));
|
||||
boolean tgtToBase = conversions.stream()
|
||||
.anyMatch(c -> c.getSrcUntId().equals(tgtUnitId) && c.getTgtUntId().equals(baseUnitId));
|
||||
|
||||
return (srcToBase || baseToSrc) && (baseToTgt || tgtToBase);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取转换策略
|
||||
*/
|
||||
private String getConversionStrategy(Long srcUnitId, Long tgtUnitId,
|
||||
List<UnitConversionDO> conversions,
|
||||
Long baseUnitId) {
|
||||
// 检查直接转换
|
||||
boolean hasDirect = conversions.stream()
|
||||
.anyMatch(c -> c.getSrcUntId().equals(srcUnitId) && c.getTgtUntId().equals(tgtUnitId));
|
||||
if (hasDirect) {
|
||||
return "DIRECT";
|
||||
}
|
||||
return "VIA_BASE_UNIT";
|
||||
}
|
||||
|
||||
private UnitConversionValidationRespVO buildEmptyValidationResult(Long quantityId, UnitQuantityDO quantity) {
|
||||
return UnitConversionValidationRespVO.builder()
|
||||
.quantityId(quantityId)
|
||||
.quantityName(quantity.getName())
|
||||
.quantitySymbol(quantity.getSymbol())
|
||||
.totalUnits(0)
|
||||
.convertibleUnits(0)
|
||||
.unconvertibleUnits(0)
|
||||
.allConvertible(true)
|
||||
.baseUnit(null)
|
||||
.unconvertibleUnitList(new ArrayList<>())
|
||||
.conversionPaths(new ArrayList<>())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -59,4 +59,11 @@ public interface UnitQuantityService {
|
||||
*/
|
||||
PageResult<UnitQuantityDO> getUnitQuantityPage(UnitQuantityPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 获取量纲及单位树
|
||||
*
|
||||
* @return 量纲及单位树列表
|
||||
*/
|
||||
List<UnitQuantityTreeRespVO> getUnitQuantityTree();
|
||||
|
||||
}
|
||||
@@ -14,6 +14,11 @@ import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
|
||||
import com.zt.plat.module.unitmanagement.dal.dao.UnitQuantity.UnitQuantityMapper;
|
||||
import com.zt.plat.module.unitmanagement.dal.dao.QuantityUnitRelation.QuantityUnitRelationMapper;
|
||||
import com.zt.plat.module.unitmanagement.dal.dao.UntInfo.UntInfoMapper;
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.QuantityUnitRelation.QuantityUnitRelationDO;
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.UntInfo.UntInfoDO;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.zt.plat.framework.common.util.collection.CollectionUtils.convertList;
|
||||
@@ -32,6 +37,12 @@ public class UnitQuantityServiceImpl implements UnitQuantityService {
|
||||
@Resource
|
||||
private UnitQuantityMapper unitQuantityMapper;
|
||||
|
||||
@Resource
|
||||
private QuantityUnitRelationMapper quantityUnitRelationMapper;
|
||||
|
||||
@Resource
|
||||
private UntInfoMapper untInfoMapper;
|
||||
|
||||
@Override
|
||||
public UnitQuantityRespVO createUnitQuantity(UnitQuantitySaveReqVO createReqVO) {
|
||||
// 插入
|
||||
@@ -89,4 +100,50 @@ public class UnitQuantityServiceImpl implements UnitQuantityService {
|
||||
return unitQuantityMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UnitQuantityTreeRespVO> getUnitQuantityTree() {
|
||||
// 1. 查询所有量纲
|
||||
List<UnitQuantityDO> quantities = unitQuantityMapper.selectList();
|
||||
|
||||
// 2. 查询所有关联关系
|
||||
List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
|
||||
|
||||
// 3. 查询所有单位
|
||||
List<UntInfoDO> units = untInfoMapper.selectList();
|
||||
Map<Long, UntInfoDO> unitMap = units.stream()
|
||||
.collect(Collectors.toMap(UntInfoDO::getId, u -> u));
|
||||
|
||||
// 4. 组装树形结构
|
||||
return quantities.stream().map(quantity -> {
|
||||
UnitQuantityTreeRespVO treeVO = new UnitQuantityTreeRespVO();
|
||||
treeVO.setId(quantity.getId());
|
||||
treeVO.setName(quantity.getName());
|
||||
treeVO.setSymbol(quantity.getSymbol());
|
||||
treeVO.setDsp(quantity.getDsp());
|
||||
|
||||
// 获取该量纲下的所有单位
|
||||
List<UnitQuantityTreeRespVO.UnitItemVO> unitItems = relations.stream()
|
||||
.filter(r -> r.getUntQtyId().equals(quantity.getId()))
|
||||
.map(r -> {
|
||||
UnitQuantityTreeRespVO.UnitItemVO unitItem = new UnitQuantityTreeRespVO.UnitItemVO();
|
||||
unitItem.setRelationId(r.getId());
|
||||
unitItem.setId(r.getUntId());
|
||||
unitItem.setIsBse(r.getIsBse());
|
||||
|
||||
// 填充单位信息
|
||||
UntInfoDO unit = unitMap.get(r.getUntId());
|
||||
if (unit != null) {
|
||||
unitItem.setName(unit.getName());
|
||||
unitItem.setSmb(unit.getSmb());
|
||||
}
|
||||
|
||||
return unitItem;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
treeVO.setUnits(unitItems);
|
||||
return treeVO;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,407 @@
|
||||
package com.zt.plat.module.unitmanagement.util;
|
||||
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.UnitConversion.UnitConversionDO;
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.QuantityUnitRelation.QuantityUnitRelationDO;
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.UntInfo.UntInfoDO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.zt.plat.module.unitmanagement.enums.UnitErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 单位转换工具类
|
||||
*
|
||||
* <p>支持三种转换策略:
|
||||
* <ul>
|
||||
* <li>直接转换:使用预定义的转换规则</li>
|
||||
* <li>基准单位转换:通过基准单位进行中转</li>
|
||||
* <li>公式转换:使用自定义转换公式</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author 系统
|
||||
*/
|
||||
@Slf4j
|
||||
public class UnitConversionUtil {
|
||||
|
||||
/**
|
||||
* 转换策略枚举
|
||||
*/
|
||||
public enum ConversionStrategy {
|
||||
/** 直接转换 */
|
||||
DIRECT,
|
||||
/** 基准单位转换 */
|
||||
VIA_BASE_UNIT,
|
||||
/** 公式转换 */
|
||||
FORMULA,
|
||||
/** 无法转换 */
|
||||
NONE
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换结果
|
||||
*/
|
||||
public static class ConversionResult {
|
||||
private final BigDecimal value;
|
||||
private final BigDecimal factor;
|
||||
private final ConversionStrategy strategy;
|
||||
private final String formula;
|
||||
|
||||
public ConversionResult(BigDecimal value, BigDecimal factor, ConversionStrategy strategy, String formula) {
|
||||
this.value = value;
|
||||
this.factor = factor;
|
||||
this.strategy = strategy;
|
||||
this.formula = formula;
|
||||
}
|
||||
|
||||
public BigDecimal getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public BigDecimal getFactor() {
|
||||
return factor;
|
||||
}
|
||||
|
||||
public ConversionStrategy getStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
public String getFormula() {
|
||||
return formula;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 单位转换
|
||||
*
|
||||
* @param value 待转换的值
|
||||
* @param srcUntId 源单位ID
|
||||
* @param tgtUntId 目标单位ID
|
||||
* @param conversions 转换规则列表
|
||||
* @param relations 量纲-单位关联关系列表
|
||||
* @param precision 精度(小数位数)
|
||||
* @return 转换结果
|
||||
*/
|
||||
public static ConversionResult convert(
|
||||
BigDecimal value,
|
||||
Long srcUntId,
|
||||
Long tgtUntId,
|
||||
List<UnitConversionDO> conversions,
|
||||
List<QuantityUnitRelationDO> relations,
|
||||
int precision) {
|
||||
|
||||
// 1. 如果源单位和目标单位相同,直接返回
|
||||
if (srcUntId.equals(tgtUntId)) {
|
||||
return new ConversionResult(value, BigDecimal.ONE, ConversionStrategy.DIRECT, "相同单位,无需转换");
|
||||
}
|
||||
|
||||
// 2. 尝试直接转换
|
||||
ConversionResult directResult = tryDirectConversion(value, srcUntId, tgtUntId, conversions, precision);
|
||||
if (directResult != null) {
|
||||
return directResult;
|
||||
}
|
||||
|
||||
// 3. 尝试通过基准单位转换
|
||||
ConversionResult viaBaseResult = tryViaBaseUnitConversion(value, srcUntId, tgtUntId, conversions, relations, precision);
|
||||
if (viaBaseResult != null) {
|
||||
return viaBaseResult;
|
||||
}
|
||||
|
||||
// 4. 无法转换 - 抛出业务异常
|
||||
log.warn("无法找到从单位 {} 到单位 {} 的转换路径", srcUntId, tgtUntId);
|
||||
throw exception(UNIT_CONVERSION_PATH_NOT_FOUND,
|
||||
"ID:" + srcUntId, "ID:" + tgtUntId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试直接转换(支持自动反向推导)
|
||||
*/
|
||||
private static ConversionResult tryDirectConversion(
|
||||
BigDecimal value,
|
||||
Long srcUntId,
|
||||
Long tgtUntId,
|
||||
List<UnitConversionDO> conversions,
|
||||
int precision) {
|
||||
|
||||
// 1. 查找正向转换规则:源 → 目标
|
||||
UnitConversionDO forwardConversion = conversions.stream()
|
||||
.filter(c -> c.getSrcUntId().equals(srcUntId) && c.getTgtUntId().equals(tgtUntId))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (forwardConversion != null) {
|
||||
BigDecimal factor = forwardConversion.getFctr();
|
||||
BigDecimal result = value.multiply(factor).setScale(precision, RoundingMode.HALF_UP);
|
||||
String formula = forwardConversion.getFmu() != null ? forwardConversion.getFmu() :
|
||||
String.format("value * %s", factor);
|
||||
|
||||
log.debug("直接转换(正向): {} (单位{}) * {} = {} (单位{})", value, srcUntId, factor, result, tgtUntId);
|
||||
return new ConversionResult(result, factor, ConversionStrategy.DIRECT, formula);
|
||||
}
|
||||
|
||||
// 2. 查找反向转换规则:目标 → 源,然后取倒数
|
||||
UnitConversionDO reverseConversion = conversions.stream()
|
||||
.filter(c -> c.getSrcUntId().equals(tgtUntId) && c.getTgtUntId().equals(srcUntId))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (reverseConversion != null) {
|
||||
// 反向系数:如果 目标→源 的系数是 f,则 源→目标 的系数是 1/f
|
||||
BigDecimal reverseFactor = reverseConversion.getFctr();
|
||||
BigDecimal factor = BigDecimal.ONE.divide(reverseFactor, Math.max(precision + 10, 20), RoundingMode.HALF_UP);
|
||||
BigDecimal result = value.multiply(factor).setScale(precision, RoundingMode.HALF_UP);
|
||||
String formula = String.format("value / %s (反向推导)", reverseFactor);
|
||||
|
||||
log.debug("直接转换(反向推导): {} (单位{}) / {} = {} (单位{})", value, srcUntId, reverseFactor, result, tgtUntId);
|
||||
return new ConversionResult(result, factor, ConversionStrategy.DIRECT, formula);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试通过基准单位转换
|
||||
*/
|
||||
private static ConversionResult tryViaBaseUnitConversion(
|
||||
BigDecimal value,
|
||||
Long srcUntId,
|
||||
Long tgtUntId,
|
||||
List<UnitConversionDO> conversions,
|
||||
List<QuantityUnitRelationDO> relations,
|
||||
int precision) {
|
||||
|
||||
// 1. 找到源单位和目标单位的量纲
|
||||
QuantityUnitRelationDO srcRelation = relations.stream()
|
||||
.filter(r -> r.getUntId().equals(srcUntId))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
QuantityUnitRelationDO tgtRelation = relations.stream()
|
||||
.filter(r -> r.getUntId().equals(tgtUntId))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (srcRelation == null || tgtRelation == null) {
|
||||
log.warn("找不到单位 {} 或 {} 的量纲关联关系", srcUntId, tgtUntId);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2. 检查是否属于同一量纲
|
||||
if (!srcRelation.getUntQtyId().equals(tgtRelation.getUntQtyId())) {
|
||||
log.warn("单位 {} 和 {} 不属于同一量纲", srcUntId, tgtUntId);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 3. 找到基准单位
|
||||
Long quantityId = srcRelation.getUntQtyId();
|
||||
QuantityUnitRelationDO baseRelation = relations.stream()
|
||||
.filter(r -> r.getUntQtyId().equals(quantityId) && r.getIsBse() == 1)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (baseRelation == null) {
|
||||
log.warn("量纲 {} 没有设置基准单位", quantityId);
|
||||
return null;
|
||||
}
|
||||
|
||||
Long baseUnitId = baseRelation.getUntId();
|
||||
|
||||
// 4. 源单位 → 基准单位
|
||||
BigDecimal toBaseValue;
|
||||
BigDecimal toBaseFactor;
|
||||
if (srcUntId.equals(baseUnitId)) {
|
||||
toBaseValue = value;
|
||||
toBaseFactor = BigDecimal.ONE;
|
||||
} else {
|
||||
ConversionResult toBaseResult = tryDirectConversion(value, srcUntId, baseUnitId, conversions, precision);
|
||||
if (toBaseResult == null) {
|
||||
log.warn("无法从源单位 {} 转换到基准单位 {}", srcUntId, baseUnitId);
|
||||
return null;
|
||||
}
|
||||
toBaseValue = toBaseResult.getValue();
|
||||
toBaseFactor = toBaseResult.getFactor();
|
||||
}
|
||||
|
||||
// 5. 基准单位 → 目标单位
|
||||
BigDecimal finalValue;
|
||||
BigDecimal fromBaseFactor;
|
||||
if (tgtUntId.equals(baseUnitId)) {
|
||||
finalValue = toBaseValue;
|
||||
fromBaseFactor = BigDecimal.ONE;
|
||||
} else {
|
||||
ConversionResult fromBaseResult = tryDirectConversion(toBaseValue, baseUnitId, tgtUntId, conversions, precision);
|
||||
if (fromBaseResult == null) {
|
||||
log.warn("无法从基准单位 {} 转换到目标单位 {}", baseUnitId, tgtUntId);
|
||||
return null;
|
||||
}
|
||||
finalValue = fromBaseResult.getValue();
|
||||
fromBaseFactor = fromBaseResult.getFactor();
|
||||
}
|
||||
|
||||
// 6. 计算总转换因子
|
||||
BigDecimal totalFactor = toBaseFactor.multiply(fromBaseFactor);
|
||||
String formula = String.format("通过基准单位(ID:%d): value * %s * %s", baseUnitId, toBaseFactor, fromBaseFactor);
|
||||
|
||||
log.debug("基准单位转换: {} (单位{}) → {} (基准{}) → {} (单位{})",
|
||||
value, srcUntId, toBaseValue, baseUnitId, finalValue, tgtUntId);
|
||||
|
||||
return new ConversionResult(finalValue, totalFactor, ConversionStrategy.VIA_BASE_UNIT, formula);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量转换
|
||||
*
|
||||
* @param values 待转换的值列表
|
||||
* @param srcUntId 源单位ID
|
||||
* @param tgtUntId 目标单位ID
|
||||
* @param conversions 转换规则列表
|
||||
* @param relations 量纲-单位关联关系列表
|
||||
* @param precision 精度(小数位数)
|
||||
* @return 转换结果列表
|
||||
*/
|
||||
public static List<ConversionResult> batchConvert(
|
||||
List<BigDecimal> values,
|
||||
Long srcUntId,
|
||||
Long tgtUntId,
|
||||
List<UnitConversionDO> conversions,
|
||||
List<QuantityUnitRelationDO> relations,
|
||||
int precision) {
|
||||
|
||||
return values.stream()
|
||||
.map(value -> convert(value, srcUntId, tgtUntId, conversions, relations, precision))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位符号转换(推荐使用)
|
||||
*
|
||||
* @param value 待转换的值
|
||||
* @param srcUnitSymbol 源单位符号(如: "kg", "m", "km")
|
||||
* @param tgtUnitSymbol 目标单位符号
|
||||
* @param conversions 转换规则列表
|
||||
* @param relations 量纲-单位关联关系列表
|
||||
* @param units 单位信息列表
|
||||
* @param precision 精度(小数位数)
|
||||
* @return 转换结果
|
||||
*/
|
||||
public static ConversionResult convertBySymbol(
|
||||
BigDecimal value,
|
||||
String srcUnitSymbol,
|
||||
String tgtUnitSymbol,
|
||||
List<UnitConversionDO> conversions,
|
||||
List<QuantityUnitRelationDO> relations,
|
||||
List<UntInfoDO> units,
|
||||
int precision) {
|
||||
|
||||
// 1. 根据符号查找单位
|
||||
UntInfoDO srcUnit = units.stream()
|
||||
.filter(u -> u.getSmb() != null && u.getSmb().equals(srcUnitSymbol))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> exception(UNIT_NOT_FOUND, "符号:" + srcUnitSymbol));
|
||||
|
||||
UntInfoDO tgtUnit = units.stream()
|
||||
.filter(u -> u.getSmb() != null && u.getSmb().equals(tgtUnitSymbol))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> exception(UNIT_NOT_FOUND, "符号:" + tgtUnitSymbol));
|
||||
|
||||
log.debug("按符号转换: {} ({}) → {} ({})", srcUnitSymbol, srcUnit.getId(), tgtUnitSymbol, tgtUnit.getId());
|
||||
|
||||
// 2. 调用原有方法
|
||||
return convert(value, srcUnit.getId(), tgtUnit.getId(), conversions, relations, precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位名称转换
|
||||
*
|
||||
* @param value 待转换的值
|
||||
* @param srcUnitName 源单位名称(如: "千克", "米", "千米")
|
||||
* @param tgtUnitName 目标单位名称
|
||||
* @param conversions 转换规则列表
|
||||
* @param relations 量纲-单位关联关系列表
|
||||
* @param units 单位信息列表
|
||||
* @param precision 精度(小数位数)
|
||||
* @return 转换结果
|
||||
*/
|
||||
public static ConversionResult convertByName(
|
||||
BigDecimal value,
|
||||
String srcUnitName,
|
||||
String tgtUnitName,
|
||||
List<UnitConversionDO> conversions,
|
||||
List<QuantityUnitRelationDO> relations,
|
||||
List<UntInfoDO> units,
|
||||
int precision) {
|
||||
|
||||
// 1. 根据名称查找单位
|
||||
UntInfoDO srcUnit = units.stream()
|
||||
.filter(u -> u.getName() != null && u.getName().equals(srcUnitName))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> exception(UNIT_NOT_FOUND, "名称:" + srcUnitName));
|
||||
|
||||
UntInfoDO tgtUnit = units.stream()
|
||||
.filter(u -> u.getName() != null && u.getName().equals(tgtUnitName))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> exception(UNIT_NOT_FOUND, "名称:" + tgtUnitName));
|
||||
|
||||
log.debug("按名称转换: {} ({}) → {} ({})", srcUnitName, srcUnit.getId(), tgtUnitName, tgtUnit.getId());
|
||||
|
||||
// 2. 调用原有方法
|
||||
return convert(value, srcUnit.getId(), tgtUnit.getId(), conversions, relations, precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位符号批量转换
|
||||
*
|
||||
* @param values 待转换的值列表
|
||||
* @param srcUnitSymbol 源单位符号
|
||||
* @param tgtUnitSymbol 目标单位符号
|
||||
* @param conversions 转换规则列表
|
||||
* @param relations 量纲-单位关联关系列表
|
||||
* @param units 单位信息列表
|
||||
* @param precision 精度(小数位数)
|
||||
* @return 转换结果列表
|
||||
*/
|
||||
public static List<ConversionResult> batchConvertBySymbol(
|
||||
List<BigDecimal> values,
|
||||
String srcUnitSymbol,
|
||||
String tgtUnitSymbol,
|
||||
List<UnitConversionDO> conversions,
|
||||
List<QuantityUnitRelationDO> relations,
|
||||
List<UntInfoDO> units,
|
||||
int precision) {
|
||||
|
||||
return values.stream()
|
||||
.map(value -> convertBySymbol(value, srcUnitSymbol, tgtUnitSymbol, conversions, relations, units, precision))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 按单位名称批量转换
|
||||
*
|
||||
* @param values 待转换的值列表
|
||||
* @param srcUnitName 源单位名称
|
||||
* @param tgtUnitName 目标单位名称
|
||||
* @param conversions 转换规则列表
|
||||
* @param relations 量纲-单位关联关系列表
|
||||
* @param units 单位信息列表
|
||||
* @param precision 精度(小数位数)
|
||||
* @return 转换结果列表
|
||||
*/
|
||||
public static List<ConversionResult> batchConvertByName(
|
||||
List<BigDecimal> values,
|
||||
String srcUnitName,
|
||||
String tgtUnitName,
|
||||
List<UnitConversionDO> conversions,
|
||||
List<QuantityUnitRelationDO> relations,
|
||||
List<UntInfoDO> units,
|
||||
int precision) {
|
||||
|
||||
return values.stream()
|
||||
.map(value -> convertByName(value, srcUnitName, tgtUnitName, conversions, relations, units, precision))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
package com.zt.plat.module.unitmanagement.util;
|
||||
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.UnitConversion.UnitConversionDO;
|
||||
import com.zt.plat.module.unitmanagement.dal.dataobject.QuantityUnitRelation.QuantityUnitRelationDO;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* UnitConversionUtil 工具类测试
|
||||
*
|
||||
* 测试内容:
|
||||
* 1. 相同单位转换
|
||||
* 2. 直接转换策略
|
||||
* 3. 基准单位转换策略
|
||||
* 4. 精度控制
|
||||
* 5. 批量转换
|
||||
* 6. 错误场景
|
||||
*/
|
||||
class UnitConversionUtilTest {
|
||||
|
||||
/**
|
||||
* 准备测试数据
|
||||
*/
|
||||
private TestData prepareTestData() {
|
||||
TestData data = new TestData();
|
||||
|
||||
// 量纲ID
|
||||
Long lengthQuantityId = 1L;
|
||||
Long weightQuantityId = 2L;
|
||||
|
||||
// 单位ID
|
||||
Long meterId = 101L; // 米(基准)
|
||||
Long kilometerId = 102L; // 千米
|
||||
Long centimeterId = 103L; // 厘米
|
||||
Long millimeterId = 104L; // 毫米
|
||||
Long kilogramId = 201L; // 千克(基准)
|
||||
Long tonId = 202L; // 吨
|
||||
|
||||
// 构建量纲-单位关联关系
|
||||
data.relations = new ArrayList<>();
|
||||
data.relations.add(createRelation(1L, lengthQuantityId, meterId, 1)); // 米是基准
|
||||
data.relations.add(createRelation(2L, lengthQuantityId, kilometerId, 0));
|
||||
data.relations.add(createRelation(3L, lengthQuantityId, centimeterId, 0));
|
||||
data.relations.add(createRelation(4L, lengthQuantityId, millimeterId, 0));
|
||||
data.relations.add(createRelation(5L, weightQuantityId, kilogramId, 1)); // 千克是基准
|
||||
data.relations.add(createRelation(6L, weightQuantityId, tonId, 0));
|
||||
|
||||
// 构建转换规则(只配置到基准单位的转换)
|
||||
data.conversions = new ArrayList<>();
|
||||
|
||||
// 千米 <-> 米
|
||||
data.conversions.add(createConversion(1L, kilometerId, meterId, new BigDecimal("1000"), "1km = 1000m"));
|
||||
data.conversions.add(createConversion(2L, meterId, kilometerId, new BigDecimal("0.001"), "1m = 0.001km"));
|
||||
|
||||
// 厘米 <-> 米
|
||||
data.conversions.add(createConversion(3L, centimeterId, meterId, new BigDecimal("0.01"), "1cm = 0.01m"));
|
||||
data.conversions.add(createConversion(4L, meterId, centimeterId, new BigDecimal("100"), "1m = 100cm"));
|
||||
|
||||
// 毫米 <-> 米
|
||||
data.conversions.add(createConversion(5L, millimeterId, meterId, new BigDecimal("0.001"), "1mm = 0.001m"));
|
||||
data.conversions.add(createConversion(6L, meterId, millimeterId, new BigDecimal("1000"), "1m = 1000mm"));
|
||||
|
||||
// 吨 <-> 千克
|
||||
data.conversions.add(createConversion(7L, tonId, kilogramId, new BigDecimal("1000"), "1t = 1000kg"));
|
||||
data.conversions.add(createConversion(8L, kilogramId, tonId, new BigDecimal("0.001"), "1kg = 0.001t"));
|
||||
|
||||
// 保存单位ID供测试使用
|
||||
data.meterId = meterId;
|
||||
data.kilometerId = kilometerId;
|
||||
data.centimeterId = centimeterId;
|
||||
data.millimeterId = millimeterId;
|
||||
data.kilogramId = kilogramId;
|
||||
data.tonId = tonId;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private QuantityUnitRelationDO createRelation(Long id, Long quantityId, Long unitId, Integer isBase) {
|
||||
QuantityUnitRelationDO relation = new QuantityUnitRelationDO();
|
||||
relation.setId(id);
|
||||
relation.setUntQtyId(quantityId);
|
||||
relation.setUntId(unitId);
|
||||
relation.setIsBse(isBase);
|
||||
return relation;
|
||||
}
|
||||
|
||||
private UnitConversionDO createConversion(Long id, Long srcId, Long tgtId, BigDecimal factor, String formula) {
|
||||
UnitConversionDO conversion = new UnitConversionDO();
|
||||
conversion.setId(id);
|
||||
conversion.setSrcUntId(srcId);
|
||||
conversion.setTgtUntId(tgtId);
|
||||
conversion.setFctr(factor);
|
||||
conversion.setFmu(formula);
|
||||
return conversion;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试1: 相同单位转换")
|
||||
void testSameUnitConversion() {
|
||||
TestData data = prepareTestData();
|
||||
|
||||
BigDecimal value = new BigDecimal("100");
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convert(
|
||||
value, data.meterId, data.meterId,
|
||||
data.conversions, data.relations, 6
|
||||
);
|
||||
|
||||
assertEquals(value, result.getValue(), "相同单位转换,值应该不变");
|
||||
assertEquals(BigDecimal.ONE, result.getFactor(), "相同单位转换,因子应该为1");
|
||||
assertEquals(UnitConversionUtil.ConversionStrategy.DIRECT, result.getStrategy(), "相同单位应使用DIRECT策略");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试2: 直接转换策略 - 千米到米")
|
||||
void testDirectConversion_KmToM() {
|
||||
TestData data = prepareTestData();
|
||||
|
||||
BigDecimal value = new BigDecimal("5.5");
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convert(
|
||||
value, data.kilometerId, data.meterId,
|
||||
data.conversions, data.relations, 6
|
||||
);
|
||||
|
||||
assertEquals(new BigDecimal("5500.000000"), result.getValue(), "5.5km应该等于5500m");
|
||||
assertEquals(new BigDecimal("1000"), result.getFactor(), "千米到米的因子应该是1000");
|
||||
assertEquals(UnitConversionUtil.ConversionStrategy.DIRECT, result.getStrategy(), "应使用DIRECT策略");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试3: 直接转换策略 - 米到千米")
|
||||
void testDirectConversion_MToKm() {
|
||||
TestData data = prepareTestData();
|
||||
|
||||
BigDecimal value = new BigDecimal("5000");
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convert(
|
||||
value, data.meterId, data.kilometerId,
|
||||
data.conversions, data.relations, 6
|
||||
);
|
||||
|
||||
assertEquals(new BigDecimal("5.000000"), result.getValue(), "5000m应该等于5km");
|
||||
assertEquals(new BigDecimal("0.001"), result.getFactor(), "米到千米的因子应该是0.001");
|
||||
assertEquals(UnitConversionUtil.ConversionStrategy.DIRECT, result.getStrategy(), "应使用DIRECT策略");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试4: 基准单位转换策略 - 厘米到千米")
|
||||
void testViaBaseUnitConversion_CmToKm() {
|
||||
TestData data = prepareTestData();
|
||||
|
||||
BigDecimal value = new BigDecimal("100000");
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convert(
|
||||
value, data.centimeterId, data.kilometerId,
|
||||
data.conversions, data.relations, 6
|
||||
);
|
||||
|
||||
assertEquals(new BigDecimal("1.000000"), result.getValue(), "100000cm应该等于1km");
|
||||
assertEquals(UnitConversionUtil.ConversionStrategy.VIA_BASE_UNIT, result.getStrategy(),
|
||||
"厘米到千米应使用VIA_BASE_UNIT策略");
|
||||
assertTrue(result.getFormula().contains("基准单位"), "公式应该提到基准单位");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试5: 基准单位转换策略 - 毫米到千米")
|
||||
void testViaBaseUnitConversion_MmToKm() {
|
||||
TestData data = prepareTestData();
|
||||
|
||||
BigDecimal value = new BigDecimal("1000000");
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convert(
|
||||
value, data.millimeterId, data.kilometerId,
|
||||
data.conversions, data.relations, 6
|
||||
);
|
||||
|
||||
assertEquals(new BigDecimal("1.000000"), result.getValue(), "1000000mm应该等于1km");
|
||||
assertEquals(UnitConversionUtil.ConversionStrategy.VIA_BASE_UNIT, result.getStrategy(),
|
||||
"毫米到千米应使用VIA_BASE_UNIT策略");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试6: 精度控制 - 2位小数")
|
||||
void testPrecisionControl_2Digits() {
|
||||
TestData data = prepareTestData();
|
||||
|
||||
BigDecimal value = new BigDecimal("1.23456789");
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convert(
|
||||
value, data.kilometerId, data.meterId,
|
||||
data.conversions, data.relations, 2
|
||||
);
|
||||
|
||||
assertEquals(new BigDecimal("1234.57"), result.getValue(), "精度应该控制在2位小数");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试7: 精度控制 - 6位小数")
|
||||
void testPrecisionControl_6Digits() {
|
||||
TestData data = prepareTestData();
|
||||
|
||||
BigDecimal value = new BigDecimal("1.23456789");
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convert(
|
||||
value, data.kilometerId, data.meterId,
|
||||
data.conversions, data.relations, 6
|
||||
);
|
||||
|
||||
assertEquals(new BigDecimal("1234.567890"), result.getValue(), "精度应该控制在6位小数");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试8: 批量转换")
|
||||
void testBatchConversion() {
|
||||
TestData data = prepareTestData();
|
||||
|
||||
List<BigDecimal> values = new ArrayList<>();
|
||||
values.add(new BigDecimal("1"));
|
||||
values.add(new BigDecimal("2"));
|
||||
values.add(new BigDecimal("3"));
|
||||
|
||||
List<UnitConversionUtil.ConversionResult> results = UnitConversionUtil.batchConvert(
|
||||
values, data.kilometerId, data.meterId,
|
||||
data.conversions, data.relations, 6
|
||||
);
|
||||
|
||||
assertEquals(3, results.size(), "应该返回3个转换结果");
|
||||
assertEquals(new BigDecimal("1000.000000"), results.get(0).getValue(), "1km = 1000m");
|
||||
assertEquals(new BigDecimal("2000.000000"), results.get(1).getValue(), "2km = 2000m");
|
||||
assertEquals(new BigDecimal("3000.000000"), results.get(2).getValue(), "3km = 3000m");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
@DisplayName("测试10: 重量单位转换 - 千克到吨")
|
||||
void testWeightConversion_KgToTon() {
|
||||
TestData data = prepareTestData();
|
||||
|
||||
BigDecimal value = new BigDecimal("1000");
|
||||
UnitConversionUtil.ConversionResult result = UnitConversionUtil.convert(
|
||||
value, data.kilogramId, data.tonId,
|
||||
data.conversions, data.relations, 6
|
||||
);
|
||||
|
||||
assertEquals(new BigDecimal("1.000000"), result.getValue(), "1000kg应该等于1t");
|
||||
assertEquals(new BigDecimal("0.001"), result.getFactor(), "千克到吨的因子应该是0.001");
|
||||
assertEquals(UnitConversionUtil.ConversionStrategy.DIRECT, result.getStrategy());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试数据容器
|
||||
*/
|
||||
static class TestData {
|
||||
List<UnitConversionDO> conversions;
|
||||
List<QuantityUnitRelationDO> relations;
|
||||
Long meterId;
|
||||
Long kilometerId;
|
||||
Long centimeterId;
|
||||
Long millimeterId;
|
||||
Long kilogramId;
|
||||
Long tonId;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user