feat(icd): 完善ICD映射管理功能
- 在AuthGlobalFilter中添加稳态检验相关接口的免认证路径 - 修改CsDevTypeMapper.xml移除icdPath字段返回避免数据冗余 - 在CsIcdPathController中新增查询参照ICD列表和ICD校验详情接口 - 更新CsIcdPathMapper添加selectReferenceIcdPathList等方法实现 - 移除CsIcdPath相关实体和参数中的path字段简化数据结构 - 扩展ICD类型定义支持手动录入和上游解析的标准/非标准分类 - 重构激活标准ICD逻辑支持不同类型间的正确转换 - 新增ICD一致性校验排除规则跳过特定描述的DOI项检查 - 优化报告映射规则应用逻辑提升校验准确性 - 添加去除重复DOI项功能确保数据唯一性
This commit is contained in:
@@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -37,6 +38,9 @@ public class IcdConsistencyCheckService {
|
||||
private static final String ISSUE_FILE_NAME = "icd-consistency-issues.json";
|
||||
private static final List<String> REQUIRED_REPORT_DESCS = Arrays.asList("统计数据", "波动闪变", "实时数据", "暂态事件");
|
||||
private static final List<String> REQUIRED_LN_CLASSES = Arrays.asList("MMXU", "MSQI", "MHAI", "MFLK");
|
||||
private static final Set<String> EXCLUDED_DOI_DESCS = new HashSet<String>(Arrays.asList(
|
||||
"电压扰动事件启动", "电压暂降事件启动", "电压暂升事件启动", "电压中断事件启动",
|
||||
"电压暂降启动定值", "电压暂升启动定值", "电压中断启动定值"));
|
||||
|
||||
private final FileStorageService fileStorageService;
|
||||
private final ObjectMapper objectMapper = buildMapper();
|
||||
@@ -45,14 +49,13 @@ public class IcdConsistencyCheckService {
|
||||
if (request == null) {
|
||||
throw new IllegalArgumentException("ICD 一致性校验请求不能为空");
|
||||
}
|
||||
log.info("ICD一致性校验,标准ICD JSON={}", request.getStandardJson());
|
||||
log.info("ICD一致性校验,待校验ICD JSON={}", request.getCheckedJson());
|
||||
MappingDocument checked = parseMapping(request.getCheckedJson(), "待校验 JSON");
|
||||
MappingDocument standard = parseMapping(request.getStandardJson(), "标准 JSON");
|
||||
|
||||
List<IcdConsistencyIssue> issues = new ArrayList<IcdConsistencyIssue>();
|
||||
validateSelfFormat(checked, "待校验映射", issues);
|
||||
boolean corrected = applySelfMappingRules(checked, issues);
|
||||
boolean corrected = applySelfMappingRules(checked, standard);
|
||||
corrected = removeDuplicateDescDoiItems(checked, standard, issues) || corrected;
|
||||
validateConsistency(checked, standard, issues);
|
||||
|
||||
IcdConsistencyCheckResponse response = new IcdConsistencyCheckResponse();
|
||||
@@ -172,6 +175,9 @@ public class IcdConsistencyCheckService {
|
||||
continue;
|
||||
}
|
||||
for (DoiItem doi : inst.getDoiList()) {
|
||||
if (isExcludedDoiDesc(doi.getDesc())) {
|
||||
continue;
|
||||
}
|
||||
if (isEmpty(doi.getSdiList())) {
|
||||
addIssue(issues, "自身格式校验", instPath + ".doiList[" + buildKey(doi.getName(), doi.getDesc()) + "]",
|
||||
"typeList 不能为空:" + joinDesc(group.getDesc(), inst.getDesc(), doi.getDesc()), null, null, false);
|
||||
@@ -197,24 +203,28 @@ public class IcdConsistencyCheckService {
|
||||
validateDataSetConsistency(checked, standard, issues);
|
||||
}
|
||||
|
||||
private boolean applySelfMappingRules(MappingDocument checked, List<IcdConsistencyIssue> issues) {
|
||||
private boolean applySelfMappingRules(MappingDocument checked, MappingDocument standard) {
|
||||
if (checked.getReportMap() == null) {
|
||||
return false;
|
||||
}
|
||||
Map<String, ReportMapItem> standardMap = indexReportMap(standard);
|
||||
boolean hasRtFre = false;
|
||||
boolean corrected = false;
|
||||
for (ReportMapItem item : checked.getReportMap()) {
|
||||
if ("实时数据".equals(trimToEmpty(item.getDesc())) && trimToEmpty(item.getRptId()).contains("RtFre")) {
|
||||
if ("实时数据".equals(trimToEmpty(item.getDesc())) && containsRtFre(item.getRptId())) {
|
||||
hasRtFre = true;
|
||||
ReportMapItem standardItem = standardMap.get(buildReportKey(item));
|
||||
boolean needRuleCorrection = standardItem == null
|
||||
|| !equalsValue(String.valueOf(standardItem.getReportCount()), String.valueOf(item.getReportCount()))
|
||||
|| !equalsValue(standardItem.getFlickerFlag(), item.getFlickerFlag());
|
||||
if (!needRuleCorrection) {
|
||||
continue;
|
||||
}
|
||||
if (!"1".equals(trimToEmpty(item.getFlickerFlag()))) {
|
||||
addIssue(issues, "映射规则", "ReportMap[" + buildReportKey(item) + "].FlickerFlag",
|
||||
"实时数据报告 rptID 包含 RtFre,FlickerFlag 已按规则调整为 1", "1", item.getFlickerFlag(), true);
|
||||
item.setFlickerFlag("1");
|
||||
corrected = true;
|
||||
}
|
||||
if (item.getReportCount() != 0) {
|
||||
addIssue(issues, "映射规则", "ReportMap[" + buildReportKey(item) + "].reportCount",
|
||||
"实时数据报告 rptID 包含 RtFre,reportCount 已按规则调整为 0", "0", String.valueOf(item.getReportCount()), true);
|
||||
item.setReportCount(0);
|
||||
corrected = true;
|
||||
}
|
||||
@@ -225,11 +235,12 @@ public class IcdConsistencyCheckService {
|
||||
}
|
||||
for (ReportMapItem item : checked.getReportMap()) {
|
||||
if ("统计数据".equals(trimToEmpty(item.getDesc()))) {
|
||||
ReportMapItem standardItem = standardMap.get(buildReportKey(item));
|
||||
if (standardItem != null && equalsValue(String.valueOf(standardItem.getReportCount()), String.valueOf(item.getReportCount()))) {
|
||||
continue;
|
||||
}
|
||||
int adjustedCount = item.getReportCount() - 1;
|
||||
if (item.getReportCount() != adjustedCount) {
|
||||
addIssue(issues, "映射规则", "ReportMap[" + buildReportKey(item) + "].reportCount",
|
||||
"存在 RtFre 实时数据报告,统计数据 reportCount 已按规则减 1",
|
||||
String.valueOf(adjustedCount), String.valueOf(item.getReportCount()), true);
|
||||
item.setReportCount(adjustedCount);
|
||||
corrected = true;
|
||||
}
|
||||
@@ -238,6 +249,47 @@ public class IcdConsistencyCheckService {
|
||||
return corrected;
|
||||
}
|
||||
|
||||
private boolean removeDuplicateDescDoiItems(MappingDocument checked, MappingDocument standard, List<IcdConsistencyIssue> issues) {
|
||||
if (checked.getDataSetList() == null) {
|
||||
return false;
|
||||
}
|
||||
Map<String, Set<String>> standardDoiKeys = indexStandardDoiKeysByInst(standard);
|
||||
boolean corrected = false;
|
||||
for (DataSetGroupItem group : checked.getDataSetList()) {
|
||||
if (group.getInstList() == null) {
|
||||
continue;
|
||||
}
|
||||
for (InstItem inst : group.getInstList()) {
|
||||
if (inst.getDoiList() == null) {
|
||||
continue;
|
||||
}
|
||||
Map<String, List<DoiItem>> doiItemsByDesc = new HashMap<String, List<DoiItem>>();
|
||||
for (DoiItem doi : inst.getDoiList()) {
|
||||
String desc = trimToEmpty(doi.getDesc());
|
||||
if (!doiItemsByDesc.containsKey(desc)) {
|
||||
doiItemsByDesc.put(desc, new ArrayList<DoiItem>());
|
||||
}
|
||||
doiItemsByDesc.get(desc).add(doi);
|
||||
}
|
||||
String instPath = buildInstPath(group, inst);
|
||||
Set<String> currentStandardKeys = standardDoiKeys.get(buildInstKey(group, inst));
|
||||
for (Map.Entry<String, List<DoiItem>> entry : doiItemsByDesc.entrySet()) {
|
||||
if (entry.getValue().size() <= 1) {
|
||||
continue;
|
||||
}
|
||||
DoiItem retained = chooseRetainedDoi(entry.getValue(), currentStandardKeys);
|
||||
String message = "同一个 doiList 下存在 desc 相同的指标,已仅保留 " + buildKey(retained.getDesc(), retained.getName())
|
||||
+ ";重复组合:" + describeDoiStandardMatches(entry.getValue(), currentStandardKeys);
|
||||
addIssue(issues, "映射规则", instPath + ".doiList[desc=" + entry.getKey() + "]", message,
|
||||
null, describeDoiKeys(entry.getValue()), true);
|
||||
removeDuplicatedDoiItems(inst.getDoiList(), entry.getValue(), retained);
|
||||
corrected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return corrected;
|
||||
}
|
||||
|
||||
private void validateReportMapConsistency(MappingDocument checked, MappingDocument standard, List<IcdConsistencyIssue> issues) {
|
||||
Map<String, ReportMapItem> checkedMap = new HashMap<String, ReportMapItem>();
|
||||
if (checked.getReportMap() != null) {
|
||||
@@ -303,6 +355,9 @@ public class IcdConsistencyCheckService {
|
||||
return;
|
||||
}
|
||||
for (DoiItem standardDoi : standardInst.getDoiList()) {
|
||||
if (isExcludedDoiDesc(standardDoi.getDesc())) {
|
||||
continue;
|
||||
}
|
||||
String doiKey = buildKey(standardDoi.getName(), standardDoi.getDesc());
|
||||
DoiItem checkedDoi = checkedDoiMap.get(doiKey);
|
||||
String path = "DataSetList[" + groupKey + "].instList[" + instKey + "].doiList[" + doiKey + "]";
|
||||
@@ -343,6 +398,17 @@ public class IcdConsistencyCheckService {
|
||||
issues.add(issue);
|
||||
}
|
||||
|
||||
private Map<String, ReportMapItem> indexReportMap(MappingDocument document) {
|
||||
Map<String, ReportMapItem> result = new HashMap<String, ReportMapItem>();
|
||||
if (document.getReportMap() == null) {
|
||||
return result;
|
||||
}
|
||||
for (ReportMapItem item : document.getReportMap()) {
|
||||
result.put(buildReportKey(item), item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, DataSetGroupItem> indexGroups(MappingDocument document) {
|
||||
Map<String, DataSetGroupItem> result = new HashMap<String, DataSetGroupItem>();
|
||||
if (document.getDataSetList() == null) {
|
||||
@@ -376,10 +442,36 @@ public class IcdConsistencyCheckService {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, Set<String>> indexStandardDoiKeysByInst(MappingDocument standard) {
|
||||
Map<String, Set<String>> result = new HashMap<String, Set<String>>();
|
||||
if (standard.getDataSetList() == null) {
|
||||
return result;
|
||||
}
|
||||
for (DataSetGroupItem group : standard.getDataSetList()) {
|
||||
if (group.getInstList() == null) {
|
||||
continue;
|
||||
}
|
||||
for (InstItem inst : group.getInstList()) {
|
||||
Set<String> doiKeys = new HashSet<String>();
|
||||
if (inst.getDoiList() != null) {
|
||||
for (DoiItem doi : inst.getDoiList()) {
|
||||
doiKeys.add(buildKey(doi.getDesc(), doi.getName()));
|
||||
}
|
||||
}
|
||||
result.put(buildInstKey(group, inst), doiKeys);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String buildReportKey(ReportMapItem item) {
|
||||
return buildKey(item.getDesc(), item.getRptId(), item.getName());
|
||||
}
|
||||
|
||||
private String buildInstKey(DataSetGroupItem group, InstItem inst) {
|
||||
return buildKey(group.getLnClass(), group.getDesc(), inst.getInst(), inst.getDesc());
|
||||
}
|
||||
|
||||
private String buildGroupPath(DataSetGroupItem group) {
|
||||
return "DataSetList[" + buildKey(group.getLnClass(), group.getDesc()) + "]";
|
||||
}
|
||||
@@ -396,10 +488,57 @@ public class IcdConsistencyCheckService {
|
||||
return String.join("+", parts);
|
||||
}
|
||||
|
||||
private DoiItem chooseRetainedDoi(List<DoiItem> doiItems, Set<String> standardDoiKeys) {
|
||||
if (standardDoiKeys != null) {
|
||||
for (DoiItem item : doiItems) {
|
||||
if (standardDoiKeys.contains(buildKey(item.getDesc(), item.getName()))) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return doiItems.get(0);
|
||||
}
|
||||
|
||||
private void removeDuplicatedDoiItems(List<DoiItem> allDoiItems, List<DoiItem> duplicatedItems, DoiItem retained) {
|
||||
Iterator<DoiItem> iterator = allDoiItems.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
DoiItem item = iterator.next();
|
||||
if (duplicatedItems.contains(item) && item != retained) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String describeDoiStandardMatches(List<DoiItem> doiItems, Set<String> standardDoiKeys) {
|
||||
List<String> values = new ArrayList<String>();
|
||||
for (DoiItem item : doiItems) {
|
||||
String key = buildKey(item.getDesc(), item.getName());
|
||||
boolean existsInStandard = standardDoiKeys != null && standardDoiKeys.contains(key);
|
||||
values.add(key + (existsInStandard ? " 在标准映射中存在" : " 不在标准映射中"));
|
||||
}
|
||||
return String.join(",", values);
|
||||
}
|
||||
|
||||
private String describeDoiKeys(List<DoiItem> doiItems) {
|
||||
List<String> values = new ArrayList<String>();
|
||||
for (DoiItem item : doiItems) {
|
||||
values.add(buildKey(item.getDesc(), item.getName()));
|
||||
}
|
||||
return String.join(",", values);
|
||||
}
|
||||
|
||||
private boolean equalsValue(String left, String right) {
|
||||
return trimToEmpty(left).equals(trimToEmpty(right));
|
||||
}
|
||||
|
||||
private boolean containsRtFre(String value) {
|
||||
return trimToEmpty(value).toLowerCase().contains("rtfre");
|
||||
}
|
||||
|
||||
private boolean isExcludedDoiDesc(String desc) {
|
||||
return EXCLUDED_DOI_DESCS.contains(trimToEmpty(desc));
|
||||
}
|
||||
|
||||
private boolean isBlank(String value) {
|
||||
return value == null || value.trim().isEmpty();
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import com.njcn.common.pojo.enums.common.LogEnum;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.response.HttpResult;
|
||||
import com.njcn.common.utils.LogUtil;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.njcn.gather.icd.mapping.pojo.param.CsIcdPathParam;
|
||||
import com.njcn.gather.icd.mapping.pojo.param.IcdCheckResultSaveParam;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathDetailVO;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathVO;
|
||||
import com.njcn.gather.icd.mapping.service.CsIcdPathService;
|
||||
import com.njcn.web.controller.BaseController;
|
||||
@@ -50,6 +52,16 @@ public class CsIcdPathController extends BaseController {
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询参照ICD列表")
|
||||
@PostMapping("/reference-list")
|
||||
public HttpResult<List<CsIcdPathVO>> referenceList() {
|
||||
String methodDescribe = getMethodDescribe("referenceList");
|
||||
LogUtil.njcnDebug(log, "{},开始查询参照ICD列表", methodDescribe);
|
||||
List<CsIcdPathVO> result = csIcdPathService.listReferenceIcdPaths();
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("新增ICD存储记录")
|
||||
@PostMapping(value = "/add", consumes = {"application/json"})
|
||||
@@ -115,6 +127,28 @@ public class CsIcdPathController extends BaseController {
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询ICD校验结果详情")
|
||||
@ApiImplicitParam(name = "id", value = "ICD记录ID", required = true)
|
||||
@PostMapping("/{id}/icd-check-msg")
|
||||
public HttpResult<JsonNode> getIcdCheckMsg(@PathVariable("id") String id) {
|
||||
String methodDescribe = getMethodDescribe("getIcdCheckMsg");
|
||||
LogUtil.njcnDebug(log, "{},开始查询ICD校验结果详情,icdId={}", methodDescribe, id);
|
||||
JsonNode result = csIcdPathService.getIcdCheckMsg(id);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询ICD映射文件详情")
|
||||
@ApiImplicitParam(name = "id", value = "ICD记录ID", required = true)
|
||||
@PostMapping("/{id}/mapping-detail")
|
||||
public HttpResult<CsIcdPathDetailVO> getMappingDetail(@PathVariable("id") String id) {
|
||||
String methodDescribe = getMethodDescribe("getMappingDetail");
|
||||
LogUtil.njcnDebug(log, "{},开始查询ICD映射文件详情,icdId={}", methodDescribe, id);
|
||||
CsIcdPathDetailVO result = csIcdPathService.getMappingDetail(id);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("保存ICD唯一性校验结果")
|
||||
@ApiImplicitParam(name = "id", value = "ICD记录ID", required = true)
|
||||
@@ -147,9 +181,6 @@ public class CsIcdPathController extends BaseController {
|
||||
}
|
||||
try {
|
||||
param.setIcdContent(icdFile.getBytes());
|
||||
if (param.getPath() == null || param.getPath().trim().isEmpty()) {
|
||||
param.setPath(resolveFileName(icdFile));
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalArgumentException("读取ICD文件失败:" + ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.njcn.gather.icd.mapping.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.njcn.gather.icd.mapping.pojo.po.CsIcdPathPO;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathDetailVO;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathVO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@@ -15,4 +16,10 @@ public interface CsIcdPathMapper extends BaseMapper<CsIcdPathPO> {
|
||||
List<CsIcdPathVO> selectIcdPathList(@Param("keyword") String keyword,
|
||||
@Param("type") Integer type,
|
||||
@Param("result") Integer result);
|
||||
|
||||
List<CsIcdPathVO> selectReferenceIcdPathList();
|
||||
|
||||
CsIcdPathVO selectIcdCheckMsgById(@Param("id") String id);
|
||||
|
||||
CsIcdPathDetailVO selectIcdPathDetailById(@Param("id") String id);
|
||||
}
|
||||
|
||||
@@ -7,12 +7,9 @@
|
||||
type="com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathVO">
|
||||
<id column="id" property="id"/>
|
||||
<result column="name" property="name"/>
|
||||
<result column="path" property="path"/>
|
||||
<result column="angle" property="angle"/>
|
||||
<result column="usePhaseIndex" property="usePhaseIndex"/>
|
||||
<result column="state" property="state"/>
|
||||
<result column="jsonStr" property="jsonStr"/>
|
||||
<result column="xmlStr" property="xmlStr"/>
|
||||
<result column="result" property="result"/>
|
||||
<result column="msg" property="msg"
|
||||
typeHandler="com.njcn.gather.icd.mapping.typehandler.JsonNodeTypeHandler"/>
|
||||
@@ -29,12 +26,9 @@
|
||||
SELECT
|
||||
ID AS id,
|
||||
Name AS name,
|
||||
Path AS path,
|
||||
Angle AS angle,
|
||||
Use_Phase_Index AS usePhaseIndex,
|
||||
State AS state,
|
||||
Json_Str AS jsonStr,
|
||||
Xml_Str AS xmlStr,
|
||||
Result AS result,
|
||||
Msg AS msg,
|
||||
Type AS type,
|
||||
@@ -46,8 +40,7 @@
|
||||
FROM cs_icd_path
|
||||
WHERE State = 1
|
||||
<if test="keyword != null and keyword != ''">
|
||||
AND (Name LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR Path LIKE CONCAT('%', #{keyword}, '%'))
|
||||
AND Name LIKE CONCAT('%', #{keyword}, '%')
|
||||
</if>
|
||||
<if test="type != null">
|
||||
AND Type = #{type}
|
||||
@@ -58,4 +51,47 @@
|
||||
ORDER BY Update_Time DESC, Create_Time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectReferenceIcdPathList"
|
||||
resultMap="CsIcdPathVOResultMap">
|
||||
SELECT
|
||||
ID AS id,
|
||||
Name AS name,
|
||||
Angle AS angle,
|
||||
Use_Phase_Index AS usePhaseIndex,
|
||||
State AS state,
|
||||
Result AS result,
|
||||
Msg AS msg,
|
||||
Type AS type,
|
||||
Reference_Icd_Id AS referenceIcdId,
|
||||
Create_By AS createBy,
|
||||
Create_Time AS createTime,
|
||||
Update_By AS updateBy,
|
||||
Update_Time AS updateTime
|
||||
FROM cs_icd_path
|
||||
WHERE State = 1
|
||||
AND Type IN (1, 3)
|
||||
ORDER BY Update_Time DESC, Create_Time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectIcdCheckMsgById"
|
||||
resultMap="CsIcdPathVOResultMap">
|
||||
SELECT Msg AS msg
|
||||
FROM cs_icd_path
|
||||
WHERE ID = #{id}
|
||||
AND State = 1
|
||||
</select>
|
||||
|
||||
<select id="selectIcdPathDetailById"
|
||||
resultType="com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathDetailVO">
|
||||
SELECT
|
||||
ID AS id,
|
||||
Name AS name,
|
||||
Json_Str AS jsonStr,
|
||||
Xml_Str AS xmlStr,
|
||||
Icd AS icdContent
|
||||
FROM cs_icd_path
|
||||
WHERE ID = #{id}
|
||||
AND State = 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -18,9 +18,6 @@ public class CsIcdPathParam {
|
||||
@NotBlank(message = "ICD名称不能为空")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("ICD存储路径")
|
||||
private String path;
|
||||
|
||||
@ApiModelProperty("ICD文件二进制内容")
|
||||
private byte[] icdContent;
|
||||
|
||||
@@ -30,7 +27,7 @@ public class CsIcdPathParam {
|
||||
@ApiModelProperty("是否使用相位索引")
|
||||
private Integer usePhaseIndex;
|
||||
|
||||
@ApiModelProperty("ICD类型,1-标准ICD")
|
||||
@ApiModelProperty("ICD类型,1-手动录入的标准ICD,2-手动录入的非标准ICD,3-上游解析传递的标准ICD,4-上游解析传递的非标准ICD")
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
@@ -53,10 +50,10 @@ public class CsIcdPathParam {
|
||||
@ApiModel("ICD存储记录列表查询参数")
|
||||
public static class ListParam {
|
||||
|
||||
@ApiModelProperty("关键字,匹配ICD名称或路径")
|
||||
@ApiModelProperty("关键字,匹配ICD名称")
|
||||
private String keyword;
|
||||
|
||||
@ApiModelProperty("ICD类型")
|
||||
@ApiModelProperty("ICD类型,1-手动录入的标准ICD,2-手动录入的非标准ICD,3-上游解析传递的标准ICD,4-上游解析传递的非标准ICD")
|
||||
private Integer type;
|
||||
|
||||
@ApiModelProperty("ICD校验结果,0-否,1-是")
|
||||
|
||||
@@ -25,9 +25,6 @@ public class CsIcdPathPO implements Serializable {
|
||||
@TableField("Name")
|
||||
private String name;
|
||||
|
||||
@TableField("Path")
|
||||
private String path;
|
||||
|
||||
@TableField("Icd")
|
||||
private byte[] icdContent;
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.njcn.gather.icd.mapping.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* ICD 映射文件详情。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("ICD映射文件详情")
|
||||
public class CsIcdPathDetailVO {
|
||||
|
||||
@ApiModelProperty("ICD记录ID")
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty("ICD名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("MMS映射JSON")
|
||||
private String jsonStr;
|
||||
|
||||
@ApiModelProperty("MMS映射XML")
|
||||
private String xmlStr;
|
||||
|
||||
@ApiModelProperty("ICD源文件文本")
|
||||
private String icdText;
|
||||
|
||||
@JsonIgnore
|
||||
private byte[] icdContent;
|
||||
}
|
||||
@@ -20,9 +20,6 @@ public class CsIcdPathVO {
|
||||
@ApiModelProperty("ICD名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("ICD存储路径")
|
||||
private String path;
|
||||
|
||||
@ApiModelProperty("角度")
|
||||
private Integer angle;
|
||||
|
||||
@@ -32,19 +29,13 @@ public class CsIcdPathVO {
|
||||
@ApiModelProperty("状态,1-正常,0-删除")
|
||||
private Integer state;
|
||||
|
||||
@ApiModelProperty("MMS映射JSON")
|
||||
private String jsonStr;
|
||||
|
||||
@ApiModelProperty("MMS映射XML")
|
||||
private String xmlStr;
|
||||
|
||||
@ApiModelProperty("校验结论,0-否,1-是")
|
||||
private Integer result;
|
||||
|
||||
@ApiModelProperty("校验结论详情JSON")
|
||||
private JsonNode msg;
|
||||
|
||||
@ApiModelProperty("ICD类型,1-标准ICD")
|
||||
@ApiModelProperty("ICD类型,1-手动录入的标准ICD,2-手动录入的非标准ICD,3-上游解析传递的标准ICD,4-上游解析传递的非标准ICD")
|
||||
private Integer type;
|
||||
|
||||
@ApiModelProperty("标准ICD引用ID")
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.njcn.gather.icd.mapping.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.njcn.gather.icd.mapping.pojo.param.CsIcdPathParam;
|
||||
import com.njcn.gather.icd.mapping.pojo.param.IcdCheckResultSaveParam;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathDetailVO;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathVO;
|
||||
|
||||
import java.util.List;
|
||||
@@ -13,6 +15,12 @@ public interface CsIcdPathService {
|
||||
|
||||
List<CsIcdPathVO> listIcdPaths(CsIcdPathParam.ListParam param);
|
||||
|
||||
List<CsIcdPathVO> listReferenceIcdPaths();
|
||||
|
||||
JsonNode getIcdCheckMsg(String icdId);
|
||||
|
||||
CsIcdPathDetailVO getMappingDetail(String icdId);
|
||||
|
||||
boolean addIcdPath(CsIcdPathParam param);
|
||||
|
||||
boolean updateIcdPath(CsIcdPathParam.UpdateParam param);
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package com.njcn.gather.icd.mapping.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.njcn.gather.icd.mapping.mapper.CsIcdPathMapper;
|
||||
import com.njcn.gather.icd.mapping.pojo.param.CsIcdPathParam;
|
||||
import com.njcn.gather.icd.mapping.pojo.param.IcdCheckResultSaveParam;
|
||||
import com.njcn.gather.icd.mapping.pojo.po.CsIcdPathPO;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathDetailVO;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathVO;
|
||||
import com.njcn.gather.icd.mapping.service.CsIcdPathService;
|
||||
import com.njcn.web.utils.RequestUtil;
|
||||
@@ -15,6 +16,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
@@ -30,7 +32,13 @@ public class CsIcdPathServiceImpl implements CsIcdPathService {
|
||||
|
||||
private static final int STATE_DELETED = 0;
|
||||
|
||||
private static final int ICD_TYPE_STANDARD = 1;
|
||||
private static final int ICD_TYPE_MANUAL_STANDARD = 1;
|
||||
|
||||
private static final int ICD_TYPE_MANUAL_NON_STANDARD = 2;
|
||||
|
||||
private static final int ICD_TYPE_UPSTREAM_STANDARD = 3;
|
||||
|
||||
private static final int ICD_TYPE_UPSTREAM_NON_STANDARD = 4;
|
||||
|
||||
private final CsIcdPathMapper csIcdPathMapper;
|
||||
|
||||
@@ -45,12 +53,38 @@ public class CsIcdPathServiceImpl implements CsIcdPathService {
|
||||
checkedParam.getResult());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CsIcdPathVO> listReferenceIcdPaths() {
|
||||
return csIcdPathMapper.selectReferenceIcdPathList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode getIcdCheckMsg(String icdId) {
|
||||
String id = requireText(icdId, "ICD璁板綍ID涓嶈兘涓虹┖");
|
||||
CsIcdPathVO icdPath = csIcdPathMapper.selectIcdCheckMsgById(id);
|
||||
return icdPath == null ? null : icdPath.getMsg();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CsIcdPathDetailVO getMappingDetail(String icdId) {
|
||||
String id = requireText(icdId, "ICD记录ID不能为空");
|
||||
CsIcdPathDetailVO detail = csIcdPathMapper.selectIcdPathDetailById(id);
|
||||
if (detail == null) {
|
||||
return null;
|
||||
}
|
||||
byte[] icdContent = detail.getIcdContent();
|
||||
if (icdContent != null && icdContent.length > 0) {
|
||||
detail.setIcdText(new String(icdContent, StandardCharsets.UTF_8));
|
||||
}
|
||||
return detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean addIcdPath(CsIcdPathParam param) {
|
||||
CsIcdPathParam checkedParam = requireParam(param);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
CsIcdPathPO icdPath = buildIcdPath(checkedParam);
|
||||
CsIcdPathPO icdPath = buildIcdPath(checkedParam, true);
|
||||
icdPath.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
icdPath.setState(STATE_NORMAL);
|
||||
icdPath.setCreateBy(currentUserId());
|
||||
@@ -65,7 +99,7 @@ public class CsIcdPathServiceImpl implements CsIcdPathService {
|
||||
public boolean updateIcdPath(CsIcdPathParam.UpdateParam param) {
|
||||
CsIcdPathParam.UpdateParam checkedParam = requireUpdateParam(param);
|
||||
requireIcdPath(checkedParam.getId());
|
||||
CsIcdPathPO icdPath = buildIcdPath(checkedParam);
|
||||
CsIcdPathPO icdPath = buildIcdPath(checkedParam, false);
|
||||
icdPath.setId(checkedParam.getId());
|
||||
icdPath.setUpdateBy(currentUserId());
|
||||
icdPath.setUpdateTime(LocalDateTime.now());
|
||||
@@ -80,13 +114,21 @@ public class CsIcdPathServiceImpl implements CsIcdPathService {
|
||||
String currentUserId = currentUserId();
|
||||
|
||||
csIcdPathMapper.update(null, new LambdaUpdateWrapper<CsIcdPathPO>()
|
||||
.set(CsIcdPathPO::getType, null)
|
||||
.set(CsIcdPathPO::getType, ICD_TYPE_MANUAL_NON_STANDARD)
|
||||
.set(CsIcdPathPO::getUpdateBy, currentUserId)
|
||||
.set(CsIcdPathPO::getUpdateTime, now)
|
||||
.eq(CsIcdPathPO::getState, STATE_NORMAL));
|
||||
.eq(CsIcdPathPO::getState, STATE_NORMAL)
|
||||
.eq(CsIcdPathPO::getType, ICD_TYPE_MANUAL_STANDARD));
|
||||
|
||||
csIcdPathMapper.update(null, new LambdaUpdateWrapper<CsIcdPathPO>()
|
||||
.set(CsIcdPathPO::getType, ICD_TYPE_UPSTREAM_NON_STANDARD)
|
||||
.set(CsIcdPathPO::getUpdateBy, currentUserId)
|
||||
.set(CsIcdPathPO::getUpdateTime, now)
|
||||
.eq(CsIcdPathPO::getState, STATE_NORMAL)
|
||||
.eq(CsIcdPathPO::getType, ICD_TYPE_UPSTREAM_STANDARD));
|
||||
|
||||
CsIcdPathPO activeIcdPath = new CsIcdPathPO();
|
||||
activeIcdPath.setType(ICD_TYPE_STANDARD);
|
||||
activeIcdPath.setType(resolveStandardType(targetIcdPath.getType()));
|
||||
activeIcdPath.setUpdateBy(currentUserId);
|
||||
activeIcdPath.setUpdateTime(now);
|
||||
return csIcdPathMapper.update(activeIcdPath, new LambdaUpdateWrapper<CsIcdPathPO>()
|
||||
@@ -116,7 +158,7 @@ public class CsIcdPathServiceImpl implements CsIcdPathService {
|
||||
throw new IllegalArgumentException("ICD校验结果不能为空");
|
||||
}
|
||||
CsIcdPathPO icdPath = requireIcdPath(icdId);
|
||||
CsIcdPathPO referenceIcd = requireUniqueReferenceIcd();
|
||||
CsIcdPathPO referenceIcd = requireReferenceIcd(icdPath.getReferenceIcdId());
|
||||
icdPath.setJsonStr(trimToNull(param.getMappingJson()));
|
||||
icdPath.setXmlStr(trimToNull(param.getXml()));
|
||||
icdPath.setResult(normalizeResult(param.getResult()));
|
||||
@@ -140,17 +182,34 @@ public class CsIcdPathServiceImpl implements CsIcdPathService {
|
||||
}
|
||||
}
|
||||
|
||||
private CsIcdPathPO buildIcdPath(CsIcdPathParam param) {
|
||||
private CsIcdPathPO buildIcdPath(CsIcdPathParam param, boolean useDefaultType) {
|
||||
CsIcdPathPO icdPath = new CsIcdPathPO();
|
||||
icdPath.setName(requireText(param.getName(), "ICD名称不能为空"));
|
||||
icdPath.setPath(requireText(param.getPath(), "ICD存储路径不能为空"));
|
||||
icdPath.setIcdContent(param.getIcdContent());
|
||||
icdPath.setAngle(param.getAngle());
|
||||
icdPath.setUsePhaseIndex(param.getUsePhaseIndex());
|
||||
icdPath.setType(param.getType());
|
||||
icdPath.setType(useDefaultType ? resolveIcdType(param.getType()) : param.getType());
|
||||
return icdPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增 ICD 记录未显式传类型时,默认归类为手动录入的非标准 ICD。
|
||||
*/
|
||||
private Integer resolveIcdType(Integer type) {
|
||||
return type == null ? ICD_TYPE_MANUAL_NON_STANDARD : type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活标准 ICD 时保留记录来源:手动录入升为 1,上游解析传递升为 3。
|
||||
*/
|
||||
private Integer resolveStandardType(Integer type) {
|
||||
if (Integer.valueOf(ICD_TYPE_UPSTREAM_STANDARD).equals(type)
|
||||
|| Integer.valueOf(ICD_TYPE_UPSTREAM_NON_STANDARD).equals(type)) {
|
||||
return ICD_TYPE_UPSTREAM_STANDARD;
|
||||
}
|
||||
return ICD_TYPE_MANUAL_STANDARD;
|
||||
}
|
||||
|
||||
private CsIcdPathParam requireParam(CsIcdPathParam param) {
|
||||
if (param == null) {
|
||||
throw new IllegalArgumentException("ICD记录参数不能为空");
|
||||
@@ -176,19 +235,15 @@ public class CsIcdPathServiceImpl implements CsIcdPathService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 全系统只允许一个正常状态的标准 ICD 作为唯一参照。
|
||||
* ICD 校验保存时以当前记录绑定的 Reference_Icd_Id 作为参照来源。
|
||||
*/
|
||||
private CsIcdPathPO requireUniqueReferenceIcd() {
|
||||
List<CsIcdPathPO> referenceIcdList = csIcdPathMapper.selectList(new LambdaQueryWrapper<CsIcdPathPO>()
|
||||
.eq(CsIcdPathPO::getState, STATE_NORMAL)
|
||||
.eq(CsIcdPathPO::getType, ICD_TYPE_STANDARD));
|
||||
if (referenceIcdList == null || referenceIcdList.isEmpty()) {
|
||||
throw new IllegalArgumentException("未配置标准ICD,无法执行唯一性校验");
|
||||
private CsIcdPathPO requireReferenceIcd(String referenceIcdId) {
|
||||
String id = requireText(referenceIcdId, "未配置参照ICD,无法保存校验结果");
|
||||
CsIcdPathPO referenceIcd = csIcdPathMapper.selectById(id);
|
||||
if (referenceIcd == null || !Integer.valueOf(STATE_NORMAL).equals(referenceIcd.getState())) {
|
||||
throw new IllegalArgumentException("参照ICD不存在或已删除,无法保存校验结果");
|
||||
}
|
||||
if (referenceIcdList.size() > 1) {
|
||||
throw new IllegalArgumentException("存在多个标准ICD,无法确定唯一参照");
|
||||
}
|
||||
return referenceIcdList.get(0);
|
||||
return referenceIcd;
|
||||
}
|
||||
|
||||
private Integer normalizeResult(Integer result) {
|
||||
|
||||
@@ -36,20 +36,62 @@ class IcdConsistencyCheckServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkShouldOnlyReturnCorrectedJsonForRtFreSelfMappingRule() {
|
||||
void checkShouldReturnPassAndCorrectedJsonForRtFreSelfMappingRule() {
|
||||
IcdConsistencyCheckRequest request = new IcdConsistencyCheckRequest();
|
||||
request.setStandardJson(buildRtFreStandardJson());
|
||||
request.setCheckedJson(buildRtFreCheckedJson());
|
||||
|
||||
IcdConsistencyCheckResponse response = service.check(request);
|
||||
|
||||
Assertions.assertEquals(0, response.getResult());
|
||||
Assertions.assertEquals(1, response.getResult());
|
||||
Assertions.assertTrue(response.getIssues().isEmpty());
|
||||
Assertions.assertTrue(response.getCorrectedJson().contains("\"rptID\" : \"demoRtFre\""));
|
||||
Assertions.assertTrue(response.getCorrectedJson().contains("\"FlickerFlag\" : \"1\""));
|
||||
Assertions.assertTrue(response.getCorrectedJson().contains("\"reportCount\" : 0"));
|
||||
Assertions.assertTrue(response.getCorrectedJson().contains("\"reportCount\" : 1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkShouldNotCorrectRtFreWhenReportMapAlreadyMatchesStandard() {
|
||||
IcdConsistencyCheckRequest request = new IcdConsistencyCheckRequest();
|
||||
request.setStandardJson(buildRtFreStandardJson());
|
||||
request.setCheckedJson(buildRtFreStandardJson());
|
||||
|
||||
IcdConsistencyCheckResponse response = service.check(request);
|
||||
|
||||
Assertions.assertEquals(1, response.getResult());
|
||||
Assertions.assertNull(response.getCorrectedJson());
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkShouldKeepStandardDoiWhenSameDoiListContainsDuplicateDesc() {
|
||||
IcdConsistencyCheckRequest request = new IcdConsistencyCheckRequest();
|
||||
request.setStandardJson(buildStandardJson());
|
||||
request.setCheckedJson(buildDuplicateDoiDescJson());
|
||||
|
||||
IcdConsistencyCheckResponse response = service.check(request);
|
||||
|
||||
Assertions.assertEquals(0, response.getResult());
|
||||
Assertions.assertTrue(response.getIssuesJson().contains("同一个 doiList 下存在 desc 相同的指标"));
|
||||
Assertions.assertTrue(response.getIssuesJson().contains("频率+Hz 在标准映射中存在"));
|
||||
Assertions.assertTrue(response.getIssuesJson().contains("频率+Hz2 不在标准映射中"));
|
||||
Assertions.assertNotNull(response.getCorrectedJson());
|
||||
Assertions.assertTrue(response.getCorrectedJson().contains("\"name\" : \"Hz\""));
|
||||
Assertions.assertFalse(response.getCorrectedJson().contains("\"name\" : \"Hz2\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkShouldIgnoreVoltageStartMetricsDuringDoiConsistency() {
|
||||
IcdConsistencyCheckRequest request = new IcdConsistencyCheckRequest();
|
||||
request.setStandardJson(buildVoltageStartMetricsStandardJson());
|
||||
request.setCheckedJson(buildStandardJson());
|
||||
|
||||
IcdConsistencyCheckResponse response = service.check(request);
|
||||
|
||||
Assertions.assertEquals(1, response.getResult());
|
||||
Assertions.assertTrue(response.getIssues().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkShouldReportEmptySdiListAsTypeListProblem() {
|
||||
IcdConsistencyCheckRequest request = new IcdConsistencyCheckRequest();
|
||||
@@ -63,6 +105,18 @@ class IcdConsistencyCheckServiceTest {
|
||||
Assertions.assertFalse(response.getIssuesJson().contains("sdiList 不能为空"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkShouldIgnoreVoltageStartMetricsDuringSelfFormatTypeListValidation() {
|
||||
IcdConsistencyCheckRequest request = new IcdConsistencyCheckRequest();
|
||||
request.setStandardJson(buildVoltageStartMetricsWithoutSdiJson());
|
||||
request.setCheckedJson(buildVoltageStartMetricsWithoutSdiJson());
|
||||
|
||||
IcdConsistencyCheckResponse response = service.check(request);
|
||||
|
||||
Assertions.assertEquals(1, response.getResult());
|
||||
Assertions.assertTrue(response.getIssues().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkShouldReturnPassWhenCheckedJsonMatchesStandardJson() {
|
||||
IcdConsistencyCheckRequest request = new IcdConsistencyCheckRequest();
|
||||
@@ -161,6 +215,69 @@ class IcdConsistencyCheckServiceTest {
|
||||
"}";
|
||||
}
|
||||
|
||||
private String buildDuplicateDoiDescJson() {
|
||||
return "{\n" +
|
||||
" \"IED\":\"IED1\",\n" +
|
||||
" \"LD\":\"LD0\",\n" +
|
||||
" \"DataType\":\"1\",\n" +
|
||||
" \"unit\":\"s\",\n" +
|
||||
" \"ReportMap\":[\n" +
|
||||
" {\"desc\":\"统计数据\",\"reportCount\":2,\"rptID\":\"rpt-stat\",\"name\":\"brcbStat\",\"buffered\":\"BR\",\"inst\":\"01\",\"FlickerFlag\":\"0\",\"Select\":\"all\",\"TrgOps\":\"dchg\"},\n" +
|
||||
" {\"desc\":\"波动闪变\",\"reportCount\":1,\"rptID\":\"rpt-flk\",\"name\":\"brcbFlk\",\"buffered\":\"BR\",\"inst\":\"02\",\"FlickerFlag\":\"0\",\"Select\":\"all\",\"TrgOps\":\"dchg\"},\n" +
|
||||
" {\"desc\":\"实时数据\",\"reportCount\":1,\"rptID\":\"rpt-rt\",\"name\":\"brcbRt\",\"buffered\":\"RP\",\"inst\":\"03\",\"FlickerFlag\":\"0\",\"Select\":\"all\",\"TrgOps\":\"dchg\"},\n" +
|
||||
" {\"desc\":\"暂态事件\",\"reportCount\":1,\"rptID\":\"rpt-tran\",\"name\":\"brcbTran\",\"buffered\":\"BR\",\"inst\":\"04\",\"FlickerFlag\":\"0\",\"Select\":\"all\",\"TrgOps\":\"dchg\"}\n" +
|
||||
" ],\n" +
|
||||
" \"DataSetList\":[\n" +
|
||||
buildDataSetWithDuplicateDoiDesc("MMXU", "统计数据", "1", "A相") + ",\n" +
|
||||
buildDataSet("MSQI", "实时数据", "1", "A相", "A", "电流", 1, 2, "A") + ",\n" +
|
||||
buildDataSet("MHAI", "谐波数据", "1", "A相", "Har", "谐波", 1, 2, "%") + ",\n" +
|
||||
buildDataSet("MFLK", "波动闪变", "1", "A相", "Flk", "闪变", 1, 2, "pu") + "\n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
}
|
||||
|
||||
private String buildVoltageStartMetricsStandardJson() {
|
||||
return "{\n" +
|
||||
" \"IED\":\"IED1\",\n" +
|
||||
" \"LD\":\"LD0\",\n" +
|
||||
" \"DataType\":\"1\",\n" +
|
||||
" \"unit\":\"s\",\n" +
|
||||
" \"ReportMap\":[\n" +
|
||||
" {\"desc\":\"统计数据\",\"reportCount\":2,\"rptID\":\"rpt-stat\",\"name\":\"brcbStat\",\"buffered\":\"BR\",\"inst\":\"01\",\"FlickerFlag\":\"0\",\"Select\":\"all\",\"TrgOps\":\"dchg\"},\n" +
|
||||
" {\"desc\":\"波动闪变\",\"reportCount\":1,\"rptID\":\"rpt-flk\",\"name\":\"brcbFlk\",\"buffered\":\"BR\",\"inst\":\"02\",\"FlickerFlag\":\"0\",\"Select\":\"all\",\"TrgOps\":\"dchg\"},\n" +
|
||||
" {\"desc\":\"实时数据\",\"reportCount\":1,\"rptID\":\"rpt-rt\",\"name\":\"brcbRt\",\"buffered\":\"RP\",\"inst\":\"03\",\"FlickerFlag\":\"0\",\"Select\":\"all\",\"TrgOps\":\"dchg\"},\n" +
|
||||
" {\"desc\":\"暂态事件\",\"reportCount\":1,\"rptID\":\"rpt-tran\",\"name\":\"brcbTran\",\"buffered\":\"BR\",\"inst\":\"04\",\"FlickerFlag\":\"0\",\"Select\":\"all\",\"TrgOps\":\"dchg\"}\n" +
|
||||
" ],\n" +
|
||||
" \"DataSetList\":[\n" +
|
||||
buildDataSetWithVoltageStartMetrics("MMXU", "统计数据", "1", "A相") + ",\n" +
|
||||
buildDataSet("MSQI", "实时数据", "1", "A相", "A", "电流", 1, 2, "A") + ",\n" +
|
||||
buildDataSet("MHAI", "谐波数据", "1", "A相", "Har", "谐波", 1, 2, "%") + ",\n" +
|
||||
buildDataSet("MFLK", "波动闪变", "1", "A相", "Flk", "闪变", 1, 2, "pu") + "\n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
}
|
||||
|
||||
private String buildVoltageStartMetricsWithoutSdiJson() {
|
||||
return "{\n" +
|
||||
" \"IED\":\"IED1\",\n" +
|
||||
" \"LD\":\"LD0\",\n" +
|
||||
" \"DataType\":\"1\",\n" +
|
||||
" \"unit\":\"s\",\n" +
|
||||
" \"ReportMap\":[\n" +
|
||||
" {\"desc\":\"统计数据\",\"reportCount\":2,\"rptID\":\"rpt-stat\",\"name\":\"brcbStat\",\"buffered\":\"BR\",\"inst\":\"01\",\"FlickerFlag\":\"0\",\"Select\":\"all\",\"TrgOps\":\"dchg\"},\n" +
|
||||
" {\"desc\":\"波动闪变\",\"reportCount\":1,\"rptID\":\"rpt-flk\",\"name\":\"brcbFlk\",\"buffered\":\"BR\",\"inst\":\"02\",\"FlickerFlag\":\"0\",\"Select\":\"all\",\"TrgOps\":\"dchg\"},\n" +
|
||||
" {\"desc\":\"实时数据\",\"reportCount\":1,\"rptID\":\"rpt-rt\",\"name\":\"brcbRt\",\"buffered\":\"RP\",\"inst\":\"03\",\"FlickerFlag\":\"0\",\"Select\":\"all\",\"TrgOps\":\"dchg\"},\n" +
|
||||
" {\"desc\":\"暂态事件\",\"reportCount\":1,\"rptID\":\"rpt-tran\",\"name\":\"brcbTran\",\"buffered\":\"BR\",\"inst\":\"04\",\"FlickerFlag\":\"0\",\"Select\":\"all\",\"TrgOps\":\"dchg\"}\n" +
|
||||
" ],\n" +
|
||||
" \"DataSetList\":[\n" +
|
||||
buildDataSetWithVoltageStartMetricsWithoutSdi("MMXU", "统计数据", "1", "A相") + ",\n" +
|
||||
buildDataSet("MSQI", "实时数据", "1", "A相", "A", "电流", 1, 2, "A") + ",\n" +
|
||||
buildDataSet("MHAI", "谐波数据", "1", "A相", "Har", "谐波", 1, 2, "%") + ",\n" +
|
||||
buildDataSet("MFLK", "波动闪变", "1", "A相", "Flk", "闪变", 1, 2, "pu") + "\n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
}
|
||||
|
||||
private String buildEmptySdiListJson() {
|
||||
return "{\n" +
|
||||
" \"IED\":\"IED1\",\n" +
|
||||
@@ -196,4 +313,51 @@ class IcdConsistencyCheckServiceTest {
|
||||
"\",\"desc\":\"" + instDesc + "\",\"doiList\":[{\"name\":\"" + doiName + "\",\"desc\":\"" + doiDesc +
|
||||
"\",\"start\":1,\"end\":4,\"unit\":\"Hz\",\"coefficient\":1.0,\"baseflag\":1,\"basecount\":1,\"icdcout\":10,\"sdiList\":[]}]}]}";
|
||||
}
|
||||
|
||||
private String buildDataSetWithDuplicateDoiDesc(String lnClass, String groupDesc, String inst, String instDesc) {
|
||||
return " {\"desc\":\"" + groupDesc + "\",\"lnClass\":\"" + lnClass + "\",\"instList\":[{\"inst\":\"" + inst +
|
||||
"\",\"desc\":\"" + instDesc + "\",\"doiList\":[" +
|
||||
buildDoi("Hz2", "频率", 5, 8, "Hz") + "," +
|
||||
buildDoi("Hz", "频率", 1, 4, "Hz") +
|
||||
"]}]}";
|
||||
}
|
||||
|
||||
private String buildDataSetWithVoltageStartMetrics(String lnClass, String groupDesc, String inst, String instDesc) {
|
||||
return " {\"desc\":\"" + groupDesc + "\",\"lnClass\":\"" + lnClass + "\",\"instList\":[{\"inst\":\"" + inst +
|
||||
"\",\"desc\":\"" + instDesc + "\",\"doiList\":[" +
|
||||
buildDoi("Hz", "频率", 1, 4, "Hz") + "," +
|
||||
buildDoi("VolDistStr", "电压扰动事件启动", 5, 6, "") + "," +
|
||||
buildDoi("VolDipStr", "电压暂降事件启动", 7, 8, "") + "," +
|
||||
buildDoi("VolSwellStr", "电压暂升事件启动", 9, 10, "") + "," +
|
||||
buildDoi("VolInterStr", "电压中断事件启动", 11, 12, "") + "," +
|
||||
buildDoi("VolDipSet", "电压暂降启动定值", 13, 14, "V") + "," +
|
||||
buildDoi("VolSwellSet", "电压暂升启动定值", 15, 16, "V") + "," +
|
||||
buildDoi("VolInterSet", "电压中断启动定值", 17, 18, "V") +
|
||||
"]}]}";
|
||||
}
|
||||
|
||||
private String buildDataSetWithVoltageStartMetricsWithoutSdi(String lnClass, String groupDesc, String inst, String instDesc) {
|
||||
return " {\"desc\":\"" + groupDesc + "\",\"lnClass\":\"" + lnClass + "\",\"instList\":[{\"inst\":\"" + inst +
|
||||
"\",\"desc\":\"" + instDesc + "\",\"doiList\":[" +
|
||||
buildDoiWithoutSdi("VolDistStr", "电压扰动事件启动", 5, 6, "") + "," +
|
||||
buildDoiWithoutSdi("VolDipStr", "电压暂降事件启动", 7, 8, "") + "," +
|
||||
buildDoiWithoutSdi("VolSwellStr", "电压暂升事件启动", 9, 10, "") + "," +
|
||||
buildDoiWithoutSdi("VolInterStr", "电压中断事件启动", 11, 12, "") + "," +
|
||||
buildDoiWithoutSdi("VolDipSet", "电压暂降启动定值", 13, 14, "V") + "," +
|
||||
buildDoiWithoutSdi("VolSwellSet", "电压暂升启动定值", 15, 16, "V") + "," +
|
||||
buildDoiWithoutSdi("VolInterSet", "电压中断启动定值", 17, 18, "V") +
|
||||
"]}]}";
|
||||
}
|
||||
|
||||
private String buildDoi(String doiName, String doiDesc, int start, int end, String unit) {
|
||||
return "{\"name\":\"" + doiName + "\",\"desc\":\"" + doiDesc +
|
||||
"\",\"start\":" + start + ",\"end\":" + end + ",\"unit\":\"" + unit +
|
||||
"\",\"coefficient\":1.0,\"baseflag\":1,\"basecount\":1,\"icdcout\":10,\"sdiList\":[{\"name\":\"mag\",\"desc\":\"幅值\",\"typeList\":[{\"name\":\"f\",\"desc\":\"浮点\"}]}]}";
|
||||
}
|
||||
|
||||
private String buildDoiWithoutSdi(String doiName, String doiDesc, int start, int end, String unit) {
|
||||
return "{\"name\":\"" + doiName + "\",\"desc\":\"" + doiDesc +
|
||||
"\",\"start\":" + start + ",\"end\":" + end + ",\"unit\":\"" + unit +
|
||||
"\",\"coefficient\":1.0,\"baseflag\":1,\"basecount\":1,\"icdcout\":10,\"sdiList\":[]}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import com.njcn.gather.icd.mapping.pojo.bo.icd.IcdDocument;
|
||||
import com.njcn.gather.icd.mapping.pojo.param.CsIcdPathParam;
|
||||
import com.njcn.gather.icd.mapping.pojo.param.IcdCheckResultSaveParam;
|
||||
import com.njcn.gather.icd.mapping.pojo.po.CsIcdPathPO;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathDetailVO;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.CsIcdPathVO;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
@@ -47,6 +49,26 @@ class CsIcdPathServiceImplTest {
|
||||
verify(csIcdPathMapper).selectIcdPathList(eq("standard"), eq(null), eq(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void listReferenceIcdPathsShouldQueryStandardIcdTypes() {
|
||||
service.listReferenceIcdPaths();
|
||||
|
||||
verify(csIcdPathMapper).selectReferenceIcdPathList();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getIcdCheckMsgShouldQueryMsgByTrimmedId() {
|
||||
JsonNode msg = objectMapper.createObjectNode().put("summary", "通过");
|
||||
CsIcdPathVO vo = new CsIcdPathVO();
|
||||
vo.setMsg(msg);
|
||||
when(csIcdPathMapper.selectIcdCheckMsgById(eq("icd-001"))).thenReturn(vo);
|
||||
|
||||
JsonNode result = service.getIcdCheckMsg(" icd-001 ");
|
||||
|
||||
Assertions.assertSame(msg, result);
|
||||
verify(csIcdPathMapper).selectIcdCheckMsgById(eq("icd-001"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void addIcdPathShouldInsertEnabledRecord() {
|
||||
CsIcdPathParam param = buildParam("标准ICD");
|
||||
@@ -58,7 +80,6 @@ class CsIcdPathServiceImplTest {
|
||||
verify(csIcdPathMapper).insert(captor.capture());
|
||||
Assertions.assertTrue(result);
|
||||
Assertions.assertEquals("标准ICD", captor.getValue().getName());
|
||||
Assertions.assertEquals("D:/icd/standard.icd", captor.getValue().getPath());
|
||||
Assertions.assertEquals(1, captor.getValue().getState());
|
||||
Assertions.assertNotNull(captor.getValue().getId());
|
||||
Assertions.assertNotNull(captor.getValue().getCreateTime());
|
||||
@@ -79,12 +100,25 @@ class CsIcdPathServiceImplTest {
|
||||
Assertions.assertArrayEquals(fileContent, captor.getValue().getIcdContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void addIcdPathShouldDefaultTypeToManualNonStandard() {
|
||||
CsIcdPathParam param = buildParam("手动录入非标准ICD");
|
||||
param.setType(null);
|
||||
when(csIcdPathMapper.insert(any(CsIcdPathPO.class))).thenReturn(1);
|
||||
|
||||
boolean result = service.addIcdPath(param);
|
||||
|
||||
ArgumentCaptor<CsIcdPathPO> captor = ArgumentCaptor.forClass(CsIcdPathPO.class);
|
||||
verify(csIcdPathMapper).insert(captor.capture());
|
||||
Assertions.assertTrue(result);
|
||||
Assertions.assertEquals(2, captor.getValue().getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateIcdPathShouldRejectDeletedRecord() {
|
||||
CsIcdPathParam.UpdateParam param = new CsIcdPathParam.UpdateParam();
|
||||
param.setId("icd-001");
|
||||
param.setName("标准ICD");
|
||||
param.setPath("D:/icd/standard.icd");
|
||||
|
||||
CsIcdPathPO deleted = new CsIcdPathPO();
|
||||
deleted.setId("icd-001");
|
||||
@@ -103,7 +137,6 @@ class CsIcdPathServiceImplTest {
|
||||
byte[] fileContent = "<SCL version=\"1\"></SCL>".getBytes();
|
||||
param.setId("icd-001");
|
||||
param.setName("标准ICD");
|
||||
param.setPath("standard.icd");
|
||||
param.setIcdContent(fileContent);
|
||||
|
||||
CsIcdPathPO existed = new CsIcdPathPO();
|
||||
@@ -134,21 +167,40 @@ class CsIcdPathServiceImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void activateIcdPathShouldOnlyKeepTargetAsStandardIcd() {
|
||||
void activateIcdPathShouldOnlyKeepTargetAsManualStandardIcd() {
|
||||
CsIcdPathPO icdPath = new CsIcdPathPO();
|
||||
icdPath.setId("icd-001");
|
||||
icdPath.setState(1);
|
||||
icdPath.setType(2);
|
||||
when(csIcdPathMapper.selectById(eq("icd-001"))).thenReturn(icdPath);
|
||||
when(csIcdPathMapper.update(any(CsIcdPathPO.class), any())).thenReturn(1);
|
||||
|
||||
boolean result = service.activateIcdPath("icd-001");
|
||||
|
||||
ArgumentCaptor<CsIcdPathPO> captor = ArgumentCaptor.forClass(CsIcdPathPO.class);
|
||||
verify(csIcdPathMapper, times(2)).update(captor.capture(), any());
|
||||
verify(csIcdPathMapper, times(3)).update(captor.capture(), any());
|
||||
Assertions.assertTrue(result);
|
||||
Assertions.assertNull(captor.getAllValues().get(0));
|
||||
Assertions.assertEquals(1, captor.getAllValues().get(1).getType());
|
||||
Assertions.assertNotNull(captor.getAllValues().get(1).getUpdateTime());
|
||||
Assertions.assertNull(captor.getAllValues().get(1));
|
||||
Assertions.assertEquals(1, captor.getAllValues().get(2).getType());
|
||||
Assertions.assertNotNull(captor.getAllValues().get(2).getUpdateTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
void activateIcdPathShouldKeepUpstreamSourceWhenTargetIsUpstreamIcd() {
|
||||
CsIcdPathPO icdPath = new CsIcdPathPO();
|
||||
icdPath.setId("icd-001");
|
||||
icdPath.setState(1);
|
||||
icdPath.setType(4);
|
||||
when(csIcdPathMapper.selectById(eq("icd-001"))).thenReturn(icdPath);
|
||||
when(csIcdPathMapper.update(any(CsIcdPathPO.class), any())).thenReturn(1);
|
||||
|
||||
boolean result = service.activateIcdPath("icd-001");
|
||||
|
||||
ArgumentCaptor<CsIcdPathPO> captor = ArgumentCaptor.forClass(CsIcdPathPO.class);
|
||||
verify(csIcdPathMapper, times(3)).update(captor.capture(), any());
|
||||
Assertions.assertTrue(result);
|
||||
Assertions.assertEquals(3, captor.getAllValues().get(2).getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -235,10 +287,36 @@ class CsIcdPathServiceImplTest {
|
||||
Assertions.assertArrayEquals(objectMapper.writeValueAsBytes(icdDocument), captor.getValue().getIcdContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMappingDetailShouldReturnJsonXmlAndUtf8IcdText() {
|
||||
CsIcdPathDetailVO detail = new CsIcdPathDetailVO();
|
||||
detail.setId("icd-001");
|
||||
detail.setName("标准ICD");
|
||||
detail.setJsonStr("{\"ied\":\"IED1\"}");
|
||||
detail.setXmlStr("<Root></Root>");
|
||||
detail.setIcdContent("<SCL name=\"demo\"></SCL>".getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||
when(csIcdPathMapper.selectIcdPathDetailById(eq("icd-001"))).thenReturn(detail);
|
||||
|
||||
CsIcdPathDetailVO result = service.getMappingDetail(" icd-001 ");
|
||||
|
||||
Assertions.assertEquals("{\"ied\":\"IED1\"}", result.getJsonStr());
|
||||
Assertions.assertEquals("<Root></Root>", result.getXmlStr());
|
||||
Assertions.assertEquals("<SCL name=\"demo\"></SCL>", result.getIcdText());
|
||||
verify(csIcdPathMapper).selectIcdPathDetailById(eq("icd-001"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMappingDetailShouldReturnNullWhenRecordMissing() {
|
||||
when(csIcdPathMapper.selectIcdPathDetailById(eq("missing"))).thenReturn(null);
|
||||
|
||||
CsIcdPathDetailVO result = service.getMappingDetail("missing");
|
||||
|
||||
Assertions.assertNull(result);
|
||||
}
|
||||
|
||||
private CsIcdPathParam buildParam(String name) {
|
||||
CsIcdPathParam param = new CsIcdPathParam();
|
||||
param.setName(name);
|
||||
param.setPath("D:/icd/standard.icd");
|
||||
param.setAngle(0);
|
||||
param.setUsePhaseIndex(1);
|
||||
param.setType(1);
|
||||
|
||||
Reference in New Issue
Block a user