From 9cd3e4a5d60203c620c8c6f679daa8685ec3eef0 Mon Sep 17 00:00:00 2001 From: lixiaolong <702156524@qq.com> Date: Wed, 16 Sep 2026 13:39:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(inspection):=20=E5=A2=9E=E5=8A=A0=E5=B7=A1?= =?UTF-8?q?=E6=A3=80=E7=82=B9=E4=BD=8D=E8=AF=AD=E6=96=99=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 inspection_waypoint 表中新增 chinese_corpus 和 english_corpus 字段存储中英文语料 - 创建 InspectionWaypointCorpusConfigVO 用于巡检点位语料查询节点参数 - 实现 InspectionWaypointCorpusMapper 提供按检测项ID查询语料的数据库操作 - 开发 InspectionWaypointCorpusOperateService 处理语料类型识别和语料获取逻辑 - 添加语料类型支持包括中文/英文、zh-CN/en-US、zh/en或0/1等多种格式 - 实现语料验证机制确保巡检点位配置了相应语言语料 - 编写单元测试验证中英文语料获取和类型解析功能 - 为 VisionLocateOperateService 增加完整的测试用例覆盖安全方向校准和平面定位功能 --- ...nspectionWaypointCorpusOperateService.java | 87 ++++++ .../InspectionWaypointCorpusMapper.java | 13 + .../InspectionWaypointCorpusConfigVO.java | 19 ++ .../InspectionWaypointCorpusVO.java | 12 + .../edge/VisionLocateOperateServiceTest.java | 258 ++++++++++++++++++ ...ctionWaypointCorpusOperateServiceTest.java | 75 +++++ sql/inspection_waypoint_corpus.sql | 4 + 7 files changed, 468 insertions(+) create mode 100644 cmvr-iot-test/src/main/java/com/cmvr/test/flow/runtime/operator/llm/InspectionWaypointCorpusOperateService.java create mode 100644 cmvr-iot-test/src/main/java/com/cmvr/test/mapper/InspectionWaypointCorpusMapper.java create mode 100644 cmvr-iot-test/src/main/java/com/cmvr/test/model/vo/inspection/InspectionWaypointCorpusConfigVO.java create mode 100644 cmvr-iot-test/src/main/java/com/cmvr/test/model/vo/inspection/InspectionWaypointCorpusVO.java create mode 100644 cmvr-iot-test/src/test/java/com/cmvr/test/flow/runtime/operator/edge/VisionLocateOperateServiceTest.java create mode 100644 cmvr-iot-test/src/test/java/com/cmvr/test/flow/runtime/operator/llm/InspectionWaypointCorpusOperateServiceTest.java create mode 100644 sql/inspection_waypoint_corpus.sql diff --git a/cmvr-iot-test/src/main/java/com/cmvr/test/flow/runtime/operator/llm/InspectionWaypointCorpusOperateService.java b/cmvr-iot-test/src/main/java/com/cmvr/test/flow/runtime/operator/llm/InspectionWaypointCorpusOperateService.java new file mode 100644 index 0000000..714e258 --- /dev/null +++ b/cmvr-iot-test/src/main/java/com/cmvr/test/flow/runtime/operator/llm/InspectionWaypointCorpusOperateService.java @@ -0,0 +1,87 @@ +package com.cmvr.test.flow.runtime.operator.llm; + +import com.alibaba.fastjson2.JSONObject; +import com.cmvr.common.exception.GlobalException; +import com.cmvr.test.enums.ActionEnum; +import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage; +import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult; +import com.cmvr.test.mapper.InspectionWaypointCorpusMapper; +import com.cmvr.test.model.vo.inspection.InspectionWaypointCorpusConfigVO; +import com.cmvr.test.model.vo.inspection.InspectionWaypointCorpusVO; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Locale; + +/** 根据检测项和语料类型读取巡检点位配置的播放语料。 */ +@Service +@RequiredArgsConstructor +public class InspectionWaypointCorpusOperateService implements LLMOperateService +{ + private final InspectionWaypointCorpusMapper inspectionWaypointCorpusMapper; + + @Override + public boolean supports(ActionEnum action) + { + return ActionEnum.INSPECTION_WAYPOINT_CORPUS.equals(action); + } + + @Override + public TaskNodeExecuteResult execute(TaskNodeExecuteMessage message) + { + JSONObject input = message.getInputParams() == null ? new JSONObject() : message.getInputParams(); + InspectionWaypointCorpusConfigVO config = input.to(InspectionWaypointCorpusConfigVO.class); + String detectItemId = StringUtils.trimToNull(config.getDetectItemId()); + String type = StringUtils.trimToNull(config.getType()); + if (detectItemId == null) + { + throw new GlobalException("检测项ID不能为空"); + } + if (type == null) + { + throw new GlobalException("语料类型不能为空"); + } + + InspectionWaypointCorpusVO waypoint = + inspectionWaypointCorpusMapper.selectByDetectItemId(detectItemId); + if (waypoint == null) + { + throw new GlobalException("未找到检测项对应的巡检点位: " + detectItemId); + } + + String corpus = resolveCorpus(waypoint, type); + if (StringUtils.isBlank(corpus)) + { + throw new GlobalException("巡检点位未配置" + languageName(type) + "语料"); + } + + return TaskNodeExecuteResult.success(new JSONObject().fluentPut("corpus", corpus)); + } + + private String resolveCorpus(InspectionWaypointCorpusVO waypoint, String type) + { + return isChinese(type) ? waypoint.getChineseCorpus() : waypoint.getEnglishCorpus(); + } + + private String languageName(String type) + { + return isChinese(type) ? "中文" : "英文"; + } + + private boolean isChinese(String type) + { + String normalized = type.trim().toLowerCase(Locale.ROOT).replace('_', '-'); + if ("0".equals(normalized) || "cn".equals(normalized) || "chinese".equals(normalized) + || "中文".equals(normalized) || normalized.startsWith("zh")) + { + return true; + } + if ("1".equals(normalized) || "english".equals(normalized) || "英文".equals(normalized) + || normalized.startsWith("en")) + { + return false; + } + throw new GlobalException("不支持的语料类型: " + type); + } +} diff --git a/cmvr-iot-test/src/main/java/com/cmvr/test/mapper/InspectionWaypointCorpusMapper.java b/cmvr-iot-test/src/main/java/com/cmvr/test/mapper/InspectionWaypointCorpusMapper.java new file mode 100644 index 0000000..34cf3fa --- /dev/null +++ b/cmvr-iot-test/src/main/java/com/cmvr/test/mapper/InspectionWaypointCorpusMapper.java @@ -0,0 +1,13 @@ +package com.cmvr.test.mapper; + +import com.cmvr.test.model.vo.inspection.InspectionWaypointCorpusVO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +/** 巡检点位语料查询Mapper。 */ +public interface InspectionWaypointCorpusMapper +{ + @Select("select chinese_corpus as chineseCorpus, english_corpus as englishCorpus " + + "from inspection_waypoint where detect_item_id = #{detectItemId} limit 1") + InspectionWaypointCorpusVO selectByDetectItemId(@Param("detectItemId") String detectItemId); +} diff --git a/cmvr-iot-test/src/main/java/com/cmvr/test/model/vo/inspection/InspectionWaypointCorpusConfigVO.java b/cmvr-iot-test/src/main/java/com/cmvr/test/model/vo/inspection/InspectionWaypointCorpusConfigVO.java new file mode 100644 index 0000000..d24bd0a --- /dev/null +++ b/cmvr-iot-test/src/main/java/com/cmvr/test/model/vo/inspection/InspectionWaypointCorpusConfigVO.java @@ -0,0 +1,19 @@ +package com.cmvr.test.model.vo.inspection; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** 巡检点位语料查询工作流节点参数。 */ +@Data +@ApiModel(value = "InspectionWaypointCorpusConfigVO", + description = "INSPECTION_WAYPOINT_CORPUS节点参数") +public class InspectionWaypointCorpusConfigVO +{ + @ApiModelProperty(value = "点位关联的检测项ID", required = true) + private String detectItemId; + + @ApiModelProperty(value = "语料类型,支持中文/英文、zh-CN/en-US、zh/en或0/1", + required = true, example = "zh-CN") + private String type; +} diff --git a/cmvr-iot-test/src/main/java/com/cmvr/test/model/vo/inspection/InspectionWaypointCorpusVO.java b/cmvr-iot-test/src/main/java/com/cmvr/test/model/vo/inspection/InspectionWaypointCorpusVO.java new file mode 100644 index 0000000..fd61790 --- /dev/null +++ b/cmvr-iot-test/src/main/java/com/cmvr/test/model/vo/inspection/InspectionWaypointCorpusVO.java @@ -0,0 +1,12 @@ +package com.cmvr.test.model.vo.inspection; + +import lombok.Data; + +/** 巡检点位中英文语料查询结果。 */ +@Data +public class InspectionWaypointCorpusVO +{ + private String chineseCorpus; + + private String englishCorpus; +} diff --git a/cmvr-iot-test/src/test/java/com/cmvr/test/flow/runtime/operator/edge/VisionLocateOperateServiceTest.java b/cmvr-iot-test/src/test/java/com/cmvr/test/flow/runtime/operator/edge/VisionLocateOperateServiceTest.java new file mode 100644 index 0000000..6a7d199 --- /dev/null +++ b/cmvr-iot-test/src/test/java/com/cmvr/test/flow/runtime/operator/edge/VisionLocateOperateServiceTest.java @@ -0,0 +1,258 @@ +package com.cmvr.test.flow.runtime.operator.edge; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.cmvr.llm.analysis.MediaAnalysisClient; +import com.cmvr.test.enums.ActionEnum; +import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage; +import com.cmvr.test.flow.runtime.operator.llm.LLMMediaAnalysisOperateService; +import com.cmvr.test.vision.domain.VisionCalibrationProfile; +import com.cmvr.test.vision.math.VisionCalibrationMath; +import org.junit.Test; + +import java.lang.reflect.Proxy; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.assertEquals; + +public class VisionLocateOperateServiceTest { + + @Test + public void calibratedSafeDirectionKeepsTheFinalFlangeOrientationStable() { + VisionLocateOperateService service = new VisionLocateOperateService( + null, null, null, null); + double[][] currentFlange = VisionCalibrationMath.fromCartesianPose( + cmvr.api.ArmCommand.CartesianPose.newBuilder() + .setRx(0.45).setRy(-0.3).setRz(0.7).build()); + double[][] flangeToTcp = VisionCalibrationMath.fromCartesianPose( + cmvr.api.ArmCommand.CartesianPose.newBuilder() + .setX(0.07).setZ(0.01) + .setRx(0.08).setRy(-0.04).setRz(0.12).build()); + double[][] currentTcp = VisionGeometry.multiply(currentFlange, flangeToTcp); + double[][] safeFlange = VisionCalibrationMath.fromCartesianPose( + cmvr.api.ArmCommand.CartesianPose.newBuilder() + .setRx(Math.PI).setRy(0.04).setRz(-0.2).build()); + VisionCalibrationProfile toolProfile = new VisionCalibrationProfile(); + toolProfile.setId("tool-profile-1"); + toolProfile.setMetadataJson(new JSONObject() + .fluentPut("safeDirectionPose", matrixArray(safeFlange)) + .toJSONString()); + + VisionLocateOperateService.StableToolOrientation orientation = + service.stableToolOrientation(currentTcp, flangeToTcp, toolProfile); + double[][] finalFlange = VisionGeometry.multiply( + orientation.tcpPose(), VisionGeometry.rigidInverse(flangeToTcp)); + + assertEquals("TOOL_CALIBRATION_SAFE_DIRECTION", orientation.source()); + assertRotationEquals(safeFlange, finalFlange, 1e-10); + } + + @Test + public void missingSafeDirectionPreservesCurrentTcpOrientation() { + VisionLocateOperateService service = new VisionLocateOperateService( + null, null, null, null); + double[][] currentTcp = VisionCalibrationMath.fromCartesianPose( + cmvr.api.ArmCommand.CartesianPose.newBuilder() + .setRx(0.2).setRy(0.4).setRz(-0.6).build()); + double[][] identity = VisionCalibrationMath.identity(); + + VisionLocateOperateService.StableToolOrientation orientation = + service.stableToolOrientation(currentTcp, identity, null); + + assertEquals("CURRENT_TCP", orientation.source()); + assertRotationEquals(currentTcp, orientation.tcpPose(), 0.0); + } + + @Test + public void calibratedPlaneMakesTargetZIndependentFromRgbdDepthNoise() { + VisionLocateOperateService service = new VisionLocateOperateService( + null, null, null, null); + double[][] identity = VisionCalibrationMath.identity(); + double[][] safeFlange = VisionCalibrationMath.identity(); + safeFlange[2][3] = 0.5; + VisionCalibrationProfile toolProfile = new VisionCalibrationProfile(); + toolProfile.setId("tool-profile-plane"); + toolProfile.setMetadataJson(new JSONObject() + .fluentPut("safeDirectionPose", matrixArray(safeFlange)) + .fluentPut("planeNormalBase", new JSONArray() + .fluentAdd(0.0).fluentAdd(0.0).fluentAdd(1.0)) + .toJSONString()); + VisionLocateOperateService.StableToolOrientation orientation = + service.stableToolOrientation(identity, identity, toolProfile); + com.cmvr.edge.client.model.camera.EdgeCameraRgbdSnapshot snapshot = + com.cmvr.edge.client.model.camera.EdgeCameraRgbdSnapshot.builder() + .width(640).height(480) + .fx(600).fy(600).cx(320).cy(240) + .build(); + + VisionLocateOperateService.TargetPosition first = service.targetPosition( + identity, snapshot, 380, 240, new double[]{0.056, 0, 0.56}, + List.of(), orientation, 0.0D); + VisionLocateOperateService.TargetPosition second = service.targetPosition( + identity, snapshot, 380, 240, new double[]{0.062, 0, 0.62}, + List.of(), orientation, 0.0D); + + assertEquals("TOOL_CALIBRATION_PLANE_OFFSET", first.source()); + assertEquals(0.05, first.point()[0], 1e-12); + assertEquals(0.5, first.point()[2], 1e-12); + assertEquals(first.point()[2], second.point()[2], 0.0); + assertEquals(60.0, first.depthResidualMm(), 1e-9); + assertEquals(120.0, second.depthResidualMm(), 1e-9); + } + + @Test + public void dynamicParallelPlaneTracksHeightButRejectsDepthOutliers() { + VisionLocateOperateService service = new VisionLocateOperateService( + null, null, null, null); + double[][] identity = VisionCalibrationMath.identity(); + VisionLocateOperateService.StableToolOrientation orientation = + new VisionLocateOperateService.StableToolOrientation( + identity, "TEST", new double[]{0, 0, 0.5}, new double[]{0, 0, 1}); + com.cmvr.edge.client.model.camera.EdgeCameraRgbdSnapshot snapshot = + com.cmvr.edge.client.model.camera.EdgeCameraRgbdSnapshot.builder() + .width(640).height(480) + .fx(600).fy(600).cx(320).cy(240) + .build(); + List lowerSamples = List.of( + pointAtDepth(0.619), pointAtDepth(0.620), pointAtDepth(0.621), + pointAtDepth(0.620), pointAtDepth(0.619), pointAtDepth(0.621), + pointAtDepth(0.620), pointAtDepth(0.620), pointAtDepth(0.619), + pointAtDepth(0.621), pointAtDepth(0.800)); + List higherSamples = List.of( + pointAtDepth(0.679), pointAtDepth(0.680), pointAtDepth(0.681), + pointAtDepth(0.680), pointAtDepth(0.679), pointAtDepth(0.681), + pointAtDepth(0.680), pointAtDepth(0.680), pointAtDepth(0.679), + pointAtDepth(0.681), pointAtDepth(0.900)); + + VisionLocateOperateService.TargetPosition lower = service.targetPosition( + identity, snapshot, 380, 240, new double[]{0.09, 0, 0.90}, + lowerSamples, orientation, null); + VisionLocateOperateService.TargetPosition higher = service.targetPosition( + identity, snapshot, 380, 240, new double[]{0.05, 0, 0.50}, + higherSamples, orientation, null); + + assertEquals("RGBD_PARALLEL_PLANE", lower.source()); + assertEquals(0.620, lower.point()[2], 1e-12); + assertEquals(0.680, higher.point()[2], 1e-12); + assertEquals(0.062, lower.point()[0], 1e-12); + assertEquals(0.068, higher.point()[0], 1e-12); + } + + @Test + public void preciseLocateUsesTheSameImageAnalysisRequestAsGenericPreciseMatch() { + AtomicReference captured = new AtomicReference<>(); + MediaAnalysisClient client = (MediaAnalysisClient) Proxy.newProxyInstance( + MediaAnalysisClient.class.getClassLoader(), + new Class[]{MediaAnalysisClient.class}, + (proxy, method, args) -> { + if (!"analyze".equals(method.getName())) { + throw new UnsupportedOperationException(method.getName()); + } + JSONObject request = (JSONObject) args[0]; + captured.set(request); + return new JSONObject() + .fluentPut("status", "SUCCEEDED") + .fluentPut("analysisType", "IMAGE_ANALYSIS") + .fluentPut("profileCode", "common.image_analysis.v1") + .fluentPut("result", new JSONObject() + .fluentPut("matched", true) + .fluentPut("center", new JSONArray().fluentAdd(610).fluentAdd(238)) + .fluentPut("matchScore", 0.8D)); + } + ); + LLMMediaAnalysisOperateService imageAnalysis = + new LLMMediaAnalysisOperateService(client, null); + + imageAnalysis.execute(imageMessage(genericPreciseMatchInput())); + JSONObject genericRequest = captured.get(); + + VisionLocateOperateService visionLocate = new VisionLocateOperateService( + null, null, imageAnalysis, null); + visionLocate.analyze(visionMessage(), "https://files.example/scene.jpg", + "common.image_analysis.v1", "定位目标中心点", visualLocateInput(), + "REFERENCE_MATCH"); + JSONObject visualRequest = captured.get(); + + assertEquals(genericRequest.getString("analysisType"), visualRequest.getString("analysisType")); + assertEquals(genericRequest.getString("profileCode"), visualRequest.getString("profileCode")); + assertEquals(genericRequest.getString("mediaUrl"), visualRequest.getString("mediaUrl")); + assertEquals(genericRequest.getJSONArray("mediaUrls"), visualRequest.getJSONArray("mediaUrls")); + assertEquals(genericRequest.getJSONObject("options"), visualRequest.getJSONObject("options")); + assertEquals(genericRequest.getJSONObject("context"), visualRequest.getJSONObject("context")); + } + + private JSONObject genericPreciseMatchInput() { + return new JSONObject() + .fluentPut("profileCode", "common.image_analysis.v1") + .fluentPut("imageUrl", new JSONArray().fluentAdd("https://files.example/scene.jpg")) + .fluentPut("referenceImageUrl", "https://files.example/reference.png") + .fluentPut("prompt", "在大图中查找小图,返回原图像素坐标 [x1,y1,x2,y2]") + .fluentPut("analysisMethod", "REFERENCE_MATCH") + .fluentPut("analysisMode", "FAST") + .fluentPut("asynchronous", false) + .fluentPut("analysisTuning", new JSONObject() + .fluentPut("maxWidth", 896) + .fluentPut("maxImages", 12) + .fluentPut("maxOutputTokens", 384) + .fluentPut("matchThreshold", 0.48D) + .fluentPut("matchSelector", "BEST") + .fluentPut("matchIndex", 1) + .fluentPut("matchSort", "ROW_MAJOR") + .fluentPut("locateConfidenceThreshold", 0.45D)); + } + + private JSONObject visualLocateInput() { + return new JSONObject() + .fluentPut("referenceImageUrl", "https://files.example/reference.png") + .fluentPut("analysisMode", "ACCURATE") + .fluentPut("matchSelector", "BEST") + .fluentPut("matchIndex", "1") + .fluentPut("matchSort", "ROW_MAJOR") + .fluentPut("confidenceThreshold", "0.45"); + } + + private TaskNodeExecuteMessage imageMessage(JSONObject input) { + TaskNodeExecuteMessage message = baseMessage(); + message.setAction(ActionEnum.IMAGE_ANALYZE); + message.setInputParams(input); + return message; + } + + private TaskNodeExecuteMessage visionMessage() { + TaskNodeExecuteMessage message = baseMessage(); + message.setAction(ActionEnum.VISION_LOCATE_TARGET); + message.setInputParams(visualLocateInput()); + return message; + } + + private TaskNodeExecuteMessage baseMessage() { + TaskNodeExecuteMessage message = new TaskNodeExecuteMessage(); + message.setInstId("inst-1"); + message.setTaskId("task-1"); + message.setItemId("item-1"); + message.setNodeId("node-1"); + message.setTrial(true); + return message; + } + + private JSONArray matrixArray(double[][] matrix) { + JSONArray values = new JSONArray(); + for (double[] row : matrix) { + for (double value : row) values.add(value); + } + return values; + } + + private double[] pointAtDepth(double depth) { + return new double[]{0, 0, depth}; + } + + private void assertRotationEquals(double[][] expected, double[][] actual, double tolerance) { + for (int row = 0; row < 3; row++) { + for (int column = 0; column < 3; column++) { + assertEquals(expected[row][column], actual[row][column], tolerance); + } + } + } +} diff --git a/cmvr-iot-test/src/test/java/com/cmvr/test/flow/runtime/operator/llm/InspectionWaypointCorpusOperateServiceTest.java b/cmvr-iot-test/src/test/java/com/cmvr/test/flow/runtime/operator/llm/InspectionWaypointCorpusOperateServiceTest.java new file mode 100644 index 0000000..350a8f3 --- /dev/null +++ b/cmvr-iot-test/src/test/java/com/cmvr/test/flow/runtime/operator/llm/InspectionWaypointCorpusOperateServiceTest.java @@ -0,0 +1,75 @@ +package com.cmvr.test.flow.runtime.operator.llm; + +import com.alibaba.fastjson2.JSONObject; +import com.cmvr.common.exception.GlobalException; +import com.cmvr.test.enums.ActionEnum; +import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage; +import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult; +import com.cmvr.test.mapper.InspectionWaypointCorpusMapper; +import com.cmvr.test.model.vo.inspection.InspectionWaypointCorpusVO; +import org.junit.Test; + +import java.lang.reflect.Proxy; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class InspectionWaypointCorpusOperateServiceTest +{ + @Test + public void returnsChineseCorpus() + { + InspectionWaypointCorpusOperateService service = service("开始巡检", "Start inspection"); + + TaskNodeExecuteResult result = service.execute(message("zh-CN")); + + assertTrue(result.isSuccess()); + assertEquals("开始巡检", result.getOutputParams().getString("corpus")); + } + + @Test + public void returnsEnglishCorpusForNumericType() + { + InspectionWaypointCorpusOperateService service = service("开始巡检", "Start inspection"); + + TaskNodeExecuteResult result = service.execute(message(1)); + + assertEquals("Start inspection", result.getOutputParams().getString("corpus")); + assertTrue(service.supports(ActionEnum.INSPECTION_WAYPOINT_CORPUS)); + } + + @Test(expected = GlobalException.class) + public void rejectsUnsupportedCorpusType() + { + service("开始巡检", "Start inspection").execute(message("fr-FR")); + } + + private InspectionWaypointCorpusOperateService service(String chineseCorpus, String englishCorpus) + { + InspectionWaypointCorpusVO waypoint = new InspectionWaypointCorpusVO(); + waypoint.setChineseCorpus(chineseCorpus); + waypoint.setEnglishCorpus(englishCorpus); + InspectionWaypointCorpusMapper mapper = (InspectionWaypointCorpusMapper) Proxy.newProxyInstance( + InspectionWaypointCorpusMapper.class.getClassLoader(), + new Class[]{InspectionWaypointCorpusMapper.class}, + (proxy, method, args) -> { + if ("selectByDetectItemId".equals(method.getName())) + { + assertEquals("detect-item-1", args[0]); + return waypoint; + } + throw new UnsupportedOperationException(method.getName()); + }); + return new InspectionWaypointCorpusOperateService(mapper); + } + + private TaskNodeExecuteMessage message(Object type) + { + TaskNodeExecuteMessage message = new TaskNodeExecuteMessage(); + message.setAction(ActionEnum.INSPECTION_WAYPOINT_CORPUS); + message.setInputParams(new JSONObject() + .fluentPut("detectItemId", "detect-item-1") + .fluentPut("type", type)); + return message; + } +} diff --git a/sql/inspection_waypoint_corpus.sql b/sql/inspection_waypoint_corpus.sql new file mode 100644 index 0000000..6b93f9b --- /dev/null +++ b/sql/inspection_waypoint_corpus.sql @@ -0,0 +1,4 @@ +-- 巡检点位增加中英文可播放语料。 +ALTER TABLE `inspection_waypoint` + ADD COLUMN `chinese_corpus` text DEFAULT NULL COMMENT '该点位可播放的中文语料' AFTER `detect_item_id`, + ADD COLUMN `english_corpus` text DEFAULT NULL COMMENT '该点位可播放的英文语料' AFTER `chinese_corpus`;