diff --git a/nflg-qms-admin/src/test/java/com/nflg/qms/admin/QmsIncomingInspectionTaskApiTest.java b/nflg-qms-admin/src/test/java/com/nflg/qms/admin/QmsIncomingInspectionTaskApiTest.java
new file mode 100644
index 00000000..242115f9
--- /dev/null
+++ b/nflg-qms-admin/src/test/java/com/nflg/qms/admin/QmsIncomingInspectionTaskApiTest.java
@@ -0,0 +1,393 @@
+package com.nflg.qms.admin;
+
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.lang.TypeReference;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.json.JSONUtil;
+import com.nflg.wms.common.pojo.ApiResult;
+import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTodoCheckSubmitItemDataQO;
+import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTodoCheckSubmitItemQO;
+import com.nflg.wms.common.pojo.qo.QmsIncomingInspectionTaskTodoCheckSubmitQO;
+import com.nflg.wms.common.pojo.vo.FileUploadVO;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 提交检测项(addCheckItem)接口测试
+ *
+ * 测试前提:
+ * 1. qms-admin 服务已启动(默认 http://localhost:8105)
+ * 2. 测试账号已登录,将有效的 token 填入 TOKEN 常量
+ * 3. 数据库中存在有效的任务ID(VALID_TASK_ID)和对应的物料唯一编号(VALID_MATERIAL_UNIQUE_NO)
+ * 4. VALID_STANDARD_ITEM_CONTENT_ID 对应数据库中已存在的检验标准项内容ID
+ *
+ */
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class QmsIncomingInspectionTaskApiTest {
+
+ // ===================== 配置区 =====================
+ /** 服务地址 */
+ private static final String BASE_URL = "http://localhost:8105";
+ /** 当前登录用户的 token */
+ private static final String TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOjEsInJuU3RyIjoiU0VxNWhlcXdHOERvVTBkeWFLZnZDbW1FTGFuek5jQlMiLCJuYW1lIjoi6LaF57qn566h55CG5ZGYIiwiY29kZSI6ImFkbWluIiwicm9sZXMiOlsiU3VwZXJBZG1pbiJdLCJ0eXBlIjoxfQ.wuEnMU5vJSqh2vr69MKooFUHD04-_-86eeJee_2zir4";
+ /** 有效的任务ID */
+ private static final Long VALID_TASK_ID = 2046829044461977601L;
+ /** 有效的物料唯一编号 */
+ private static final String VALID_MATERIAL_UNIQUE_NO = "MAT_UNIQUE_001";
+ /** 有效的检验标准项内容ID */
+ private static final Long VALID_STANDARD_ITEM_CONTENT_ID = 2047511371773046785L;
+ // ===================== 配置区结束 =====================
+
+ // ==================== HTTP 工具方法 ====================
+
+ private static ApiResult post(String path, Object body, TypeReference> typeRef) {
+ String url = BASE_URL + path;
+ String reqBody = body == null ? "" : JSONUtil.toJsonStr(body);
+ HttpResponse resp = HttpRequest.post(url)
+ .header("authorization", TOKEN)
+ .header("Content-Type", "application/json")
+ .body(reqBody)
+ .execute();
+ String raw = resp.body();
+ System.out.println("[POST] " + path);
+ System.out.println(" 请求: " + reqBody);
+ System.out.println(" 响应: " + raw);
+ return JSONUtil.toBean(raw, typeRef, false);
+ }
+
+ private static void assertSuccess(ApiResult result, String msg) {
+ Assert.isTrue(result != null && result.getCode() == 200,
+ () -> new RuntimeException(msg + " => " + JSONUtil.toJsonStr(result)));
+ }
+
+ private static void assertFailed(ApiResult> result, String msg) {
+ Assert.isTrue(result != null && result.getCode() != 200,
+ () -> new RuntimeException(msg + " => 预期失败但实际成功"));
+ }
+
+ // ==================== 提交检测项接口测试 ====================
+
+ /**
+ * 【提交检测项】正常提交(所有样本合格)
+ * 验证点:
+ * 1. 接口返回成功
+ * 2. inspectionQty == qualifiedQty,记录应标记为合格
+ */
+ @Test
+ @Order(1)
+ public void test01_addCheckItem_Success_AllQualified() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.setQualifiedQty(5);
+ request.setUnqualifiedQty(0);
+ request.setInspectionQty(5);
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertSuccess(result, "提交检测项(全部合格)失败");
+ System.out.println(" ✅ 提交检测项(全部合格)成功");
+ }
+
+ /**
+ * 【提交检测项】正常提交(存在不合格样本)
+ * 验证点:
+ * 1. 接口返回成功
+ * 2. qualifiedQty < inspectionQty,记录应标记为不合格
+ */
+ @Test
+ @Order(2)
+ public void test02_addCheckItem_Success_PartialUnqualified() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.setQualifiedQty(3);
+ request.setUnqualifiedQty(2);
+ request.setInspectionQty(5);
+
+ // 不合格样本设置 qualified=false
+ QmsIncomingInspectionTaskTodoCheckSubmitItemDataQO unqualifiedData =
+ buildItemData(false, new BigDecimal("9.5"), Collections.emptyList());
+ request.getItems().get(0).getDatas().add(unqualifiedData);
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertSuccess(result, "提交检测项(含不合格样本)失败");
+ System.out.println(" ✅ 提交检测项(含不合格样本)成功");
+ }
+
+ /**
+ * 【提交检测项】带图片的样本提交
+ * 验证点:图片ID能正常保存到检验数据记录
+ */
+ @Test
+ @Order(3)
+ public void test03_addCheckItem_Success_WithImages() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+
+ FileUploadVO image = new FileUploadVO(100L, "test_image.jpg", "http://example.com/test_image.jpg");
+ request.getItems().get(0).getDatas().get(0).setImages(List.of(image));
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertSuccess(result, "带图片提交检测项失败");
+ System.out.println(" ✅ 带图片提交检测项成功");
+ }
+
+ /**
+ * 【提交检测项】带备注的检验项提交
+ * 验证点:备注字段能正常保存
+ */
+ @Test
+ @Order(4)
+ public void test04_addCheckItem_Success_WithRemark() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.getItems().get(0).setRemark("外观轻微划痕,不影响功能");
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertSuccess(result, "带备注提交检测项失败");
+ System.out.println(" ✅ 带备注提交检测项成功");
+ }
+
+ /**
+ * 【提交检测项】更新已有检验记录(传入已有ID)
+ * 验证点:当 id 不为 null 时,接口执行 saveOrUpdate 逻辑,更新已有记录
+ */
+ @Test
+ @Order(5)
+ public void test05_addCheckItem_Success_UpdateExisting() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.setId(1L); // 已存在的记录ID,根据实际环境替换
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertSuccess(result, "更新已有检验记录失败");
+ System.out.println(" ✅ 更新已有检验记录成功");
+ }
+
+ /**
+ * 【提交检测项】任务ID为空
+ * 验证点:接口返回参数校验错误(@NotNull 校验)
+ */
+ @Test
+ @Order(6)
+ public void test06_addCheckItem_Fail_TaskIdNull() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.setTaskId(null);
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertFailed(result, "任务ID为空应返回失败");
+ System.out.println(" ✅ 任务ID为空校验通过");
+ }
+
+ /**
+ * 【提交检测项】物料唯一编号为空
+ * 验证点:接口返回参数校验错误(@NotNull 校验)
+ */
+ @Test
+ @Order(7)
+ public void test07_addCheckItem_Fail_MaterialUniqueNoNull() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.setMaterialUniqueNo(null);
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertFailed(result, "物料唯一编号为空应返回失败");
+ System.out.println(" ✅ 物料唯一编号为空校验通过");
+ }
+
+ /**
+ * 【提交检测项】样本数量为空
+ * 验证点:接口返回参数校验错误(@NotNull 校验)
+ */
+ @Test
+ @Order(8)
+ public void test08_addCheckItem_Fail_InspectionQtyNull() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.setInspectionQty(null);
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertFailed(result, "样本数量为空应返回失败");
+ System.out.println(" ✅ 样本数量为空校验通过");
+ }
+
+ /**
+ * 【提交检测项】合格数量为空
+ * 验证点:接口返回参数校验错误(@NotNull 校验)
+ */
+ @Test
+ @Order(9)
+ public void test09_addCheckItem_Fail_QualifiedQtyNull() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.setQualifiedQty(null);
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertFailed(result, "合格数量为空应返回失败");
+ System.out.println(" ✅ 合格数量为空校验通过");
+ }
+
+ /**
+ * 【提交检测项】不合格数量为空
+ * 验证点:接口返回参数校验错误(@NotNull 校验)
+ */
+ @Test
+ @Order(10)
+ public void test10_addCheckItem_Fail_UnqualifiedQtyNull() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.setUnqualifiedQty(null);
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertFailed(result, "不合格数量为空应返回失败");
+ System.out.println(" ✅ 不合格数量为空校验通过");
+ }
+
+ /**
+ * 【提交检测项】检验项列表为空
+ * 验证点:接口返回参数校验错误(@NotEmpty 校验)
+ */
+ @Test
+ @Order(11)
+ public void test11_addCheckItem_Fail_ItemsEmpty() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.setItems(Collections.emptyList());
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertFailed(result, "检验项列表为空应返回失败");
+ System.out.println(" ✅ 检验项列表为空校验通过");
+ }
+
+ /**
+ * 【提交检测项】检验项列表为null
+ * 验证点:接口返回参数校验错误(@NotEmpty 校验)
+ */
+ @Test
+ @Order(12)
+ public void test12_addCheckItem_Fail_ItemsNull() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.setItems(null);
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertFailed(result, "检验项列表为null应返回失败");
+ System.out.println(" ✅ 检验项列表为null校验通过");
+ }
+
+ /**
+ * 【提交检测项】检验项中检验标准项内容ID为空
+ * 验证点:接口返回参数校验错误(@NotNull 级联校验)
+ */
+ @Test
+ @Order(13)
+ public void test13_addCheckItem_Fail_ItemContentIdNull() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.getItems().get(0).setInspectionStandardItemContentId(null);
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertFailed(result, "检验标准项内容ID为空应返回失败");
+ System.out.println(" ✅ 检验标准项内容ID为空校验通过");
+ }
+
+ /**
+ * 【提交检测项】检验项的样本列表为空
+ * 验证点:接口返回参数校验错误(@NotEmpty 级联校验)
+ */
+ @Test
+ @Order(14)
+ public void test14_addCheckItem_Fail_ItemDatasEmpty() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.getItems().get(0).setDatas(Collections.emptyList());
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertFailed(result, "样本列表为空应返回失败");
+ System.out.println(" ✅ 样本列表为空校验通过");
+ }
+
+ /**
+ * 【提交检测项】样本中是否合格字段为空
+ * 验证点:接口返回参数校验错误(@NotNull 级联校验)
+ */
+ @Test
+ @Order(15)
+ public void test15_addCheckItem_Fail_DataQualifiedNull() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+ request.getItems().get(0).getDatas().get(0).setQualified(null);
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertFailed(result, "是否合格字段为空应返回失败");
+ System.out.println(" ✅ 是否合格字段为空校验通过");
+ }
+
+ /**
+ * 【提交检测项】多个检验项提交
+ * 验证点:可以一次提交多个检验项,每项下有多个样本数据
+ */
+ @Test
+ @Order(16)
+ public void test16_addCheckItem_Success_MultipleItems() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = buildValidRequest();
+
+ QmsIncomingInspectionTaskTodoCheckSubmitItemQO item2 = buildItem(VALID_STANDARD_ITEM_CONTENT_ID + 1, null);
+ request.setItems(new ArrayList<>(List.of(request.getItems().get(0), item2)));
+
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", request, new TypeReference<>() {});
+ assertSuccess(result, "多个检验项提交失败");
+ System.out.println(" ✅ 多个检验项提交成功");
+ }
+
+ /**
+ * 【提交检测项】请求体为空(无请求体)
+ * 验证点:接口返回参数解析或校验错误
+ */
+ @Test
+ @Order(17)
+ public void test17_addCheckItem_Fail_EmptyBody() {
+ ApiResult result = post("/incoming-inspection-task/pad/add-check-item", null, new TypeReference<>() {});
+ assertFailed(result, "空请求体应返回失败");
+ System.out.println(" ✅ 空请求体校验通过");
+ }
+
+ // ==================== 辅助方法 ====================
+
+ /**
+ * 构建一个有效的提交检测项请求
+ */
+ private QmsIncomingInspectionTaskTodoCheckSubmitQO buildValidRequest() {
+ QmsIncomingInspectionTaskTodoCheckSubmitQO request = new QmsIncomingInspectionTaskTodoCheckSubmitQO();
+ request.setTaskId(VALID_TASK_ID);
+ request.setMaterialUniqueNo(VALID_MATERIAL_UNIQUE_NO);
+ request.setInspectionQty(5);
+ request.setQualifiedQty(5);
+ request.setUnqualifiedQty(0);
+ request.setItems(new ArrayList<>(List.of(buildItem(VALID_STANDARD_ITEM_CONTENT_ID, null))));
+ return request;
+ }
+
+ /**
+ * 构建一个检验项
+ *
+ * @param contentId 检验标准项内容ID
+ * @param remark 备注(可为null)
+ */
+ private QmsIncomingInspectionTaskTodoCheckSubmitItemQO buildItem(Long contentId, String remark) {
+ QmsIncomingInspectionTaskTodoCheckSubmitItemQO item = new QmsIncomingInspectionTaskTodoCheckSubmitItemQO();
+ item.setInspectionStandardItemContentId(contentId);
+ item.setRemark(remark);
+ item.setDatas(new ArrayList<>(List.of(buildItemData(true, new BigDecimal("10.5"), Collections.emptyList()))));
+ return item;
+ }
+
+ /**
+ * 构建一个样本数据
+ *
+ * @param qualified 是否合格
+ * @param measuredValue 测量值(可为null)
+ * @param images 图片列表
+ */
+ private QmsIncomingInspectionTaskTodoCheckSubmitItemDataQO buildItemData(
+ Boolean qualified, BigDecimal measuredValue, List images) {
+ QmsIncomingInspectionTaskTodoCheckSubmitItemDataQO data =
+ new QmsIncomingInspectionTaskTodoCheckSubmitItemDataQO();
+ data.setQualified(qualified);
+ data.setMeasuredValue(measuredValue);
+ data.setImages(images);
+ return data;
+ }
+}