From e97b55310155a2dd691bd698a10295a4d867f60c Mon Sep 17 00:00:00 2001
From: baoshiwei <baoshiwei@shlanbao.cn>
Date: 星期五, 17 四月 2026 15:55:51 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmJudgeDetails.java                                                         |    8 
 ruoyi-plus-soybean/src/router/elegant/routes.ts                                                                                                          |   27 
 ruoyi-plus-soybean/src/views/qm/batch/modules/batch-operate-drawer.vue                                                                                   |  280 -
 ruoyi-plus-soybean/src/service/api/qm/judge-details.ts                                                                                                   |   10 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/vo/MdMatTypeVo.java                                                         |  106 +
 RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java                            |   11 
 RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports |    2 
 ruoyi-plus-soybean/src/typings/api/md.mat-type.api.d.ts                                                                                                  |   76 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmMatcheckMapper.java                                                       |   38 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmJudgeServiceImpl.java                                               |   61 
 ruoyi-plus-soybean/src/views/md/mat-type/index.vue                                                                                                       |  241 ++
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmBatchVo.java                                                           |   15 
 ruoyi-plus-soybean/src/views/qm/judge/modules/judge-operate-drawer.vue                                                                                   |   59 
 ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-operate-drawer.vue                                                                   |   70 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeDetailsVo.java                                                    |   54 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/impl/MdMatServiceImpl.java                                                 |  147 +
 RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/MatNameTranslationImpl.java                  |   28 
 RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/MatService.java                                              |   13 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/controller/MdMatController.java                                                    |  105 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmMatcheckMapper.xml                                                               |   67 
 ruoyi-plus-soybean/src/views/qm/judge/modules/judge-search.vue                                                                                           |   54 
 RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/JudgeNameTranslationImpl.java                |   26 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmMatcheckService.java                                                    |   85 
 RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/JudgeService.java                                            |   13 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/MdMatType.java                                                              |   87 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/bo/MdMatBo.java                                                             |   97 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmMatcheckBo.java                                                        |  183 +
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/mapper/MdMatMapper.java                                                            |   15 
 ruoyi-plus-soybean/src/typings/elegant-router.d.ts                                                                                                       |    6 
 ruoyi-plus-soybean/src/views/qm/matcheck/index.vue                                                                                                       |  268 ++
 ruoyi-plus-soybean/src/service/api/qm/matcheck.ts                                                                                                        |   57 
 ruoyi-plus-soybean/src/views/qm/matcheck/modules/matcheck-search.vue                                                                                     |   93 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/MdMat.java                                                                  |   97 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmMatcheckController.java                                               |  122 +
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmJudgeDetailsServiceImpl.java                                        |   45 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/IMdMatTypeService.java                                                     |   68 
 ruoyi-plus-soybean/src/views/qm/matcheck/modules/matcheck-operate-drawer.vue                                                                             |  266 ++
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/test                                                                                  |    0 
 ruoyi-plus-soybean/src/router/elegant/transform.ts                                                                                                       |    3 
 ruoyi-plus-soybean/src/typings/api/qm.judge-details.api.d.ts                                                                                             |   40 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmJudgeDetailsBo.java                                                    |    8 
 ruoyi-plus-soybean/src/views/qm/judge/index.vue                                                                                                          |  103 
 ruoyi-plus-soybean/src/typings/api/qm.batch.api.d.ts                                                                                                     |    4 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmMatcheck.java                                                             |  184 +
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/vo/MdMatVo.java                                                             |  118 +
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/mapper/MdMatTypeMapper.java                                                        |   15 
 ruoyi-plus-soybean/src/service/api/md/mat.ts                                                                                                             |   35 
 ruoyi-plus-soybean/src/views/md/mat/modules/mat-operate-drawer.vue                                                                                       |  184 +
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmMatcheckVo.java                                                        |  255 ++
 ruoyi-plus-soybean/src/views/md/mat/index.vue                                                                                                            |  283 ++
 ruoyi-plus-soybean/src/typings/api/md.mat.api.d.ts                                                                                                       |   83 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeVo.java                                                           |    1 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/bo/MdMatTypeBo.java                                                         |   87 
 ruoyi-plus-soybean/src/views/qm/batch/index.vue                                                                                                          |  231 +
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmJudgeDetailsController.java                                           |   10 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/md/MdMatMapper.xml                                                                    |    6 
 ruoyi-plus-soybean/src/views/md/mat-type/modules/mat-type-operate-drawer.vue                                                                             |  171 +
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/md/MdMatTypeMapper.xml                                                                |    6 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmMatcheckServiceImpl.java                                            |  154 +
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/impl/MdMatTypeServiceImpl.java                                             |  138 +
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmJudgeDetailsService.java                                                |    8 
 ruoyi-plus-soybean/src/typings/api/qm.matcheck.api.d.ts                                                                                                  |  165 +
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/controller/MdMatTypeController.java                                                |  105 
 ruoyi-plus-soybean/src/router/elegant/imports.ts                                                                                                         |    3 
 ruoyi-plus-soybean/src/views/md/mat/modules/mat-search.vue                                                                                               |  119 +
 ruoyi-plus-soybean/src/views/qm/batch/modules/batch-search.vue                                                                                           |  166 
 ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-sub-table.vue                                                                        |  414 +++
 ruoyi-plus-soybean/src/service/api/md/mat-type.ts                                                                                                        |   35 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/test                                                                                  |    0 
 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/IMdMatService.java                                                         |   68 
 ruoyi-plus-soybean/src/views/md/mat-type/modules/mat-type-search.vue                                                                                     |   99 
 71 files changed, 5,838 insertions(+), 463 deletions(-)

diff --git a/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/JudgeService.java b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/JudgeService.java
new file mode 100644
index 0000000..36c1903
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/JudgeService.java
@@ -0,0 +1,13 @@
+package org.dromara.common.core.service;
+
+/**
+ * 鍒ゅ畾渚濇嵁
+ */
+public interface JudgeService {
+    /**
+     * 鍒ゅ畾渚濇嵁code杞琻ame
+     * @param judgeCode
+     * @return
+     */
+    String selectJudgeNameByCode(String judgeCode);
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/MatService.java b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/MatService.java
new file mode 100644
index 0000000..283acda
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/MatService.java
@@ -0,0 +1,13 @@
+package org.dromara.common.core.service;
+
+/**
+ * 鐗╂枡
+ */
+public interface MatService {
+    /**
+     * 鐗╂枡code杞琻ame
+     * @param matCode
+     * @return
+     */
+    String selectMatNameByCode(String matCode);
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java
index c084ea1..254b13c 100755
--- a/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java
+++ b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java
@@ -32,4 +32,15 @@
      */
     String OSS_ID_TO_URL = "oss_id_to_url";
 
+
+    /**
+     * 鐗╂枡code杞琻ame
+     */
+    String MAT_CODE_TO_NAME = "mat_code_to_name";
+
+    /**
+     * 鍒ゅ畾渚濇嵁code杞琻ame
+     */
+    String JUDGE_CODE_TO_NAME = "judge_code_to_name";
+
 }
diff --git a/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/JudgeNameTranslationImpl.java b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/JudgeNameTranslationImpl.java
new file mode 100755
index 0000000..9234fd2
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/JudgeNameTranslationImpl.java
@@ -0,0 +1,26 @@
+package org.dromara.common.translation.core.impl;
+
+import lombok.AllArgsConstructor;
+import org.dromara.common.core.service.JudgeService;
+import org.dromara.common.core.service.MatService;
+import org.dromara.common.translation.annotation.TranslationType;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.common.translation.core.TranslationInterface;
+
+/**
+ * judgeName缈昏瘧瀹炵幇
+ *
+ * @author zhuguifei
+ */
+@AllArgsConstructor
+@TranslationType(type = TransConstant.JUDGE_CODE_TO_NAME)
+public class JudgeNameTranslationImpl implements TranslationInterface<String> {
+
+    private final JudgeService judgeService;
+
+    @Override
+    public String translation(Object key, String other) {
+        if(key == null) return  "";
+        return judgeService.selectJudgeNameByCode(key.toString());
+    }
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/MatNameTranslationImpl.java b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/MatNameTranslationImpl.java
new file mode 100755
index 0000000..39d48cf
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/MatNameTranslationImpl.java
@@ -0,0 +1,28 @@
+package org.dromara.common.translation.core.impl;
+
+import cn.hutool.core.convert.Convert;
+import lombok.AllArgsConstructor;
+import org.dromara.common.core.service.MatService;
+import org.dromara.common.core.service.UserService;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.translation.annotation.TranslationType;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.common.translation.core.TranslationInterface;
+
+/**
+ * matName缈昏瘧瀹炵幇
+ *
+ * @author zhuguifei
+ */
+@AllArgsConstructor
+@TranslationType(type = TransConstant.MAT_CODE_TO_NAME)
+public class MatNameTranslationImpl implements TranslationInterface<String> {
+
+    private final MatService matService;
+
+    @Override
+    public String translation(Object key, String other) {
+        if(key == null) return  "";
+        return matService.selectMatNameByCode(key.toString());
+    }
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
index ad40205..88a1ea3 100755
--- a/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -4,3 +4,5 @@
 org.dromara.common.translation.core.impl.OssUrlTranslationImpl
 org.dromara.common.translation.core.impl.UserNameTranslationImpl
 org.dromara.common.translation.core.impl.NicknameTranslationImpl
+org.dromara.common.translation.core.impl.MatNameTranslationImpl
+org.dromara.common.translation.core.impl.JudgeNameTranslationImpl
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmJudgeDetailsController.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmJudgeDetailsController.java
index c58d4d6..20b4367 100644
--- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmJudgeDetailsController.java
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmJudgeDetailsController.java
@@ -46,6 +46,16 @@
     }
 
     /**
+     * 鏌ヨ鍒ゅ畾妯℃澘鏄庣粏鏍戝舰缁撴瀯鍒楄〃
+     */
+    @SaCheckPermission("qm:judgeDetails:list")
+    @GetMapping("/tree")
+    public TableDataInfo<QmJudgeDetailsVo> tree(@RequestParam @NotBlank(message = "judgeId涓嶈兘涓虹┖") String judgeId) {
+        List<QmJudgeDetailsVo> list = qmJudgeDetailsService.queryTreeListByJudgeId(judgeId);
+        return TableDataInfo.build(list);
+    }
+
+    /**
      * 瀵煎嚭鍒ゅ畾妯℃澘鏄庣粏鍒楄〃
      */
     @SaCheckPermission("qm:judgeDetails:export")
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmMatcheckController.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmMatcheckController.java
new file mode 100644
index 0000000..5bf78c1
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmMatcheckController.java
@@ -0,0 +1,122 @@
+package org.dromara.qa.qm.controller;
+
+import java.util.List;
+import java.util.Map;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.qa.qm.domain.vo.QmMatcheckVo;
+import org.dromara.qa.qm.domain.bo.QmMatcheckBo;
+import org.dromara.qa.qm.service.IQmMatcheckService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 鏉愭枡妫�楠岀粺璁�
+ *
+ * @author zhuguifei
+ * @date 2026-04-15
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/qm/matcheck")
+public class QmMatcheckController extends BaseController {
+
+    private final IQmMatcheckService qmMatcheckService;
+
+    /**
+     * 鏌ヨ鏉愭枡妫�楠岀粺璁″垪琛�
+     */
+    @SaCheckPermission("qm:matcheck:list")
+    @GetMapping("/list")
+    public TableDataInfo<QmMatcheckVo> list(QmMatcheckBo bo, PageQuery pageQuery) {
+        return qmMatcheckService.queryPageList(bo, pageQuery);
+    }
+
+
+    @SaCheckPermission("qm:matcheck:list")
+    @GetMapping("/listCheckItem")
+    public R<List<Map<String, Object>>> listCheckItem(@RequestParam String judgeId) {
+        return R.ok(qmMatcheckService.getQmCheckItem(judgeId));
+    }
+
+    /**
+     * 鎸夋壒娆″拰鐗屽彿鏌ヨ鏉愭枡妫�楠岀粺璁�(澶氳〃)
+     */
+    @SaCheckPermission("qm:matcheck:list")
+    @GetMapping("/listQmMatcheck")
+    public TableDataInfo<QmMatcheckVo> listQmMatcheck(QmMatcheckBo bo, PageQuery pageQuery) {
+        return TableDataInfo.build(qmMatcheckService.listQmMatcheck(bo), pageQuery.build());
+    }
+
+    /**
+     * 瀵煎嚭鏉愭枡妫�楠岀粺璁″垪琛�
+     */
+    @SaCheckPermission("qm:matcheck:export")
+    @Log(title = "鏉愭枡妫�楠岀粺璁�", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(QmMatcheckBo bo, HttpServletResponse response) {
+        List<QmMatcheckVo> list = qmMatcheckService.queryList(bo);
+        ExcelUtil.exportExcel(list, "鏉愭枡妫�楠岀粺璁�", QmMatcheckVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇鏉愭枡妫�楠岀粺璁¤缁嗕俊鎭�
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("qm:matcheck:query")
+    @GetMapping("/{id}")
+    public R<QmMatcheckVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable String id) {
+        return R.ok(qmMatcheckService.queryById(id));
+    }
+
+    /**
+     * 鏂板鏉愭枡妫�楠岀粺璁�
+     */
+    @SaCheckPermission("qm:matcheck:add")
+    @Log(title = "鏉愭枡妫�楠岀粺璁�", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody QmMatcheckBo bo) {
+        return toAjax(qmMatcheckService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼鏉愭枡妫�楠岀粺璁�
+     */
+    @SaCheckPermission("qm:matcheck:edit")
+    @Log(title = "鏉愭枡妫�楠岀粺璁�", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody QmMatcheckBo bo) {
+        return toAjax(qmMatcheckService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎鏉愭枡妫�楠岀粺璁�
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("qm:matcheck:remove")
+    @Log(title = "鏉愭枡妫�楠岀粺璁�", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable String[] ids) {
+        return toAjax(qmMatcheckService.deleteWithValidByIds(List.of(ids), true));
+    }
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmJudgeDetails.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmJudgeDetails.java
index 1b07cdf..a7b227e 100644
--- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmJudgeDetails.java
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmJudgeDetails.java
@@ -44,17 +44,17 @@
     /**
      * 鏍囧噯鍊�
      */
-    private Long value3;
+    private Double value3;
 
     /**
      * 鍒ゅ畾鍊�1
      */
-    private Long value1;
+    private Double value1;
 
     /**
      * 鍒ゅ畾鍊�2
      */
-    private Long value2;
+    private Double value2;
 
     /**
      * 缂洪櫡浣嶇疆
@@ -69,7 +69,7 @@
     /**
      * 鍒嗗�兼爣鍑� (鎵e垎鏍囧噯锛屽緱鍒嗘爣鍑�),姣斿涓嶅悎鏍间竴娆℃墸澶氬皯鍒�
      */
-    private Long stdscore;
+    private Double stdscore;
 
     /**
      * 鏍囪姝ら」鏄惁涓哄悎鎴愰」鐩紝姣斿澶栬锛屽疄闄呬笂鍏宠仈浜嗗緢澶氬瓙椤圭洰
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmMatcheck.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmMatcheck.java
new file mode 100644
index 0000000..e3f73e4
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmMatcheck.java
@@ -0,0 +1,184 @@
+package org.dromara.qa.qm.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+
+import java.io.Serial;
+import java.util.Date;
+
+/**
+ * 鏉愭枡妫�楠岀粺璁″璞� qm_matcheck
+ *
+ * @author zhuguifei
+ * @date 2026-04-15
+ */
+@Data
+@TableName("qm_matcheck")
+public class QmMatcheck  {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @TableId(value = "id")
+    private String id;
+
+    /**
+     * 姹囨�昏〃ID
+     */
+    private String pid;
+
+    /**
+     * 妫�楠屾壒娆�
+     */
+    private String batchCode;
+
+    /**
+     * 鐗屽彿
+     */
+    private String matCode;
+
+    /**
+     * 浠櫒缂栧彿
+     */
+    private String instrumentCode;
+
+    /**
+     * 鎶�鏈姹�
+     */
+    private String techReq;
+
+    /**
+     * 妫�楠屼緷鎹�
+     */
+    private String checkStd;
+
+    /**
+     * 娴嬭瘯鐜
+     */
+    private String testEnv;
+
+    /**
+     * 妫�楠岄」鐩瓹OD
+     */
+    private String itemCode;
+
+    /**
+     * 鐩樺彿
+     */
+    private String subBatchCode;
+
+    /**
+     * 姣忕洏妫�楠屾暟閲�
+     */
+    private Long sampleNumber;
+
+    /**
+     * 鍙栨牱绫诲瀷
+     */
+    private Long sampleType;
+
+    /**
+     * 妫�楠屽憳
+     */
+    private String checkName;
+
+    /**
+     * 妫�楠屾椂闂�
+     */
+    private Date checkTime;
+
+    /**
+     * 澶嶆牳鍛�
+     */
+    private String reviewName;
+
+    /**
+     * 澶嶆牳鏃堕棿
+     */
+    private Date reviewTime;
+
+    /**
+     * 鏈�澶у��
+     */
+    private Double maxval;
+
+    /**
+     * 鏈�灏忓��
+     */
+    private Double minval;
+
+    /**
+     * 骞冲潎鍊�
+     */
+    private Double avgval;
+
+    /**
+     * SD鍊�
+     */
+    private Double sdval;
+
+    /**
+     * CV鍊�
+     */
+    private Double cvval;
+
+    /**
+     * CPK鍊�
+     */
+    private Double cpkval;
+
+    /**
+     * 瓒呮爣鏁�
+     */
+    private Double badval;
+
+    /**
+     * 鍒ゅ畾
+     */
+    private String judge;
+
+    /**
+     * 鍗曢」鍒ゅ畾
+     */
+    private String singlejudge;
+
+    /**
+     * 鐗堟湰鍚嶇О
+     */
+    private String verName;
+
+    /**
+     * 鐗堟湰缂栧彿
+     */
+    private String verCode;
+
+    /**
+     * 淇濆瓨鏈�
+     */
+    private String archDate;
+
+    /**
+     * 鍒犻櫎鏍囧織
+     */
+    private Long del;
+
+    /**
+     * 0-鏈笂浼爉es   1-宸蹭笂浼�
+     */
+    private String flag;
+
+    /**
+     * 涓婁紶mes鏃堕棿
+     */
+    private Date toMesTime;
+
+    /**
+     * 澶囨敞
+     */
+    private String chkDes;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmJudgeDetailsBo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmJudgeDetailsBo.java
index 9fd1f63..e5aa98d 100644
--- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmJudgeDetailsBo.java
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmJudgeDetailsBo.java
@@ -43,17 +43,17 @@
     /**
      * 鏍囧噯鍊�
      */
-    private Long value3;
+    private Double value3;
 
     /**
      * 鍒ゅ畾鍊�1
      */
-    private Long value1;
+    private Double value1;
 
     /**
      * 鍒ゅ畾鍊�2
      */
-    private Long value2;
+    private Double value2;
 
     /**
      * 缂洪櫡浣嶇疆
@@ -68,7 +68,7 @@
     /**
      * 鍒嗗�兼爣鍑� (鎵e垎鏍囧噯锛屽緱鍒嗘爣鍑�),姣斿涓嶅悎鏍间竴娆℃墸澶氬皯鍒�
      */
-    private Long stdscore;
+    private Double stdscore;
 
     /**
      * 鏍囪姝ら」鏄惁涓哄悎鎴愰」鐩紝姣斿澶栬锛屽疄闄呬笂鍏宠仈浜嗗緢澶氬瓙椤圭洰
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmMatcheckBo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmMatcheckBo.java
new file mode 100644
index 0000000..98378e5
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmMatcheckBo.java
@@ -0,0 +1,183 @@
+package org.dromara.qa.qm.domain.bo;
+
+import org.dromara.qa.qm.domain.QmMatcheck;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * 鏉愭枡妫�楠岀粺璁′笟鍔″璞� qm_matcheck
+ *
+ * @author zhuguifei
+ * @date 2026-04-15
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = QmMatcheck.class, reverseConvertGenerate = false)
+public class QmMatcheckBo extends BaseEntity {
+
+    /**
+     * id
+     */
+    private String id;
+
+    /**
+     * 姹囨�昏〃ID
+     */
+    private String pid;
+
+    /**
+     * 妫�楠屾壒娆�
+     */
+    private String batchCode;
+
+    /**
+     * 鐗屽彿
+     */
+    private String matCode;
+
+    /**
+     * 浠櫒缂栧彿
+     */
+    private String instrumentCode;
+
+    /**
+     * 鎶�鏈姹�
+     */
+    private String techReq;
+
+    /**
+     * 妫�楠屼緷鎹�
+     */
+    private String checkStd;
+
+    /**
+     * 娴嬭瘯鐜
+     */
+    private String testEnv;
+
+    /**
+     * 妫�楠岄」鐩瓹OD
+     */
+    private String itemCode;
+
+    /**
+     * 鐩樺彿
+     */
+    private String subBatchCode;
+
+    /**
+     * 姣忕洏妫�楠屾暟閲�
+     */
+    private Long sampleNumber;
+
+    /**
+     * 鍙栨牱绫诲瀷
+     */
+    private Long sampleType;
+
+    /**
+     * 妫�楠屽憳
+     */
+    private String checkName;
+
+    /**
+     * 妫�楠屾椂闂�
+     */
+    private Date checkTime;
+
+    /**
+     * 澶嶆牳鍛�
+     */
+    private String reviewName;
+
+    /**
+     * 澶嶆牳鏃堕棿
+     */
+    private Date reviewTime;
+
+    /**
+     * 鏈�澶у��
+     */
+    private Double maxval;
+
+    /**
+     * 鏈�灏忓��
+     */
+    private Double minval;
+
+    /**
+     * 骞冲潎鍊�
+     */
+    private Double avgval;
+
+    /**
+     * SD鍊�
+     */
+    private Double sdval;
+
+    /**
+     * CV鍊�
+     */
+    private Double cvval;
+
+    /**
+     * CPK鍊�
+     */
+    private Double cpkval;
+
+    /**
+     * 瓒呮爣鏁�
+     */
+    private Double badval;
+
+    /**
+     * 鍒ゅ畾
+     */
+    private String judge;
+
+    /**
+     * 鍗曢」鍒ゅ畾
+     */
+    private String singlejudge;
+
+    /**
+     * 鐗堟湰鍚嶇О
+     */
+    private String verName;
+
+    /**
+     * 鐗堟湰缂栧彿
+     */
+    private String verCode;
+
+    /**
+     * 淇濆瓨鏈�
+     */
+    private String archDate;
+
+    /**
+     * 鍒犻櫎鏍囧織
+     */
+    private Long del;
+
+    /**
+     * 0-鏈笂浼爉es   1-宸蹭笂浼�
+     */
+    private String flag;
+
+    /**
+     * 涓婁紶mes鏃堕棿
+     */
+    private Date toMesTime;
+
+    /**
+     * 澶囨敞
+     */
+    private String chkDes;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmBatchVo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmBatchVo.java
index 4d3132f..ce8136f 100644
--- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmBatchVo.java
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmBatchVo.java
@@ -2,6 +2,8 @@
 
 import java.util.Date;
 
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
 import org.dromara.qa.qm.domain.QmBatch;
 import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
 import cn.idev.excel.annotation.ExcelProperty;
@@ -59,8 +61,15 @@
     /**
      * 鐗屽彿
      */
-    @ExcelProperty(value = "鐗屽彿")
+    @ExcelProperty(value = "鐗屽彿code")
     private String matCode;
+
+    /**
+     * 鐗屽彿
+     */
+    @ExcelProperty(value = "鐗屽彿")
+    @Translation(type = TransConstant.MAT_CODE_TO_NAME, mapper = "matCode")
+    private String matName;
 
     /**
      * 鍒ゅ畾渚濇嵁浠g爜
@@ -68,6 +77,10 @@
     @ExcelProperty(value = "鍒ゅ畾渚濇嵁浠g爜")
     private String judgeCode;
 
+    @ExcelProperty(value = "鍒ゅ畾渚濇嵁")
+    @Translation(type = TransConstant.JUDGE_CODE_TO_NAME, mapper = "judgeCode")
+    private String judgeName;
+
     /**
      * 鎵规鐢熸垚鏃ユ湡
      */
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeDetailsVo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeDetailsVo.java
index f005ed1..9829c65 100644
--- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeDetailsVo.java
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeDetailsVo.java
@@ -11,7 +11,7 @@
 import java.io.Serial;
 import java.io.Serializable;
 import java.util.Date;
-
+import java.util.List;
 
 
 /**
@@ -27,6 +27,8 @@
 
     @Serial
     private static final long serialVersionUID = 1L;
+
+    private String id;
 
     /**
      * 鍒ゅ畾涓绘爣璇�
@@ -50,19 +52,19 @@
      * 鏍囧噯鍊�
      */
     @ExcelProperty(value = "鏍囧噯鍊�")
-    private Long value3;
+    private Double value3;
 
     /**
      * 鍒ゅ畾鍊�1
      */
     @ExcelProperty(value = "鍒ゅ畾鍊�1")
-    private Long value1;
+    private Double value1;
 
     /**
      * 鍒ゅ畾鍊�2
      */
     @ExcelProperty(value = "鍒ゅ畾鍊�2")
-    private Long value2;
+    private Double value2;
 
     /**
      * 缂洪櫡浣嶇疆
@@ -80,7 +82,7 @@
      * 鍒嗗�兼爣鍑� (鎵e垎鏍囧噯锛屽緱鍒嗘爣鍑�),姣斿涓嶅悎鏍间竴娆℃墸澶氬皯鍒�
      */
     @ExcelProperty(value = "鍒嗗�兼爣鍑� (鎵e垎鏍囧噯锛屽緱鍒嗘爣鍑�),姣斿涓嶅悎鏍间竴娆℃墸澶氬皯鍒�")
-    private Long stdscore;
+    private Double stdscore;
 
     /**
      * 鏍囪姝ら」鏄惁涓哄悎鎴愰」鐩紝姣斿澶栬锛屽疄闄呬笂鍏宠仈浜嗗緢澶氬瓙椤圭洰
@@ -113,4 +115,46 @@
     private String updateUser;
 
 
+    /**
+     * 瀛愭壒娆$爜
+     */
+    @ExcelProperty(value = "瀛愭壒娆$爜")
+    private String subBatchCode;
+
+    /**
+     * 涓嶈壇鍊�
+     */
+    @ExcelProperty(value = "涓嶈壇鍊�")
+    private Long badVal;
+
+    /**
+     * 鎵规鐮�
+     */
+    @ExcelProperty(value = "鎵规鐮�")
+    private String batchCode;
+
+    /**
+     * 鐗╂枡鐮�
+     */
+    @ExcelProperty(value = "鐗╂枡鐮�")
+    private String matCode;
+
+    /**
+     * 璁惧
+     */
+    @ExcelProperty(value = "璁惧")
+    private String eqp;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    @ExcelProperty(value = "鏇存柊鏃堕棿")
+    private Date updateTime;
+
+    /**
+     * 瀛愰」鍒楄〃锛堢敤浜庢爲褰㈢粨鏋勶級
+     */
+    private List<QmJudgeDetailsVo> children;
+
+
 }
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeVo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeVo.java
index e0fd2d8..66fd9a8 100644
--- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeVo.java
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeVo.java
@@ -48,6 +48,7 @@
      * 鐗╂枡鐗屽彿
      */
     @ExcelProperty(value = "鐗╂枡鐗屽彿")
+    @Translation(type = TransConstant.MAT_CODE_TO_NAME, mapper = "matCode")
     private String matName;
 
     /**
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmMatcheckVo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmMatcheckVo.java
new file mode 100644
index 0000000..30a2376
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmMatcheckVo.java
@@ -0,0 +1,255 @@
+package org.dromara.qa.qm.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.dromara.qa.qm.domain.QmMatcheck;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 鏉愭枡妫�楠岀粺璁¤鍥惧璞� qm_matcheck
+ *
+ * @author zhuguifei
+ * @date 2026-04-15
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = QmMatcheck.class)
+public class QmMatcheckVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @ExcelProperty(value = "id")
+    private String id;
+
+    /**
+     * 姹囨�昏〃ID
+     */
+    @ExcelProperty(value = "姹囨�昏〃ID")
+    private String pid;
+
+    /**
+     * 妫�楠屾壒娆�
+     */
+    @ExcelProperty(value = "妫�楠屾壒娆�")
+    private String batchCode;
+
+    /**
+     * 鐗屽彿
+     */
+    @ExcelProperty(value = "鐗屽彿")
+    private String matCode;
+
+    /**
+     * 浠櫒缂栧彿
+     */
+    @ExcelProperty(value = "浠櫒缂栧彿")
+    private String instrumentCode;
+
+    /**
+     * 鎶�鏈姹�
+     */
+    @ExcelProperty(value = "鎶�鏈姹�")
+    private String techReq;
+
+    /**
+     * 妫�楠屼緷鎹�
+     */
+    @ExcelProperty(value = "妫�楠屼緷鎹�")
+    private String checkStd;
+
+    /**
+     * 娴嬭瘯鐜
+     */
+    @ExcelProperty(value = "娴嬭瘯鐜")
+    private String testEnv;
+
+    /**
+     * 妫�楠岄」鐩瓹OD
+     */
+    @ExcelProperty(value = "妫�楠岄」鐩瓹OD")
+    private String itemCode;
+
+    /**
+     * 妫�楠岄」鐩悕绉�
+     */
+    private String itemName;
+
+    /**
+     * 璁惧
+     */
+    private String eqp;
+
+    /**
+     * 鐩樺彿
+     */
+    @ExcelProperty(value = "鐩樺彿")
+    private String subBatchCode;
+
+    /**
+     * 姣忕洏妫�楠屾暟閲�
+     */
+    @ExcelProperty(value = "姣忕洏妫�楠屾暟閲�")
+    private Long sampleNumber;
+
+    /**
+     * 鍙栨牱绫诲瀷
+     */
+    @ExcelProperty(value = "鍙栨牱绫诲瀷")
+    private Long sampleType;
+
+    /**
+     * 妫�楠屽憳
+     */
+    @ExcelProperty(value = "妫�楠屽憳")
+    private String checkName;
+
+    /**
+     * 妫�楠屾椂闂�
+     */
+    @ExcelProperty(value = "妫�楠屾椂闂�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date checkTime;
+
+    /**
+     * 澶嶆牳鍛�
+     */
+    @ExcelProperty(value = "澶嶆牳鍛�")
+    private String reviewName;
+
+    /**
+     * 澶嶆牳鏃堕棿
+     */
+    @ExcelProperty(value = "澶嶆牳鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date reviewTime;
+
+    /**
+     * 鏈�澶у��
+     */
+    @ExcelProperty(value = "鏈�澶у��")
+    private Double maxval;
+
+    /**
+     * 鏈�灏忓��
+     */
+    @ExcelProperty(value = "鏈�灏忓��")
+    private Double minval;
+
+    /**
+     * 骞冲潎鍊�
+     */
+    @ExcelProperty(value = "骞冲潎鍊�")
+    private Double avgval;
+
+    /**
+     * SD鍊�
+     */
+    @ExcelProperty(value = "SD鍊�")
+    private Double sdval;
+
+    /**
+     * CV鍊�
+     */
+    @ExcelProperty(value = "CV鍊�")
+    private Double cvval;
+
+    /**
+     * CPK鍊�
+     */
+    @ExcelProperty(value = "CPK鍊�")
+    private Double cpkval;
+
+    /**
+     * 瓒呮爣鏁�
+     */
+    @ExcelProperty(value = "瓒呮爣鏁�")
+    private Double badval;
+
+    /**
+     * 鍒ゅ畾
+     */
+    @ExcelProperty(value = "鍒ゅ畾")
+    private String judge;
+
+    /**
+     * 鍗曢」鍒ゅ畾
+     */
+    @ExcelProperty(value = "鍗曢」鍒ゅ畾")
+    private String singlejudge;
+
+    /**
+     * 鐗堟湰鍚嶇О
+     */
+    @ExcelProperty(value = "鐗堟湰鍚嶇О")
+    private String verName;
+
+    /**
+     * 鐗堟湰缂栧彿
+     */
+    @ExcelProperty(value = "鐗堟湰缂栧彿")
+    private String verCode;
+
+    /**
+     * 淇濆瓨鏈�
+     */
+    @ExcelProperty(value = "淇濆瓨鏈�")
+    private String archDate;
+
+    /**
+     * 鍒犻櫎鏍囧織
+     */
+    @ExcelProperty(value = "鍒犻櫎鏍囧織")
+    private Long del;
+
+    /**
+     * 0-鏈笂浼爉es   1-宸蹭笂浼�
+     */
+    @ExcelProperty(value = "0-鏈笂浼爉es   1-宸蹭笂浼�")
+    private String flag;
+
+    /**
+     * 涓婁紶mes鏃堕棿
+     */
+    @ExcelProperty(value = "涓婁紶mes鏃堕棿")
+    private Date toMesTime;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String chkDes;
+
+    /**
+     * 妫�楠屼汉灞曠ず鍚�
+     */
+    private String checker;
+
+    /**
+     * 鍒ゅ畾瑙勭▼code(闈炴暟鎹簱瀛楁)
+     */
+    private String judgeCode;
+
+    /**
+     * 鏄惁鐢熸垚30鏀儫鏄庣粏(闈炴暟鎹簱瀛楁)
+     */
+    private String generateDetails;
+
+    /**
+     * 妫�娴嬬被鍨�(闈炴暟鎹簱瀛楁)
+     */
+    private String checkType;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmMatcheckMapper.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmMatcheckMapper.java
new file mode 100644
index 0000000..6c6fbaa
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmMatcheckMapper.java
@@ -0,0 +1,38 @@
+package org.dromara.qa.qm.mapper;
+
+import org.apache.ibatis.annotations.Result;
+import org.apache.ibatis.annotations.Results;
+import org.dromara.qa.qm.domain.bo.QmMatcheckBo;
+import org.dromara.qa.qm.domain.QmMatcheck;
+import org.dromara.qa.qm.domain.vo.QmMatcheckVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鏉愭枡妫�楠岀粺璁apper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2026-04-15
+ */
+public interface QmMatcheckMapper extends BaseMapperPlus<QmMatcheck, QmMatcheckVo> {
+    @Results(id = "qmCheckItemMap", value = {
+            @Result(property = "itemCode", column = "item_code"),
+            @Result(property = "itemName", column = "item_name")
+    })
+    @Select("SELECT b.item_code, a.item_name FROM QM_JUDGE_DETAILS a " +
+            "JOIN QM_CHECKITEM b ON a.item_cod = b.id " +
+            "WHERE a.judge_id = #{judgeId} AND a.rid IS NULL AND a.category IN (0)")
+    List<Map<String, Object>> getQmCheckItem(@Param("judgeId") String judgeId);
+
+    /**
+     * 鎸夋壒娆″拰鐗屽彿鏌ヨ鏉愭枡妫�楠岀粺璁�(澶氳〃)
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 鏉愭枡妫�楠岀粺璁″垪琛�
+     */
+    List<QmMatcheckVo> listQmMatcheck(@Param("bo") QmMatcheckBo bo);
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmJudgeDetailsService.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmJudgeDetailsService.java
index d6506ed..ad2a804 100644
--- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmJudgeDetailsService.java
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmJudgeDetailsService.java
@@ -42,6 +42,14 @@
     List<QmJudgeDetailsVo> queryList(QmJudgeDetailsBo bo);
 
     /**
+     * 鏌ヨ鏍戝舰缁撴瀯鏁版嵁
+     *
+     * @param judgeId 鍒ゅ畾涓绘爣璇�
+     * @return 鏍戝舰缁撴瀯鍒楄〃
+     */
+    List<QmJudgeDetailsVo> queryTreeListByJudgeId(String judgeId);
+
+    /**
      * 鏂板鍒ゅ畾妯℃澘鏄庣粏
      *
      * @param bo 鍒ゅ畾妯℃澘鏄庣粏
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmMatcheckService.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmMatcheckService.java
new file mode 100644
index 0000000..6f7f7da
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmMatcheckService.java
@@ -0,0 +1,85 @@
+package org.dromara.qa.qm.service;
+
+import org.dromara.qa.qm.domain.vo.QmMatcheckVo;
+import org.dromara.qa.qm.domain.bo.QmMatcheckBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鏉愭枡妫�楠岀粺璁ervice鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2026-04-15
+ */
+public interface IQmMatcheckService {
+
+    /**
+     * 鏌ヨ鏉愭枡妫�楠岀粺璁�
+     *
+     * @param id 涓婚敭
+     * @return 鏉愭枡妫�楠岀粺璁�
+     */
+    QmMatcheckVo queryById(String id);
+
+    /**
+     * 鍒嗛〉鏌ヨ鏉愭枡妫�楠岀粺璁″垪琛�
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 鏉愭枡妫�楠岀粺璁″垎椤靛垪琛�
+     */
+    TableDataInfo<QmMatcheckVo> queryPageList(QmMatcheckBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勬潗鏂欐楠岀粺璁″垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 鏉愭枡妫�楠岀粺璁″垪琛�
+     */
+    List<QmMatcheckVo> queryList(QmMatcheckBo bo);
+
+    /**
+     * 鏂板鏉愭枡妫�楠岀粺璁�
+     *
+     * @param bo 鏉愭枡妫�楠岀粺璁�
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(QmMatcheckBo bo);
+
+    /**
+     * 淇敼鏉愭枡妫�楠岀粺璁�
+     *
+     * @param bo 鏉愭枡妫�楠岀粺璁�
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(QmMatcheckBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゆ潗鏂欐楠岀粺璁′俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid);
+
+    /**
+     * 鑾峰彇妫�楠岄」鐩�
+     *
+     * @param judgeId 鍒ゅ畾ID
+     * @return 妫�楠岄」鐩垪琛�
+     */
+    List<Map<String, Object>> getQmCheckItem(String judgeId);
+
+    /**
+     * 鎸夋壒娆″拰鐗屽彿鏌ヨ鏉愭枡妫�楠岀粺璁�(澶氳〃)
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 鏉愭枡妫�楠岀粺璁″垪琛�
+     */
+    List<QmMatcheckVo> listQmMatcheck(QmMatcheckBo bo);
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmJudgeDetailsServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmJudgeDetailsServiceImpl.java
index ccfb91d..c76b09c 100644
--- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmJudgeDetailsServiceImpl.java
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmJudgeDetailsServiceImpl.java
@@ -70,6 +70,51 @@
         return baseMapper.selectVoList(lqw);
     }
 
+    /**
+     * 鏌ヨ鏍戝舰缁撴瀯鏁版嵁
+     *
+     * @param judgeId 鍒ゅ畾涓绘爣璇�
+     * @return 鏍戝舰缁撴瀯鍒楄〃
+     */
+    @Override
+    public List<QmJudgeDetailsVo> queryTreeListByJudgeId(String judgeId) {
+        if (StringUtils.isBlank(judgeId)) {
+            return new java.util.ArrayList<>();
+        }
+        // 1. 鏌ヨ鏍硅妭鐐� (rid is null)
+        List<QmJudgeDetailsVo> roots = selectTreeNodes(judgeId, null);
+        for (QmJudgeDetailsVo root : roots) {
+            // 2. 鏌ヨ绗竴绾у瓙鑺傜偣 (rid = root.itemCod)
+            List<QmJudgeDetailsVo> children = selectTreeNodes(judgeId, root.getItemCod());
+            for (QmJudgeDetailsVo child : children) {
+                // 3. 鏌ヨ绗簩绾у瓙鑺傜偣 (rid = child.itemCod)
+                List<QmJudgeDetailsVo> grandchildren = selectTreeNodes(judgeId, child.getItemCod());
+                child.setChildren(grandchildren);
+            }
+            root.setChildren(children);
+        }
+        return roots;
+    }
+
+    /**
+     * 鏌ヨ鏍戣妭鐐�
+     *
+     * @param judgeId 鍒ゅ畾涓绘爣璇�
+     * @param rid     鍏宠仈椤笽D
+     * @return 鑺傜偣鍒楄〃
+     */
+    private List<QmJudgeDetailsVo> selectTreeNodes(String judgeId, String rid) {
+        LambdaQueryWrapper<QmJudgeDetails> lqw = Wrappers.lambdaQuery();
+        lqw.eq(QmJudgeDetails::getJudgeId, judgeId);
+        if (rid == null) {
+            lqw.isNull(QmJudgeDetails::getRid);
+        } else {
+            lqw.eq(QmJudgeDetails::getRid, rid);
+        }
+        lqw.orderByAsc(QmJudgeDetails::getId);
+        return baseMapper.selectVoList(lqw);
+    }
+
     private LambdaQueryWrapper<QmJudgeDetails> buildQueryWrapper(QmJudgeDetailsBo bo) {
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<QmJudgeDetails> lqw = Wrappers.lambdaQuery();
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmJudgeServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmJudgeServiceImpl.java
index 55b949c..e6edd0e 100644
--- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmJudgeServiceImpl.java
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmJudgeServiceImpl.java
@@ -1,5 +1,6 @@
 package org.dromara.qa.qm.service.impl;
 
+import org.dromara.common.core.service.JudgeService;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -19,6 +20,13 @@
 import org.dromara.qa.qm.service.IQmStdService;
 import org.dromara.qa.qm.mapper.QmStdMapper;
 
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import org.dromara.qa.qm.domain.QmCheckitem;
+import org.dromara.qa.qm.domain.QmJudgeDetails;
+import org.dromara.qa.qm.mapper.QmCheckitemMapper;
+import org.dromara.qa.qm.mapper.QmJudgeDetailsMapper;
+import org.springframework.transaction.annotation.Transactional;
+
 import java.util.List;
 import java.util.Map;
 import java.util.Collection;
@@ -35,10 +43,12 @@
 @Slf4j
 @RequiredArgsConstructor
 @Service
-public class QmJudgeServiceImpl implements IQmJudgeService {
+public class QmJudgeServiceImpl implements IQmJudgeService, JudgeService {
 
     private final QmJudgeMapper baseMapper;
     private final QmStdMapper qmStdMapper;
+    private final QmCheckitemMapper qmCheckitemMapper;
+    private final QmJudgeDetailsMapper qmJudgeDetailsMapper;
 
     /**
      * 鏌ヨ鍒ゅ畾渚濇嵁
@@ -127,12 +137,52 @@
      * @return 鏄惁鏂板鎴愬姛
      */
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Boolean insertByBo(QmJudgeBo bo) {
         QmJudge add = MapstructUtils.convert(bo, QmJudge.class);
+        if (add.getCdate() == null) {
+            add.setCdate(new java.util.Date());
+        }
         validEntityBeforeSave(add);
         boolean flag = baseMapper.insert(add) > 0;
         if (flag) {
             bo.setId(add.getId());
+
+            // 1. 鏍规嵁 stdCod 鏌ヨ鍚敤鐨勮绋嬫楠岄」鐩�
+            LambdaQueryWrapper<QmCheckitem> itemLqw = Wrappers.lambdaQuery();
+            itemLqw.eq(QmCheckitem::getStdCode, bo.getStdCod());
+            itemLqw.eq(QmCheckitem::getEnable, 1L);
+            itemLqw.ne(QmCheckitem::getDel, 1L);
+            List<QmCheckitem> checkitems = qmCheckitemMapper.selectList(itemLqw);
+
+            if (!checkitems.isEmpty()) {
+                List<QmJudgeDetails> detailsList = checkitems.stream().map(item -> {
+                    QmJudgeDetails detail = new QmJudgeDetails();
+                    detail.setJudgeId(add.getId());
+                    detail.setItemCod(item.getId());
+                    detail.setItemName(item.getItemName());
+                    detail.setValue3(0.0);
+                    detail.setValue1(0.0);
+                    detail.setValue2(0.0);
+                    detail.setLocation(item.getLocation());
+                    detail.setCls(item.getCheckLevel());
+                    detail.setStdscore(item.getScore() != null ? item.getScore() : 0.0);
+                    detail.setIsmix(item.getIsmix() != null ? item.getIsmix() : 0L);
+                    detail.setRid(item.getRid());
+                    detail.setCategory(item.getCategory());
+                    detail.setDecisionDes(item.getItemDes());
+                    return detail;
+                }).collect(Collectors.toList());
+                qmJudgeDetailsMapper.insertBatch(detailsList);
+            }
+
+            // 2. 灏嗗師鏉ュ瓨鍦ㄧ殑鐩稿悓鐗╂枡鐗屽彿鍜岀被鍨嬬殑渚濇嵁璁剧疆涓虹鐢�
+            LambdaUpdateWrapper<QmJudge> updateWrapper = Wrappers.lambdaUpdate();
+            updateWrapper.set(QmJudge::getStatus, 0L)
+                .eq(QmJudge::getMatCode, bo.getMatCode())
+                .eq(QmJudge::getCategory, bo.getCategory())
+                .ne(QmJudge::getId, add.getId());
+            baseMapper.update(null, updateWrapper);
         }
         return flag;
     }
@@ -171,4 +221,13 @@
         }
         return baseMapper.deleteByIds(ids) > 0;
     }
+
+    @Override
+    public String selectJudgeNameByCode(String judgeCode) {
+        QmJudgeVo qmJudgeVo = baseMapper.selectVoById(judgeCode);
+        if(qmJudgeVo!=null){
+            return qmJudgeVo.getJudgeName();
+        }
+        return null;
+    }
 }
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmMatcheckServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmMatcheckServiceImpl.java
new file mode 100644
index 0000000..721519d
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmMatcheckServiceImpl.java
@@ -0,0 +1,154 @@
+package org.dromara.qa.qm.service.impl;
+
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.dromara.qa.qm.domain.bo.QmMatcheckBo;
+import org.dromara.qa.qm.domain.vo.QmMatcheckVo;
+import org.dromara.qa.qm.domain.QmMatcheck;
+import org.dromara.qa.qm.mapper.QmMatcheckMapper;
+import org.dromara.qa.qm.service.IQmMatcheckService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 鏉愭枡妫�楠岀粺璁ervice涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2026-04-15
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class QmMatcheckServiceImpl implements IQmMatcheckService {
+
+    private final QmMatcheckMapper baseMapper;
+
+    /**
+     * 鏌ヨ鏉愭枡妫�楠岀粺璁�
+     *
+     * @param id 涓婚敭
+     * @return 鏉愭枡妫�楠岀粺璁�
+     */
+    @Override
+    public QmMatcheckVo queryById(String id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ鏉愭枡妫�楠岀粺璁″垪琛�
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 鏉愭枡妫�楠岀粺璁″垎椤靛垪琛�
+     */
+    @Override
+    public TableDataInfo<QmMatcheckVo> queryPageList(QmMatcheckBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<QmMatcheck> lqw = buildQueryWrapper(bo);
+        Page<QmMatcheckVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勬潗鏂欐楠岀粺璁″垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 鏉愭枡妫�楠岀粺璁″垪琛�
+     */
+    @Override
+    public List<QmMatcheckVo> queryList(QmMatcheckBo bo) {
+        LambdaQueryWrapper<QmMatcheck> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<QmMatcheck> buildQueryWrapper(QmMatcheckBo bo) {
+        LambdaQueryWrapper<QmMatcheck> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getBatchCode()), QmMatcheck::getBatchCode, bo.getBatchCode());
+        lqw.eq(StringUtils.isNotBlank(bo.getMatCode()), QmMatcheck::getMatCode, bo.getMatCode());
+        lqw.like(StringUtils.isNotBlank(bo.getCheckName()), QmMatcheck::getCheckName, bo.getCheckName());
+        return lqw;
+    }
+
+    /**
+     * 鏂板鏉愭枡妫�楠岀粺璁�
+     *
+     * @param bo 鏉愭枡妫�楠岀粺璁�
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public Boolean insertByBo(QmMatcheckBo bo) {
+        QmMatcheck add = MapstructUtils.convert(bo, QmMatcheck.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼鏉愭枡妫�楠岀粺璁�
+     *
+     * @param bo 鏉愭枡妫�楠岀粺璁�
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(QmMatcheckBo bo) {
+        QmMatcheck update = MapstructUtils.convert(bo, QmMatcheck.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(QmMatcheck entity){
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゆ潗鏂欐楠岀粺璁′俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+
+    /**
+     * 鑾峰彇妫�楠岄」鐩�
+     *
+     * @param judgeId 鍒ゅ畾ID
+     * @return 妫�楠岄」鐩垪琛�
+     */
+    @Override
+    public List<Map<String, Object>> getQmCheckItem(String judgeId) {
+        return baseMapper.getQmCheckItem(judgeId);
+    }
+
+    /**
+     * 鎸夋壒娆″拰鐗屽彿鏌ヨ鏉愭枡妫�楠岀粺璁�(澶氳〃)
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 鏉愭枡妫�楠岀粺璁″垪琛�
+     */
+    @Override
+    public List<QmMatcheckVo> listQmMatcheck(QmMatcheckBo bo) {
+        return baseMapper.listQmMatcheck(bo);
+    }
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/controller/MdMatController.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/controller/MdMatController.java
new file mode 100644
index 0000000..038b934
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/controller/MdMatController.java
@@ -0,0 +1,105 @@
+package org.dromara.sc.md.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.sc.md.domain.vo.MdMatVo;
+import org.dromara.sc.md.domain.bo.MdMatBo;
+import org.dromara.sc.md.service.IMdMatService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 鐗╂枡
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/md/mat")
+public class MdMatController extends BaseController {
+
+    private final IMdMatService mdMatService;
+
+    /**
+     * 鏌ヨ鐗╂枡鍒楄〃
+     */
+    @SaCheckPermission("md:mat:list")
+    @GetMapping("/list")
+    public TableDataInfo<MdMatVo> list(MdMatBo bo, PageQuery pageQuery) {
+        return mdMatService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭鐗╂枡鍒楄〃
+     */
+    @SaCheckPermission("md:mat:export")
+    @Log(title = "鐗╂枡", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(MdMatBo bo, HttpServletResponse response) {
+        List<MdMatVo> list = mdMatService.queryList(bo);
+        ExcelUtil.exportExcel(list, "鐗╂枡", MdMatVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇鐗╂枡璇︾粏淇℃伅
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("md:mat:query")
+    @GetMapping("/{id}")
+    public R<MdMatVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable String id) {
+        return R.ok(mdMatService.queryById(id));
+    }
+
+    /**
+     * 鏂板鐗╂枡
+     */
+    @SaCheckPermission("md:mat:add")
+    @Log(title = "鐗╂枡", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody MdMatBo bo) {
+        return toAjax(mdMatService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼鐗╂枡
+     */
+    @SaCheckPermission("md:mat:edit")
+    @Log(title = "鐗╂枡", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody MdMatBo bo) {
+        return toAjax(mdMatService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎鐗╂枡
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("md:mat:remove")
+    @Log(title = "鐗╂枡", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable String[] ids) {
+        return toAjax(mdMatService.deleteWithValidByIds(List.of(ids), true));
+    }
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/controller/MdMatTypeController.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/controller/MdMatTypeController.java
new file mode 100644
index 0000000..2729d63
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/controller/MdMatTypeController.java
@@ -0,0 +1,105 @@
+package org.dromara.sc.md.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.sc.md.domain.vo.MdMatTypeVo;
+import org.dromara.sc.md.domain.bo.MdMatTypeBo;
+import org.dromara.sc.md.service.IMdMatTypeService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 鐗╂枡绫诲瀷
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/md/matType")
+public class MdMatTypeController extends BaseController {
+
+    private final IMdMatTypeService mdMatTypeService;
+
+    /**
+     * 鏌ヨ鐗╂枡绫诲瀷鍒楄〃
+     */
+    @SaCheckPermission("md:matType:list")
+    @GetMapping("/list")
+    public TableDataInfo<MdMatTypeVo> list(MdMatTypeBo bo, PageQuery pageQuery) {
+        return mdMatTypeService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭鐗╂枡绫诲瀷鍒楄〃
+     */
+    @SaCheckPermission("md:matType:export")
+    @Log(title = "鐗╂枡绫诲瀷", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(MdMatTypeBo bo, HttpServletResponse response) {
+        List<MdMatTypeVo> list = mdMatTypeService.queryList(bo);
+        ExcelUtil.exportExcel(list, "鐗╂枡绫诲瀷", MdMatTypeVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇鐗╂枡绫诲瀷璇︾粏淇℃伅
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("md:matType:query")
+    @GetMapping("/{id}")
+    public R<MdMatTypeVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable String id) {
+        return R.ok(mdMatTypeService.queryById(id));
+    }
+
+    /**
+     * 鏂板鐗╂枡绫诲瀷
+     */
+    @SaCheckPermission("md:matType:add")
+    @Log(title = "鐗╂枡绫诲瀷", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody MdMatTypeBo bo) {
+        return toAjax(mdMatTypeService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼鐗╂枡绫诲瀷
+     */
+    @SaCheckPermission("md:matType:edit")
+    @Log(title = "鐗╂枡绫诲瀷", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody MdMatTypeBo bo) {
+        return toAjax(mdMatTypeService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎鐗╂枡绫诲瀷
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("md:matType:remove")
+    @Log(title = "鐗╂枡绫诲瀷", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable String[] ids) {
+        return toAjax(mdMatTypeService.deleteWithValidByIds(List.of(ids), true));
+    }
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/MdMat.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/MdMat.java
new file mode 100644
index 0000000..389590c
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/MdMat.java
@@ -0,0 +1,97 @@
+package org.dromara.sc.md.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.io.Serial;
+
+/**
+ * 鐗╂枡瀵硅薄 MD_MAT
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+@Data
+@TableName("MD_MAT")
+public class MdMat {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @TableId(value = "ID")
+    private String id;
+
+    /**
+     * 鐗╂枡浠g爜
+     */
+    private String code;
+
+    /**
+     * 鍏ㄧО
+     */
+    private String name;
+
+    /**
+     * 绠�绉�
+     */
+    private String simpleName;
+
+    /**
+     * 鎻忚堪
+     */
+    private String des;
+
+    /**
+     * 鍗曚綅
+     */
+    private String uid;
+
+    /**
+     * 鏈�鍚庢洿鏂版椂闂�
+     */
+    private Date lastUpdateTime;
+
+    /**
+     * 鍚敤
+     */
+    private Long enable;
+
+    /**
+     * 鍒犻櫎
+     */
+    private String del;
+
+    /**
+     * 鐗╂枡绫诲瀷
+     */
+    private String tid;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    private String createUserName;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createUserTime;
+
+    /**
+     * 鏇存柊浜�
+     */
+    private String updateUserName;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    private Date updateUserTime;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/MdMatType.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/MdMatType.java
new file mode 100644
index 0000000..273e37f
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/MdMatType.java
@@ -0,0 +1,87 @@
+package org.dromara.sc.md.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.io.Serial;
+
+/**
+ * 鐗╂枡绫诲瀷瀵硅薄 MD_MAT_TYPE
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+@Data
+@TableName("MD_MAT_TYPE")
+public class MdMatType {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @TableId(value = "ID")
+    private String id;
+
+    /**
+     * 鐗╂枡缁勫閿�
+     */
+    private String gid;
+
+    /**
+     * 缂栫爜
+     */
+    private String code;
+
+    /**
+     * 鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 鎻忚堪
+     */
+    private String des;
+
+    /**
+     * 鍚敤
+     */
+    private Long enable;
+
+    /**
+     * 鍒犻櫎
+     */
+    private String del;
+
+    /**
+     * mes缂栫爜
+     */
+    private String mesCode;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    private String createUserName;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createUserTime;
+
+    /**
+     * 鏇存柊浜�
+     */
+    private String updateUserName;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    private Date updateUserTime;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/bo/MdMatBo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/bo/MdMatBo.java
new file mode 100644
index 0000000..8937469
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/bo/MdMatBo.java
@@ -0,0 +1,97 @@
+package org.dromara.sc.md.domain.bo;
+
+import org.dromara.sc.md.domain.MdMat;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+/**
+ * 鐗╂枡涓氬姟瀵硅薄 MD_MAT
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = MdMat.class, reverseConvertGenerate = false)
+public class MdMatBo extends BaseEntity {
+
+    /**
+     * id
+     */
+    @NotBlank(message = "id涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private String id;
+
+    /**
+     * 鐗╂枡浠g爜
+     */
+    private String code;
+
+    /**
+     * 鍏ㄧО
+     */
+    private String name;
+
+    /**
+     * 绠�绉�
+     */
+    private String simpleName;
+
+    /**
+     * 鎻忚堪
+     */
+    private String des;
+
+    /**
+     * 鍗曚綅
+     */
+    private String uid;
+
+    /**
+     * 鏈�鍚庢洿鏂版椂闂�
+     */
+    private Date lastUpdateTime;
+
+    /**
+     * 鍚敤
+     */
+    private Long enable;
+
+    /**
+     * 鍒犻櫎
+     */
+    private String del;
+
+    /**
+     * 鐗╂枡绫诲瀷
+     */
+    private String tid;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    private String createUserName;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createUserTime;
+
+    /**
+     * 鏇存柊浜�
+     */
+    private String updateUserName;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    private Date updateUserTime;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/bo/MdMatTypeBo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/bo/MdMatTypeBo.java
new file mode 100644
index 0000000..570defe
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/bo/MdMatTypeBo.java
@@ -0,0 +1,87 @@
+package org.dromara.sc.md.domain.bo;
+
+import org.dromara.sc.md.domain.MdMatType;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+/**
+ * 鐗╂枡绫诲瀷涓氬姟瀵硅薄 MD_MAT_TYPE
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = MdMatType.class, reverseConvertGenerate = false)
+public class MdMatTypeBo extends BaseEntity {
+
+    /**
+     * id
+     */
+    @NotBlank(message = "id涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private String id;
+
+    /**
+     * 鐗╂枡缁勫閿�
+     */
+    private String gid;
+
+    /**
+     * 缂栫爜
+     */
+    private String code;
+
+    /**
+     * 鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 鎻忚堪
+     */
+    private String des;
+
+    /**
+     * 鍚敤
+     */
+    private Long enable;
+
+    /**
+     * 鍒犻櫎
+     */
+    private String del;
+
+    /**
+     * mes缂栫爜
+     */
+    private String mesCode;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    private String createUserName;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createUserTime;
+
+    /**
+     * 鏇存柊浜�
+     */
+    private String updateUserName;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    private Date updateUserTime;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/vo/MdMatTypeVo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/vo/MdMatTypeVo.java
new file mode 100644
index 0000000..e84d889
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/vo/MdMatTypeVo.java
@@ -0,0 +1,106 @@
+package org.dromara.sc.md.domain.vo;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.dromara.sc.md.domain.MdMatType;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 鐗╂枡绫诲瀷瑙嗗浘瀵硅薄 MD_MAT_TYPE
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = MdMatType.class)
+public class MdMatTypeVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @ExcelProperty(value = "id")
+    private String id;
+
+    /**
+     * 鐗╂枡缁勫閿�
+     */
+    @ExcelProperty(value = "鐗╂枡缁勫閿�")
+    private String gid;
+
+    /**
+     * 缂栫爜
+     */
+    @ExcelProperty(value = "缂栫爜")
+    private String code;
+
+    /**
+     * 鍚嶇О
+     */
+    @ExcelProperty(value = "鍚嶇О")
+    private String name;
+
+    /**
+     * 鎻忚堪
+     */
+    @ExcelProperty(value = "鎻忚堪")
+    private String des;
+
+    /**
+     * 鍚敤
+     */
+    @ExcelProperty(value = "鍚敤")
+    private Long enable;
+
+    /**
+     * 鍒犻櫎
+     */
+    @ExcelProperty(value = "鍒犻櫎")
+    private String del;
+
+    /**
+     * mes缂栫爜
+     */
+    @ExcelProperty(value = "mes缂栫爜")
+    private String mesCode;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @ExcelProperty(value = "鍒涘缓浜�")
+    private String createUserName;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ExcelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createUserTime;
+
+    /**
+     * 鏇存柊浜�
+     */
+    @ExcelProperty(value = "鏇存柊浜�")
+    private String updateUserName;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    @ExcelProperty(value = "鏇存柊鏃堕棿")
+    private Date updateUserTime;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/vo/MdMatVo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/vo/MdMatVo.java
new file mode 100644
index 0000000..56be849
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/vo/MdMatVo.java
@@ -0,0 +1,118 @@
+package org.dromara.sc.md.domain.vo;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.dromara.sc.md.domain.MdMat;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 鐗╂枡瑙嗗浘瀵硅薄 MD_MAT
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = MdMat.class)
+public class MdMatVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @ExcelProperty(value = "id")
+    private String id;
+
+    /**
+     * 鐗╂枡浠g爜
+     */
+    @ExcelProperty(value = "鐗╂枡浠g爜")
+    private String code;
+
+    /**
+     * 鍏ㄧО
+     */
+    @ExcelProperty(value = "鍏ㄧО")
+    private String name;
+
+    /**
+     * 绠�绉�
+     */
+    @ExcelProperty(value = "绠�绉�")
+    private String simpleName;
+
+    /**
+     * 鎻忚堪
+     */
+    @ExcelProperty(value = "鎻忚堪")
+    private String des;
+
+    /**
+     * 鍗曚綅
+     */
+    @ExcelProperty(value = "鍗曚綅")
+    private String uid;
+
+    /**
+     * 鏈�鍚庢洿鏂版椂闂�
+     */
+    @ExcelProperty(value = "鏈�鍚庢洿鏂版椂闂�")
+    private Date lastUpdateTime;
+
+    /**
+     * 鍚敤
+     */
+    @ExcelProperty(value = "鍚敤")
+    private Long enable;
+
+    /**
+     * 鍒犻櫎
+     */
+    @ExcelProperty(value = "鍒犻櫎")
+    private String del;
+
+    /**
+     * 鐗╂枡绫诲瀷
+     */
+    @ExcelProperty(value = "鐗╂枡绫诲瀷")
+    private String tid;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @ExcelProperty(value = "鍒涘缓浜�")
+    private String createUserName;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ExcelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createUserTime;
+
+    /**
+     * 鏇存柊浜�
+     */
+    @ExcelProperty(value = "鏇存柊浜�")
+    private String updateUserName;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    @ExcelProperty(value = "鏇存柊鏃堕棿")
+    private Date updateUserTime;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/mapper/MdMatMapper.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/mapper/MdMatMapper.java
new file mode 100644
index 0000000..0c41b40
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/mapper/MdMatMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.sc.md.mapper;
+
+import org.dromara.sc.md.domain.MdMat;
+import org.dromara.sc.md.domain.vo.MdMatVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 鐗╂枡Mapper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+public interface MdMatMapper extends BaseMapperPlus<MdMat, MdMatVo> {
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/mapper/MdMatTypeMapper.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/mapper/MdMatTypeMapper.java
new file mode 100644
index 0000000..2e962df
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/mapper/MdMatTypeMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.sc.md.mapper;
+
+import org.dromara.sc.md.domain.MdMatType;
+import org.dromara.sc.md.domain.vo.MdMatTypeVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 鐗╂枡绫诲瀷Mapper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+public interface MdMatTypeMapper extends BaseMapperPlus<MdMatType, MdMatTypeVo> {
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/IMdMatService.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/IMdMatService.java
new file mode 100644
index 0000000..0b9c397
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/IMdMatService.java
@@ -0,0 +1,68 @@
+package org.dromara.sc.md.service;
+
+import org.dromara.sc.md.domain.vo.MdMatVo;
+import org.dromara.sc.md.domain.bo.MdMatBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 鐗╂枡Service鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+public interface IMdMatService {
+
+    /**
+     * 鏌ヨ鐗╂枡
+     *
+     * @param id 涓婚敭
+     * @return 鐗╂枡
+     */
+    MdMatVo queryById(String id);
+
+    /**
+     * 鍒嗛〉鏌ヨ鐗╂枡鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 鐗╂枡鍒嗛〉鍒楄〃
+     */
+    TableDataInfo<MdMatVo> queryPageList(MdMatBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勭墿鏂欏垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 鐗╂枡鍒楄〃
+     */
+    List<MdMatVo> queryList(MdMatBo bo);
+
+    /**
+     * 鏂板鐗╂枡
+     *
+     * @param bo 鐗╂枡
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(MdMatBo bo);
+
+    /**
+     * 淇敼鐗╂枡
+     *
+     * @param bo 鐗╂枡
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(MdMatBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ょ墿鏂欎俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid);
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/IMdMatTypeService.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/IMdMatTypeService.java
new file mode 100644
index 0000000..ac89e41
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/IMdMatTypeService.java
@@ -0,0 +1,68 @@
+package org.dromara.sc.md.service;
+
+import org.dromara.sc.md.domain.vo.MdMatTypeVo;
+import org.dromara.sc.md.domain.bo.MdMatTypeBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 鐗╂枡绫诲瀷Service鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+public interface IMdMatTypeService {
+
+    /**
+     * 鏌ヨ鐗╂枡绫诲瀷
+     *
+     * @param id 涓婚敭
+     * @return 鐗╂枡绫诲瀷
+     */
+    MdMatTypeVo queryById(String id);
+
+    /**
+     * 鍒嗛〉鏌ヨ鐗╂枡绫诲瀷鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 鐗╂枡绫诲瀷鍒嗛〉鍒楄〃
+     */
+    TableDataInfo<MdMatTypeVo> queryPageList(MdMatTypeBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勭墿鏂欑被鍨嬪垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 鐗╂枡绫诲瀷鍒楄〃
+     */
+    List<MdMatTypeVo> queryList(MdMatTypeBo bo);
+
+    /**
+     * 鏂板鐗╂枡绫诲瀷
+     *
+     * @param bo 鐗╂枡绫诲瀷
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(MdMatTypeBo bo);
+
+    /**
+     * 淇敼鐗╂枡绫诲瀷
+     *
+     * @param bo 鐗╂枡绫诲瀷
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(MdMatTypeBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ょ墿鏂欑被鍨嬩俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid);
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/impl/MdMatServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/impl/MdMatServiceImpl.java
new file mode 100644
index 0000000..1575845
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/impl/MdMatServiceImpl.java
@@ -0,0 +1,147 @@
+package org.dromara.sc.md.service.impl;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import org.dromara.common.core.service.MatService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.dromara.sc.md.domain.bo.MdMatBo;
+import org.dromara.sc.md.domain.vo.MdMatVo;
+import org.dromara.sc.md.domain.MdMat;
+import org.dromara.sc.md.mapper.MdMatMapper;
+import org.dromara.sc.md.service.IMdMatService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 鐗╂枡Service涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+@DS("oracle_sc")
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class MdMatServiceImpl implements IMdMatService, MatService {
+
+    private final MdMatMapper baseMapper;
+
+    /**
+     * 鏌ヨ鐗╂枡
+     *
+     * @param id 涓婚敭
+     * @return 鐗╂枡
+     */
+    @Override
+    public MdMatVo queryById(String id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ鐗╂枡鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 鐗╂枡鍒嗛〉鍒楄〃
+     */
+    @Override
+    public TableDataInfo<MdMatVo> queryPageList(MdMatBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<MdMat> lqw = buildQueryWrapper(bo);
+        Page<MdMatVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勭墿鏂欏垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 鐗╂枡鍒楄〃
+     */
+    @Override
+    public List<MdMatVo> queryList(MdMatBo bo) {
+        LambdaQueryWrapper<MdMat> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<MdMat> buildQueryWrapper(MdMatBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<MdMat> lqw = Wrappers.lambdaQuery();
+        lqw.orderByAsc(MdMat::getId);
+        lqw.eq(StringUtils.isNotBlank(bo.getCode()), MdMat::getCode, bo.getCode());
+        lqw.like(StringUtils.isNotBlank(bo.getName()), MdMat::getName, bo.getName());
+        lqw.like(StringUtils.isNotBlank(bo.getSimpleName()), MdMat::getSimpleName, bo.getSimpleName());
+        lqw.eq(bo.getEnable() != null, MdMat::getEnable, bo.getEnable());
+        lqw.eq(StringUtils.isNotBlank(bo.getTid()), MdMat::getTid, bo.getTid());
+        return lqw;
+    }
+
+    /**
+     * 鏂板鐗╂枡
+     *
+     * @param bo 鐗╂枡
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public Boolean insertByBo(MdMatBo bo) {
+        MdMat add = MapstructUtils.convert(bo, MdMat.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼鐗╂枡
+     *
+     * @param bo 鐗╂枡
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(MdMatBo bo) {
+        MdMat update = MapstructUtils.convert(bo, MdMat.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(MdMat entity){
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ょ墿鏂欎俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+
+    @Override
+    public String selectMatNameByCode(String matCode) {
+        LambdaQueryWrapper<MdMat> lqw = Wrappers.lambdaQuery();
+        lqw.eq(MdMat::getCode,matCode);
+        MdMatVo mdMatVo = baseMapper.selectVoOne(lqw);
+        return mdMatVo.getName();
+    }
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/impl/MdMatTypeServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/impl/MdMatTypeServiceImpl.java
new file mode 100644
index 0000000..8a43315
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/impl/MdMatTypeServiceImpl.java
@@ -0,0 +1,138 @@
+package org.dromara.sc.md.service.impl;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.dromara.sc.md.domain.bo.MdMatTypeBo;
+import org.dromara.sc.md.domain.vo.MdMatTypeVo;
+import org.dromara.sc.md.domain.MdMatType;
+import org.dromara.sc.md.mapper.MdMatTypeMapper;
+import org.dromara.sc.md.service.IMdMatTypeService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 鐗╂枡绫诲瀷Service涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2026-04-13
+ */
+@DS("oracle_sc")
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class MdMatTypeServiceImpl implements IMdMatTypeService {
+
+    private final MdMatTypeMapper baseMapper;
+
+    /**
+     * 鏌ヨ鐗╂枡绫诲瀷
+     *
+     * @param id 涓婚敭
+     * @return 鐗╂枡绫诲瀷
+     */
+    @Override
+    public MdMatTypeVo queryById(String id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ鐗╂枡绫诲瀷鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 鐗╂枡绫诲瀷鍒嗛〉鍒楄〃
+     */
+    @Override
+    public TableDataInfo<MdMatTypeVo> queryPageList(MdMatTypeBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<MdMatType> lqw = buildQueryWrapper(bo);
+        Page<MdMatTypeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勭墿鏂欑被鍨嬪垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 鐗╂枡绫诲瀷鍒楄〃
+     */
+    @Override
+    public List<MdMatTypeVo> queryList(MdMatTypeBo bo) {
+        LambdaQueryWrapper<MdMatType> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<MdMatType> buildQueryWrapper(MdMatTypeBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<MdMatType> lqw = Wrappers.lambdaQuery();
+        lqw.orderByAsc(MdMatType::getId);
+        lqw.like(StringUtils.isNotBlank(bo.getCode()), MdMatType::getCode, bo.getCode());
+        lqw.like(StringUtils.isNotBlank(bo.getName()), MdMatType::getName, bo.getName());
+        lqw.eq(bo.getEnable() != null, MdMatType::getEnable, bo.getEnable());
+        lqw.eq(StringUtils.isNotBlank(bo.getDel()), MdMatType::getDel, bo.getDel());
+        lqw.like(StringUtils.isNotBlank(bo.getMesCode()), MdMatType::getMesCode, bo.getMesCode());
+        return lqw;
+    }
+
+    /**
+     * 鏂板鐗╂枡绫诲瀷
+     *
+     * @param bo 鐗╂枡绫诲瀷
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public Boolean insertByBo(MdMatTypeBo bo) {
+        MdMatType add = MapstructUtils.convert(bo, MdMatType.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼鐗╂枡绫诲瀷
+     *
+     * @param bo 鐗╂枡绫诲瀷
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(MdMatTypeBo bo) {
+        MdMatType update = MapstructUtils.convert(bo, MdMatType.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(MdMatType entity){
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ょ墿鏂欑被鍨嬩俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/test b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/test
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/test
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmMatcheckMapper.xml b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmMatcheckMapper.xml
new file mode 100644
index 0000000..180a1a7
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmMatcheckMapper.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.qa.qm.mapper.QmMatcheckMapper">
+
+    <select id="listQmMatcheck" resultType="org.dromara.qa.qm.domain.vo.QmMatcheckVo">
+        SELECT
+            a.ID AS id,
+            a.PID AS pid,
+            a.BATCH_CODE AS batchCode,
+            a.MAT_CODE AS matCode,
+            a.INSTRUMENT_CODE AS instrumentCode,
+            a.TECH_REQ AS techReq,
+            a.CHECK_STD AS checkStd,
+            a.TEST_ENV AS testEnv,
+            a.ITEM_CODE AS itemCode,
+            d.ITEM_NAME AS itemName,
+            CAST(NULL AS VARCHAR(100)) AS eqp,
+            a.SUB_BATCH_CODE AS subBatchCode,
+            a.SAMPLE_NUMBER AS sampleNumber,
+            a.SAMPLE_TYPE AS sampleType,
+            a.CHECK_NAME AS checkName,
+            a.CHECK_TIME AS checkTime,
+            a.REVIEW_NAME AS reviewName,
+            a.REVIEW_TIME AS reviewTime,
+            a.MAXVAL AS maxval,
+            a.MINVAL AS minval,
+            a.AVGVAL AS avgval,
+            a.SDVAL AS sdval,
+            a.CVVAL AS cvval,
+            a.CPKVAL AS cpkval,
+            a.BADVAL AS badval,
+            a.JUDGE AS judge,
+            a.SINGLEJUDGE AS singlejudge,
+            a.VER_NAME AS verName,
+            a.VER_CODE AS verCode,
+            a.ARCH_DATE AS archDate,
+            a.DEL AS del,
+            a.FLAG AS flag,
+            a.TO_MES_TIME AS toMesTime,
+            a.CHK_DES AS chkDes,
+            CAST(NULL AS VARCHAR(200)) AS checker,
+            b.JUDGE_CODE AS judgeCode,
+            CAST(NULL AS VARCHAR(10)) AS generateDetails,
+            CAST(NULL AS VARCHAR(10)) AS checkType
+        FROM QM_MATCHECK a
+            JOIN QM_BATCH b ON b.BATCH_CODE = a.BATCH_CODE
+                AND b.MAT_CODE = a.MAT_CODE
+            JOIN QM_JUDGE c ON b.JUDGE_CODE = c.ID
+            JOIN QM_CHECKITEM d ON d.STD_CODE = c.STD_COD
+                AND d.ITEM_CODE = a.ITEM_CODE
+                AND d.RID IS NULL
+                AND d.DEL != 1
+        <where>
+            <if test="bo.batchCode != null and bo.batchCode != ''">
+                AND a.BATCH_CODE = #{bo.batchCode}
+            </if>
+            <if test="bo.matCode != null and bo.matCode != ''">
+                AND a.MAT_CODE = #{bo.matCode}
+            </if>
+            AND (a.DEL = 0 OR a.DEL IS NULL)
+            AND b.DELETED != '1'
+        </where>
+        ORDER BY a.ITEM_CODE, a.SUB_BATCH_CODE
+    </select>
+</mapper>
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/md/MdMatMapper.xml b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/md/MdMatMapper.xml
new file mode 100644
index 0000000..afb20ab
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/md/MdMatMapper.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.sc.md.mapper.MdMatMapper">
+</mapper>
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/md/MdMatTypeMapper.xml b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/md/MdMatTypeMapper.xml
new file mode 100644
index 0000000..5659381
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/md/MdMatTypeMapper.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.sc.md.mapper.MdMatTypeMapper">
+</mapper>
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/test b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/test
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/test
diff --git a/ruoyi-plus-soybean/src/router/elegant/imports.ts b/ruoyi-plus-soybean/src/router/elegant/imports.ts
index 4639592..6e4b3ff 100755
--- a/ruoyi-plus-soybean/src/router/elegant/imports.ts
+++ b/ruoyi-plus-soybean/src/router/elegant/imports.ts
@@ -33,6 +33,8 @@
   demo_tree: () => import("@/views/demo/tree/index.vue"),
   home: () => import("@/views/home/index.vue"),
   md_instrument: () => import("@/views/md/instrument/index.vue"),
+  "md_mat-type": () => import("@/views/md/mat-type/index.vue"),
+  md_mat: () => import("@/views/md/mat/index.vue"),
   md_shift: () => import("@/views/md/shift/index.vue"),
   "md_weighing-box": () => import("@/views/md/weighing-box/index.vue"),
   monitor_cache: () => import("@/views/monitor/cache/index.vue"),
@@ -42,6 +44,7 @@
   qm_batch: () => import("@/views/qm/batch/index.vue"),
   "qm_judge-details": () => import("@/views/qm/judge-details/index.vue"),
   qm_judge: () => import("@/views/qm/judge/index.vue"),
+  qm_matcheck: () => import("@/views/qm/matcheck/index.vue"),
   qm_std: () => import("@/views/qm/std/index.vue"),
   report_demo: () => import("@/views/report/demo/index.vue"),
   "report_silk-storage-output": () => import("@/views/report/silk-storage-output/index.vue"),
diff --git a/ruoyi-plus-soybean/src/router/elegant/routes.ts b/ruoyi-plus-soybean/src/router/elegant/routes.ts
index 2fadf2c..0d1d1ce 100755
--- a/ruoyi-plus-soybean/src/router/elegant/routes.ts
+++ b/ruoyi-plus-soybean/src/router/elegant/routes.ts
@@ -199,6 +199,24 @@
         }
       },
       {
+        name: 'md_mat',
+        path: '/md/mat',
+        component: 'view.md_mat',
+        meta: {
+          title: 'md_mat',
+          i18nKey: 'route.md_mat'
+        }
+      },
+      {
+        name: 'md_mat-type',
+        path: '/md/mat-type',
+        component: 'view.md_mat-type',
+        meta: {
+          title: 'md_mat-type',
+          i18nKey: 'route.md_mat-type'
+        }
+      },
+      {
         name: 'md_shift',
         path: '/md/shift',
         component: 'view.md_shift',
@@ -302,6 +320,15 @@
         }
       },
       {
+        name: 'qm_matcheck',
+        path: '/qm/matcheck',
+        component: 'view.qm_matcheck',
+        meta: {
+          title: 'qm_matcheck',
+          i18nKey: 'route.qm_matcheck'
+        }
+      },
+      {
         name: 'qm_std',
         path: '/qm/std',
         component: 'view.qm_std',
diff --git a/ruoyi-plus-soybean/src/router/elegant/transform.ts b/ruoyi-plus-soybean/src/router/elegant/transform.ts
index 4d6dcc9..d2cbbfa 100755
--- a/ruoyi-plus-soybean/src/router/elegant/transform.ts
+++ b/ruoyi-plus-soybean/src/router/elegant/transform.ts
@@ -186,6 +186,8 @@
   "login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?",
   "md": "/md",
   "md_instrument": "/md/instrument",
+  "md_mat": "/md/mat",
+  "md_mat-type": "/md/mat-type",
   "md_shift": "/md/shift",
   "md_weighing-box": "/md/weighing-box",
   "monitor": "/monitor",
@@ -197,6 +199,7 @@
   "qm_batch": "/qm/batch",
   "qm_judge": "/qm/judge",
   "qm_judge-details": "/qm/judge-details",
+  "qm_matcheck": "/qm/matcheck",
   "qm_std": "/qm/std",
   "report": "/report",
   "report_demo": "/report/demo",
diff --git a/ruoyi-plus-soybean/src/service/api/md/mat-type.ts b/ruoyi-plus-soybean/src/service/api/md/mat-type.ts
new file mode 100644
index 0000000..da2cdd3
--- /dev/null
+++ b/ruoyi-plus-soybean/src/service/api/md/mat-type.ts
@@ -0,0 +1,35 @@
+import { request } from '@/service/request';
+
+/** 鑾峰彇鐗╂枡绫诲瀷鍒楄〃 */
+export function fetchGetMatTypeList (params?: Api.Md.MatTypeSearchParams) {
+    return request<Api.Md.MatTypeList>({
+        url: '/md/matType/list',
+        method: 'get',
+        params
+    });
+}
+/** 鏂板鐗╂枡绫诲瀷 */
+export function fetchCreateMatType (data: Api.Md.MatTypeOperateParams) {
+    return request<boolean>({
+        url: '/md/matType',
+        method: 'post',
+        data
+    });
+}
+
+/** 淇敼鐗╂枡绫诲瀷 */
+export function fetchUpdateMatType (data: Api.Md.MatTypeOperateParams) {
+    return request<boolean>({
+        url: '/md/matType',
+        method: 'put',
+        data
+    });
+}
+
+/** 鎵归噺鍒犻櫎鐗╂枡绫诲瀷 */
+export function fetchBatchDeleteMatType (ids: CommonType.IdType[]) {
+    return request<boolean>({
+        url: `/md/matType/${ids.join(',')}`,
+        method: 'delete'
+    });
+}
diff --git a/ruoyi-plus-soybean/src/service/api/md/mat.ts b/ruoyi-plus-soybean/src/service/api/md/mat.ts
new file mode 100644
index 0000000..dcd6389
--- /dev/null
+++ b/ruoyi-plus-soybean/src/service/api/md/mat.ts
@@ -0,0 +1,35 @@
+import { request } from '@/service/request';
+
+/** 鑾峰彇鐗╂枡鍒楄〃 */
+export function fetchGetMatList (params?: Api.Md.MatSearchParams) {
+    return request<Api.Md.MatList>({
+        url: '/md/mat/list',
+        method: 'get',
+        params
+    });
+}
+/** 鏂板鐗╂枡 */
+export function fetchCreateMat (data: Api.Md.MatOperateParams) {
+    return request<boolean>({
+        url: '/md/mat',
+        method: 'post',
+        data
+    });
+}
+
+/** 淇敼鐗╂枡 */
+export function fetchUpdateMat (data: Api.Md.MatOperateParams) {
+    return request<boolean>({
+        url: '/md/mat',
+        method: 'put',
+        data
+    });
+}
+
+/** 鎵归噺鍒犻櫎鐗╂枡 */
+export function fetchBatchDeleteMat (ids: CommonType.IdType[]) {
+    return request<boolean>({
+        url: `/md/mat/${ids.join(',')}`,
+        method: 'delete'
+    });
+}
diff --git a/ruoyi-plus-soybean/src/service/api/qm/judge-details.ts b/ruoyi-plus-soybean/src/service/api/qm/judge-details.ts
index 3f180f9..971f037 100644
--- a/ruoyi-plus-soybean/src/service/api/qm/judge-details.ts
+++ b/ruoyi-plus-soybean/src/service/api/qm/judge-details.ts
@@ -8,6 +8,16 @@
     params
   });
 }
+/** 鑾峰彇鍒ゅ畾妯℃澘鏄庣粏鏍戝舰鍒楄〃 */
+export function fetchGetJudgeDetailsTree(params?: Api.Qm.JudgeDetailsSearchParams) {
+  return request<Api.Qm.JudgeDetailsList>({
+    url: '/qm/judgeDetails/tree',
+    method: 'get',
+    params
+  });
+}
+
+
 /** 鏂板鍒ゅ畾妯℃澘鏄庣粏 */
 export function fetchCreateJudgeDetails(data: Api.Qm.JudgeDetailsOperateParams) {
   return request<boolean>({
diff --git a/ruoyi-plus-soybean/src/service/api/qm/matcheck.ts b/ruoyi-plus-soybean/src/service/api/qm/matcheck.ts
new file mode 100644
index 0000000..8353c54
--- /dev/null
+++ b/ruoyi-plus-soybean/src/service/api/qm/matcheck.ts
@@ -0,0 +1,57 @@
+import { request } from '@/service/request';
+
+/** 鑾峰彇鏉愭枡妫�楠岀粺璁″垪琛� */
+export function fetchGetMatcheckList (params?: Api.Qm.MatcheckSearchParams) {
+    return request<Api.Qm.MatcheckList>({
+        url: '/qm/matcheck/list',
+        method: 'get',
+        params
+    });
+}
+
+export function fetchCheckItemList (params?: Api.Qm.MatcheckSearchParams) {
+  return request<Api.Qm.MatcheckCustomItem[]>({
+    url: '/qm/matcheck/listCheckItem',
+    method: 'get',
+    params
+  });
+}
+
+
+/**
+ * 澶氳〃鏌ヨ
+ * @param params
+ */
+export function fetchGetQmMatcheckList (params?: Api.Qm.MatcheckSearchParams) {
+  return request<Api.Qm.MatcheckList[]>({
+    url: '/qm/matcheck/listQmMatcheck',
+    method: 'get',
+    params
+  });
+}
+
+/** 鏂板鏉愭枡妫�楠岀粺璁� */
+export function fetchCreateMatcheck (data: Api.Qm.MatcheckOperateParams) {
+    return request<boolean>({
+        url: '/qm/matcheck',
+        method: 'post',
+        data
+    });
+}
+
+/** 淇敼鏉愭枡妫�楠岀粺璁� */
+export function fetchUpdateMatcheck (data: Api.Qm.MatcheckOperateParams) {
+    return request<boolean>({
+        url: '/qm/matcheck',
+        method: 'put',
+        data
+    });
+}
+
+/** 鎵归噺鍒犻櫎鏉愭枡妫�楠岀粺璁� */
+export function fetchBatchDeleteMatcheck (ids: CommonType.IdType[]) {
+    return request<boolean>({
+        url: `/qm/matcheck/${ids.join(',')}`,
+        method: 'delete'
+    });
+}
diff --git a/ruoyi-plus-soybean/src/typings/api/md.mat-type.api.d.ts b/ruoyi-plus-soybean/src/typings/api/md.mat-type.api.d.ts
new file mode 100644
index 0000000..aa4ccc5
--- /dev/null
+++ b/ruoyi-plus-soybean/src/typings/api/md.mat-type.api.d.ts
@@ -0,0 +1,76 @@
+/**
+ * Namespace Api
+ *
+ * All backend api type
+ */
+declare namespace Api {
+    /**
+     * namespace Md
+     *
+     * backend api module: "Md"
+     */
+    namespace Md {
+        /** mat type */
+        type MatType = Common.CommonRecord<{
+            /** id */
+                id: CommonType.IdType; 
+            /** 鐗╂枡缁勫閿� */
+                gid: CommonType.IdType; 
+            /** 缂栫爜 */
+                code: string; 
+            /** 鍚嶇О */
+                name: string; 
+            /** 鎻忚堪 */
+                des: string; 
+            /** 鍚敤 */
+                enable: number; 
+            /** 鍒犻櫎 */
+                del: string; 
+            /** mes缂栫爜 */
+                mesCode: string; 
+            /** 鍒涘缓浜� */
+                createUserName: string; 
+            /** 鍒涘缓鏃堕棿 */
+                createUserTime: string; 
+            /** 鏇存柊浜� */
+                updateUserName: string; 
+            /** 鏇存柊鏃堕棿 */
+                updateUserTime: string; 
+        }>;
+
+        /** mat type search params */
+        type MatTypeSearchParams = CommonType.RecordNullable<
+            Pick<
+                Api.Md.MatType,
+                        | 'code'
+                        | 'name'
+                        | 'enable'
+                        | 'del'
+                        | 'mesCode'
+            > &
+            Api.Common.CommonSearchParams
+        >;
+
+        /** mat type operate params */
+        type MatTypeOperateParams = CommonType.RecordNullable<
+            Pick<
+                Api.Md.MatType,
+                        | 'id'
+                        | 'gid'
+                        | 'code'
+                        | 'name'
+                        | 'des'
+                        | 'enable'
+                        | 'del'
+                        | 'mesCode'
+                        | 'createUserName'
+                        | 'createUserTime'
+                        | 'updateUserName'
+                        | 'updateUserTime'
+            >
+        >;
+
+        /** mat type list */
+        type MatTypeList = Api.Common.PaginatingQueryRecord<MatType>;
+    }
+}
diff --git a/ruoyi-plus-soybean/src/typings/api/md.mat.api.d.ts b/ruoyi-plus-soybean/src/typings/api/md.mat.api.d.ts
new file mode 100644
index 0000000..5ed69f4
--- /dev/null
+++ b/ruoyi-plus-soybean/src/typings/api/md.mat.api.d.ts
@@ -0,0 +1,83 @@
+/**
+ * Namespace Api
+ *
+ * All backend api type
+ */
+declare namespace Api {
+    /**
+     * namespace Md
+     *
+     * backend api module: "Md"
+     */
+    namespace Md {
+        /** mat */
+        type Mat = Common.CommonRecord<{
+            /** id */
+                id: CommonType.IdType; 
+            /** 鐗╂枡浠g爜 */
+                code: string; 
+            /** 鍏ㄧО */
+                name: string; 
+            /** 绠�绉� */
+                simpleName: string; 
+            /** 鎻忚堪 */
+                des: string; 
+            /** 鍗曚綅 */
+                uid: CommonType.IdType; 
+            /** 鏈�鍚庢洿鏂版椂闂� */
+                lastUpdateTime: string; 
+            /** 鍚敤 */
+                enable: number; 
+            /** 鍒犻櫎 */
+                del: string; 
+            /** 鐗╂枡绫诲瀷 */
+                tid: CommonType.IdType; 
+            /** 鍒涘缓浜� */
+                createUserName: string; 
+            /** 鍒涘缓鏃堕棿 */
+                createUserTime: string; 
+            /** 鏇存柊浜� */
+                updateUserName: string; 
+            /** 鏇存柊鏃堕棿 */
+                updateUserTime: string; 
+        }>;
+
+        /** mat search params */
+        type MatSearchParams = CommonType.RecordNullable<
+            Pick<
+                Api.Md.Mat,
+                        | 'code'
+                        | 'name'
+                        | 'simpleName'
+                        | 'enable'
+                        | 'del'
+                        | 'tid'
+            > &
+            Api.Common.CommonSearchParams
+        >;
+
+        /** mat operate params */
+        type MatOperateParams = CommonType.RecordNullable<
+            Pick<
+                Api.Md.Mat,
+                        | 'id'
+                        | 'code'
+                        | 'name'
+                        | 'simpleName'
+                        | 'des'
+                        | 'uid'
+                        | 'lastUpdateTime'
+                        | 'enable'
+                        | 'del'
+                        | 'tid'
+                        | 'createUserName'
+                        | 'createUserTime'
+                        | 'updateUserName'
+                        | 'updateUserTime'
+            >
+        >;
+
+        /** mat list */
+        type MatList = Api.Common.PaginatingQueryRecord<Mat>;
+    }
+}
diff --git a/ruoyi-plus-soybean/src/typings/api/qm.batch.api.d.ts b/ruoyi-plus-soybean/src/typings/api/qm.batch.api.d.ts
index bdb8333..97572b6 100755
--- a/ruoyi-plus-soybean/src/typings/api/qm.batch.api.d.ts
+++ b/ruoyi-plus-soybean/src/typings/api/qm.batch.api.d.ts
@@ -24,6 +24,8 @@
       eqpCode: string;
       /** 鐗屽彿 */
       matCode: string;
+      /** 鐗屽彿 */
+      matName: string;
       /** 鍒ゅ畾渚濇嵁浠g爜 */
       judgeCode: string;
       /** 鎵规鐢熸垚鏃ユ湡 */
@@ -113,6 +115,7 @@
       Pick<
         Api.Qm.Batch,
         | 'batchCode'
+        | 'isflag'
         | 'typ'
         | 'eqpCode'
         | 'matCode'
@@ -120,6 +123,7 @@
         | 'flag'
         | 'toMesDate'
         | 'fromMesDate'
+        | 'enabled'
         | 'deleted'
         | 'category'
         | 'state'
diff --git a/ruoyi-plus-soybean/src/typings/api/qm.judge-details.api.d.ts b/ruoyi-plus-soybean/src/typings/api/qm.judge-details.api.d.ts
index 681ce8f..f4e3cbc 100644
--- a/ruoyi-plus-soybean/src/typings/api/qm.judge-details.api.d.ts
+++ b/ruoyi-plus-soybean/src/typings/api/qm.judge-details.api.d.ts
@@ -16,32 +16,54 @@
       id: CommonType.IdType;
       /** 鍒ゅ畾涓绘爣璇� */
       judgeId: CommonType.IdType;
-      /** 鍒ゅ畾椤笽TEM */
+      /** 妫�楠岄」鐩唬鐮� */
+      itemCode: string;
+      /** 鍒ゅ畾椤笽TEM (鍏煎鏃у瓧娈�) */
       itemCod: string;
-      /** 鍒ゅ畾椤筃AME */
+      /** 妫�楠岄」鐩悕绉� */
       itemName: string;
+      /** 鍗曚綅 */
+      unit: string;
+      /** 鍚敤 */
+      enable: number;
+      /** 鍒犻櫎 */
+      del: number;
+      /** 妫�楠岄」鎻忚堪 */
+      itemDes: string;
+      /** 瑙勭▼浠g爜 */
+      stdCode: string;
+      /** 浠櫒鎻忚堪 */
+      instrumentDes: string;
       /** 鏍囧噯鍊� */
       value3: number;
       /** 鍒ゅ畾鍊�1 */
       value1: number;
       /** 鍒ゅ畾鍊�2 */
       value2: number;
-      /** 缂洪櫡浣嶇疆 */
+      /** 缂洪櫡浣嶇疆-澶栬鐢� */
       location: string;
-      /** 鍒ゅ畾绾у埆 (A,B,C,D) */
+      /** 鍒咥,B,C,D鍥涗釜绾у埆 */
+      checkLevel: string;
+      /** 鍒ゅ畾绾у埆 (A,B,C,D) (鍏煎鏃у瓧娈�) */
       cls: string;
-      /** 鍒嗗�兼爣鍑� (鎵e垎鏍囧噯锛屽緱鍒嗘爣鍑�),姣斿涓嶅悎鏍间竴娆℃墸澶氬皯鍒� */
+      /** 鍒嗗�� */
+      score: number;
+      /** 鍒嗗�兼爣鍑� (鎵e垎鏍囧噯锛屽緱鍒嗘爣鍑�) (鍏煎鏃у瓧娈�) */
       stdscore: number;
-      /** 鏍囪姝ら」鏄惁涓哄悎鎴愰」鐩紝姣斿澶栬锛屽疄闄呬笂鍏宠仈浜嗗緢澶氬瓙椤圭洰 */
+      /** 鏄惁鍚堟垚椤� */
       ismix: number;
-      /** 鑻ユ瀛楁鏈塙UID鍊硷紝琛ㄦ槑瀹冨彲鑳戒负鍏朵粬椤圭洰鐨勫瓙椤癸紝姣斿鈥滅┖澶粹��,瀹冧负鐑熸敮澶栬椤圭洰鐨勫瓙椤� */
+      /** 鍏宠仈椤笽D */
       rid: CommonType.IdType;
-      /** 鑼冨洿-澶囩敤 */
+      /** 绫诲埆 0:鎴愬搧 1杈呮枡 */
       category: number;
-      /** 澶囨敞 */
+      /** 浠櫒缂栫爜 */
+      instrumentCode: string;
+      /** 澶囨敞 (鍏煎鏃у瓧娈�) */
       decisionDes: string;
       /** 淇敼浜� */
       updateUser: string;
+      /** 瀛愯妭鐐� */
+      children?: Api.Qm.JudgeDetails[];
     }>;
 
     /** judge details search params */
diff --git a/ruoyi-plus-soybean/src/typings/api/qm.matcheck.api.d.ts b/ruoyi-plus-soybean/src/typings/api/qm.matcheck.api.d.ts
new file mode 100644
index 0000000..c340104
--- /dev/null
+++ b/ruoyi-plus-soybean/src/typings/api/qm.matcheck.api.d.ts
@@ -0,0 +1,165 @@
+/**
+ * Namespace Api
+ *
+ * All backend api type
+ */
+declare namespace Api {
+    /**
+     * namespace Qm
+     *
+     * backend api module: "Qm"
+     */
+    namespace Qm {
+        /** matcheck */
+        type Matcheck = Common.CommonRecord<{
+            /** id */
+                id: CommonType.IdType;
+            /** 姹囨�昏〃ID */
+                pid: CommonType.IdType;
+            /** 妫�楠屾壒娆� */
+                batchCode: string;
+            /** 鐗屽彿 */
+                matCode: string;
+            /** 浠櫒缂栧彿 */
+                instrumentCode: string;
+            /** 鎶�鏈姹� */
+                techReq: string;
+            /** 妫�楠屼緷鎹� */
+                checkStd: string;
+            /** 娴嬭瘯鐜 */
+                testEnv: string;
+            /** 妫�楠岄」鐩瓹OD */
+                itemCode: string;
+            /** 妫�楠岄」鐩悕绉� */
+                itemName: string;
+            /** 璁惧 */
+                eqp: string;
+            /** 鐩樺彿 */
+                subBatchCode: string;
+            /** 姣忕洏妫�楠屾暟閲� */
+                sampleNumber: number;
+            /** 鍙栨牱绫诲瀷 */
+                sampleType: number;
+            /** 妫�楠屽憳 */
+                checkName: string;
+            /** 妫�楠屾椂闂� */
+                checkTime: string;
+            /** 澶嶆牳鍛� */
+                reviewName: string;
+            /** 澶嶆牳鏃堕棿 */
+                reviewTime: string;
+            /** 鏈�澶у�� */
+                maxval: number;
+            /** 鏈�灏忓�� */
+                minval: number;
+            /** 骞冲潎鍊� */
+                avgval: number;
+            /** SD鍊� */
+                sdval: number;
+            /** CV鍊� */
+                cvval: number;
+            /** CPK鍊� */
+                cpkval: number;
+            /** 瓒呮爣鏁� */
+                badval: number;
+            /** 鍒ゅ畾 */
+                judge: string;
+            /** 鍗曢」鍒ゅ畾 */
+                singlejudge: string;
+            /** 鐗堟湰鍚嶇О */
+                verName: string;
+            /** 鐗堟湰缂栧彿 */
+                verCode: string;
+            /** 淇濆瓨鏈� */
+                archDate: string;
+            /** 鍒犻櫎鏍囧織 */
+                del: number;
+            /** 0-鏈笂浼爉es 1-宸蹭笂浼� */
+                flag: string;
+            /** 涓婁紶MES鏃堕棿 */
+                toMesTime: string;
+            /** 澶囨敞 */
+                chkDes: string;
+            /** 妫�楠屼汉灞曠ず鍚� */
+                checker: string;
+            /** 鍒ゅ畾瑙勭▼ code锛堥潪鏁版嵁搴撳瓧娈碉級 */
+                judgeCode: string;
+            /** 鏄惁鐢熸垚 30 鏀儫鏄庣粏锛堥潪鏁版嵁搴撳瓧娈碉級 */
+                generateDetails: string;
+            /** 妫�娴嬬被鍨嬶紙闈炴暟鎹簱瀛楁锛� */
+                checkType: string;
+        }>;
+
+        /** matcheck search params */
+        type MatcheckSearchParams = CommonType.RecordNullable<
+            Pick<
+                Api.Qm.Matcheck,
+                        | 'batchCode'
+                        | 'judgeCode'
+                        | 'matCode'
+                        | 'checkName'
+                        | 'checkTime'
+                        | 'reviewName'
+                        | 'reviewTime'
+            > &
+            Api.Common.CommonSearchParams & {
+                /** 妫�楠岄」涓嬫媺绛夋帴鍙d娇鐢ㄧ殑鍒ゅ畾瑙勭▼ id */
+                judgeId?: string;
+            }
+        >;
+
+        /** matcheck operate params */
+        type MatcheckOperateParams = CommonType.RecordNullable<
+            Pick<
+                Api.Qm.Matcheck,
+                        | 'id'
+                        | 'pid'
+                        | 'batchCode'
+                        | 'matCode'
+                        | 'instrumentCode'
+                        | 'techReq'
+                        | 'checkStd'
+                        | 'testEnv'
+                        | 'itemCode'
+                        | 'itemName'
+                        | 'eqp'
+                        | 'subBatchCode'
+                        | 'sampleNumber'
+                        | 'sampleType'
+                        | 'checkName'
+                        | 'checkTime'
+                        | 'reviewName'
+                        | 'reviewTime'
+                        | 'maxval'
+                        | 'minval'
+                        | 'avgval'
+                        | 'sdval'
+                        | 'cvval'
+                        | 'cpkval'
+                        | 'badval'
+                        | 'judge'
+                        | 'singlejudge'
+                        | 'verName'
+                        | 'verCode'
+                        | 'archDate'
+                        | 'del'
+                        | 'flag'
+                        | 'toMesTime'
+                        | 'chkDes'
+                        | 'checker'
+                        | 'judgeCode'
+                        | 'generateDetails'
+                        | 'checkType'
+            >
+        >;
+
+        /** matcheck list */
+        type MatcheckList = Api.Common.PaginatingQueryRecord<Matcheck>;
+
+        /** custom matcheck item */
+        type MatcheckCustomItem = {
+            itemCode: string;
+            itemName: string;
+        };
+    }
+}
diff --git a/ruoyi-plus-soybean/src/typings/elegant-router.d.ts b/ruoyi-plus-soybean/src/typings/elegant-router.d.ts
index 42fe324..c2dc49e 100755
--- a/ruoyi-plus-soybean/src/typings/elegant-router.d.ts
+++ b/ruoyi-plus-soybean/src/typings/elegant-router.d.ts
@@ -40,6 +40,8 @@
     "login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
     "md": "/md";
     "md_instrument": "/md/instrument";
+    "md_mat": "/md/mat";
+    "md_mat-type": "/md/mat-type";
     "md_shift": "/md/shift";
     "md_weighing-box": "/md/weighing-box";
     "monitor": "/monitor";
@@ -51,6 +53,7 @@
     "qm_batch": "/qm/batch";
     "qm_judge": "/qm/judge";
     "qm_judge-details": "/qm/judge-details";
+    "qm_matcheck": "/qm/matcheck";
     "qm_std": "/qm/std";
     "report": "/report";
     "report_demo": "/report/demo";
@@ -161,6 +164,8 @@
     | "demo_tree"
     | "home"
     | "md_instrument"
+    | "md_mat-type"
+    | "md_mat"
     | "md_shift"
     | "md_weighing-box"
     | "monitor_cache"
@@ -170,6 +175,7 @@
     | "qm_batch"
     | "qm_judge-details"
     | "qm_judge"
+    | "qm_matcheck"
     | "qm_std"
     | "report_demo"
     | "report_silk-storage-output"
diff --git a/ruoyi-plus-soybean/src/views/md/mat-type/index.vue b/ruoyi-plus-soybean/src/views/md/mat-type/index.vue
new file mode 100644
index 0000000..c3fdd16
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/md/mat-type/index.vue
@@ -0,0 +1,241 @@
+<script setup lang="tsx">
+import { ref } from 'vue';
+import { NDivider } from 'naive-ui';
+import { fetchBatchDeleteMatType, fetchGetMatTypeList } from '@/service/api/md/mat-type';
+import { useAppStore } from '@/store/modules/app';
+import { useAuth } from '@/hooks/business/auth';
+import { useDownload } from '@/hooks/business/download';
+import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
+import { $t } from '@/locales';
+import ButtonIcon from '@/components/custom/button-icon.vue';
+import MatTypeOperateDrawer from './modules/mat-type-operate-drawer.vue';
+import MatTypeSearch from './modules/mat-type-search.vue';
+
+defineOptions({
+  name: 'MatTypeList'
+});
+
+
+const appStore = useAppStore();
+const { download } = useDownload();
+const { hasAuth } = useAuth();
+
+const searchParams = ref<Api.Md.MatTypeSearchParams>({
+  pageNum: 1,
+  pageSize: 10,
+  code: null,
+  name: null,
+  enable: 1,
+  del: '0',
+  mesCode: null,
+  params: {}
+});
+
+const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
+  useNaivePaginatedTable({
+  api: () => fetchGetMatTypeList(searchParams.value),
+  transform: response => defaultTransform(response),
+  onPaginationParamsChange: params => {
+    searchParams.value.pageNum = params.page;
+    searchParams.value.pageSize = params.pageSize;
+  },
+  columns: () => [
+    {
+      type: 'selection',
+      align: 'center',
+      width: 48
+    },
+    {
+      key: 'index',
+      title: $t('common.index'),
+      align: 'center',
+      width: 64,
+      render: (_, index) => index + 1
+    },
+    {
+      key: 'code',
+      title: '缂栫爜',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'name',
+      title: '鍚嶇О',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'des',
+      title: '鎻忚堪',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'enable',
+      title: '鍚敤',
+      align: 'center',
+      minWidth: 120,
+      render: row => (row.enable == 1 ? '鏄�' : '鍚�')
+    },
+    {
+      key: 'del',
+      title: '鍒犻櫎',
+      align: 'center',
+      minWidth: 120,
+      render: row => (row.del == 1 ? '鏄�' : '鍚�')
+    },
+    {
+      key: 'mesCode',
+      title: 'mes缂栫爜',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'createUserName',
+      title: '鍒涘缓浜�',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'createUserTime',
+      title: '鍒涘缓鏃堕棿',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'updateUserName',
+      title: '鏇存柊浜�',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'updateUserTime',
+      title: '鏇存柊鏃堕棿',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'operate',
+      title: $t('common.operate'),
+      align: 'center',
+      fixed: 'right',
+      width: 130,
+      render: row => {
+        const divider = () => {
+          if (!hasAuth('md:matType:edit') || !hasAuth('md:matType:remove')) {
+            return null;
+          }
+          return <NDivider vertical />;
+        };
+
+        const editBtn = () => {
+          if (!hasAuth('md:matType:edit')) {
+            return null;
+          }
+          return (
+            <ButtonIcon
+              text
+              type="primary"
+              icon="material-symbols:drive-file-rename-outline-outline"
+              tooltipContent={$t('common.edit')}
+              onClick={() => edit(row.id)}
+            />
+          );
+        };
+
+        const deleteBtn = () => {
+          if (!hasAuth('md:matType:remove')) {
+            return null;
+          }
+          return (
+            <ButtonIcon
+              text
+              type="error"
+              icon="material-symbols:delete-outline"
+              tooltipContent={$t('common.delete')}
+              popconfirmContent={$t('common.confirmDelete')}
+              onPositiveClick={() => handleDelete(row.id)}
+            />
+          );
+        };
+
+        return (
+          <div class="flex-center gap-8px">
+            {editBtn()}
+            {divider()}
+            {deleteBtn()}
+          </div>
+        );
+      }
+    }
+  ]
+});
+
+const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
+  useTableOperate(data, 'id', getData);
+
+async function handleBatchDelete() {
+  // request
+  const { error } = await fetchBatchDeleteMatType(checkedRowKeys.value);
+  if (error) return;
+  onBatchDeleted();
+}
+
+async function handleDelete(id: CommonType.IdType) {
+  // request
+  const { error } = await fetchBatchDeleteMatType([id]);
+  if (error) return;
+  onDeleted();
+}
+
+function edit(id: CommonType.IdType) {
+  handleEdit(id);
+}
+
+function handleExport() {
+  download('/md/matType/export', searchParams.value, `鐗╂枡绫诲瀷_${new Date().getTime()}.xlsx`);
+}
+</script>
+
+<template>
+  <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
+    <MatTypeSearch v-model:model="searchParams" @search="getDataByPage" />
+    <NCard title="鐗╂枡绫诲瀷鍒楄〃" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
+      <template #header-extra>
+        <TableHeaderOperation
+          v-model:columns="columnChecks"
+          :disabled-delete="checkedRowKeys.length === 0"
+          :loading="loading"
+          :show-add="hasAuth('md:matType:add')"
+          :show-delete="hasAuth('md:matType:remove')"
+          :show-export="hasAuth('md:matType:export')"
+          @add="handleAdd"
+          @delete="handleBatchDelete"
+          @export="handleExport"
+          @refresh="getData"
+        />
+      </template>
+      <NDataTable
+        v-model:checked-row-keys="checkedRowKeys"
+        :columns="columns"
+        :data="data"
+        size="small"
+        :flex-height="!appStore.isMobile"
+        :scroll-x="scrollX"
+        :loading="loading"
+        remote
+        :row-key="row => row.id"
+        :pagination="mobilePagination"
+        class="sm:h-full"
+      />
+      <MatTypeOperateDrawer
+        v-model:visible="drawerVisible"
+        :operate-type="operateType"
+        :row-data="editingData"
+        @submitted="getDataByPage"
+      />
+    </NCard>
+  </div>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/md/mat-type/modules/mat-type-operate-drawer.vue b/ruoyi-plus-soybean/src/views/md/mat-type/modules/mat-type-operate-drawer.vue
new file mode 100644
index 0000000..c46a545
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/md/mat-type/modules/mat-type-operate-drawer.vue
@@ -0,0 +1,171 @@
+<script setup lang="ts">
+import { computed, ref, watch } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { fetchCreateMatType, fetchUpdateMatType } from '@/service/api/md/mat-type';
+import { useFormRules, useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+  name: 'MatTypeOperateDrawer'
+});
+
+interface Props {
+  /** the type of operation */
+  operateType: NaiveUI.TableOperateType;
+  /** the edit row data */
+  rowData?: Api.Md.MatType | null;
+}
+
+const props = defineProps<Props>();
+
+interface Emits {
+  (e: 'submitted'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const visible = defineModel<boolean>('visible', {
+  default: false
+});
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+const { createRequiredRule } = useFormRules();
+
+const title = computed(() => {
+  const titles: Record<NaiveUI.TableOperateType, string> = {
+    add: '鏂板鐗╂枡绫诲瀷',
+    edit: '缂栬緫鐗╂枡绫诲瀷'
+  };
+  return titles[props.operateType];
+});
+
+type Model = Api.Md.MatTypeOperateParams;
+
+const model = ref<Model>(createDefaultModel());
+
+function createDefaultModel(): Model {
+  return {
+      id: '',
+      gid: '',
+      code: '',
+      name: '',
+      des: '',
+      enable: null,
+      del: '',
+      mesCode: '',
+      createUserName: '',
+      createUserTime: null,
+      updateUserName: '',
+      updateUserTime: null
+  };
+}
+
+type RuleKey = Extract<
+  keyof Model,
+  | 'id'
+>;
+
+const rules: Record<RuleKey, App.Global.FormRule> = {
+  id: createRequiredRule('id涓嶈兘涓虹┖'),
+};
+
+function handleUpdateModelWhenEdit() {
+  model.value = createDefaultModel();
+
+  if (props.operateType === 'edit' && props.rowData) {
+    Object.assign(model.value, jsonClone(props.rowData));
+  }
+}
+
+function closeDrawer() {
+  visible.value = false;
+}
+
+async function handleSubmit() {
+  await validate();
+
+  const { id, gid, code, name, des, enable, del, mesCode, createUserName, createUserTime, updateUserName, updateUserTime } = model.value;
+
+  // request
+  if (props.operateType === 'add') {
+    const { error } = await fetchCreateMatType({ gid, code, name, des, enable, del, mesCode, createUserName, createUserTime, updateUserName, updateUserTime });
+    if (error) return;
+  }
+
+  if (props.operateType === 'edit') {
+    const { error } = await fetchUpdateMatType({ id, gid, code, name, des, enable, del, mesCode, createUserName, createUserTime, updateUserName, updateUserTime });
+    if (error) return;
+  }
+
+  window.$message?.success($t('common.updateSuccess'));
+  closeDrawer();
+  emit('submitted');
+}
+
+watch(visible, () => {
+  if (visible.value) {
+    handleUpdateModelWhenEdit();
+    restoreValidation();
+  }
+});
+</script>
+
+<template>
+  <NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
+    <NDrawerContent :title="title" :native-scrollbar="false" closable>
+      <NForm ref="formRef" :model="model" :rules="rules">
+        <NFormItem label="鐗╂枡缁勫閿�" path="gid">
+          <NInput v-model:value="model.gid" placeholder="璇疯緭鍏ョ墿鏂欑粍澶栭敭" />
+        </NFormItem>
+        <NFormItem label="缂栫爜" path="code">
+          <NInput v-model:value="model.code" placeholder="璇疯緭鍏ョ紪鐮�" />
+        </NFormItem>
+        <NFormItem label="鍚嶇О" path="name">
+          <NInput v-model:value="model.name" placeholder="璇疯緭鍏ュ悕绉�" />
+        </NFormItem>
+        <NFormItem label="鎻忚堪" path="des">
+          <NInput v-model:value="model.des" placeholder="璇疯緭鍏ユ弿杩�" />
+        </NFormItem>
+        <NFormItem label="鍚敤" path="enable">
+          <NInput v-model:value="model.enable" placeholder="璇疯緭鍏ュ惎鐢�" />
+        </NFormItem>
+        <NFormItem label="鍒犻櫎" path="del">
+          <NInput v-model:value="model.del" placeholder="璇疯緭鍏ュ垹闄�" />
+        </NFormItem>
+        <NFormItem label="mes缂栫爜" path="mesCode">
+          <NInput v-model:value="model.mesCode" placeholder="璇疯緭鍏es缂栫爜" />
+        </NFormItem>
+        <NFormItem label="鍒涘缓浜�" path="createUserName">
+          <NInput v-model:value="model.createUserName" placeholder="璇疯緭鍏ュ垱寤轰汉" />
+        </NFormItem>
+        <NFormItem label="鍒涘缓鏃堕棿" path="createUserTime">
+          <NDatePicker
+            v-model:formatted-value="model.createUserTime"
+            type="datetime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            clearable
+          />
+        </NFormItem>
+        <NFormItem label="鏇存柊浜�" path="updateUserName">
+          <NInput v-model:value="model.updateUserName" placeholder="璇疯緭鍏ユ洿鏂颁汉" />
+        </NFormItem>
+        <NFormItem label="鏇存柊鏃堕棿" path="updateUserTime">
+          <NDatePicker
+            v-model:formatted-value="model.updateUserTime"
+            type="datetime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            clearable
+          />
+        </NFormItem>
+      </NForm>
+      <template #footer>
+        <NSpace :size="16">
+          <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
+          <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
+        </NSpace>
+      </template>
+    </NDrawerContent>
+  </NDrawer>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/md/mat-type/modules/mat-type-search.vue b/ruoyi-plus-soybean/src/views/md/mat-type/modules/mat-type-search.vue
new file mode 100644
index 0000000..a55c423
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/md/mat-type/modules/mat-type-search.vue
@@ -0,0 +1,99 @@
+<script setup lang="ts">
+import { toRaw } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+  name: 'MatTypeSearch'
+});
+
+interface Emits {
+  (e: 'search'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+
+const model = defineModel<Api.Md.MatTypeSearchParams>('model', { required: true });
+
+const defaultModel = jsonClone(toRaw(model.value));
+
+function resetModel() {
+  Object.assign(model.value, defaultModel);
+}
+
+async function reset() {
+  await restoreValidation();
+  resetModel();
+  emit('search');
+}
+
+async function search() {
+  await validate();
+  emit('search');
+}
+</script>
+
+<template>
+  <NCard :bordered="false" size="small" class="card-wrapper">
+    <NCollapse>
+      <NCollapseItem :title="$t('common.search')" name="md-mat-type-search">
+        <NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
+          <NGrid responsive="screen" item-responsive>
+            <NFormItemGi span="24 s:12 m:6" label="缂栫爜" label-width="auto" path="code" class="pr-24px">
+              <NInput v-model:value="model.code" placeholder="璇疯緭鍏ョ紪鐮�" />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="鍚嶇О" label-width="auto" path="name" class="pr-24px">
+              <NInput v-model:value="model.name" placeholder="璇疯緭鍏ュ悕绉�" />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="鍚敤" label-width="auto" path="enable" class="pr-24px">
+              <NSelect
+                v-model:value="model.enable"
+                placeholder="璇烽�夋嫨鍚敤"
+                :options="[
+                  { label: '鏄�', value: 1 },
+                  { label: '鍚�', value: 0 }
+                ]"
+                clearable
+              />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="鍒犻櫎" label-width="auto" path="del" class="pr-24px">
+              <NSelect
+                v-model:value="model.del"
+                placeholder="璇烽�夋嫨鍒犻櫎"
+                :options="[
+                  { label: '鏄�', value: '1' },
+                  { label: '鍚�', value: '0' }
+                ]"
+                clearable
+              />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="mes缂栫爜" label-width="auto" path="mesCode" class="pr-24px">
+              <NInput v-model:value="model.mesCode" placeholder="璇疯緭鍏es缂栫爜" />
+            </NFormItemGi>
+            <NFormItemGi :show-feedback="false" span="24" class="pr-24px">
+              <NSpace class="w-full" justify="end">
+                <NButton @click="reset">
+                  <template #icon>
+                    <icon-ic-round-refresh class="text-icon" />
+                  </template>
+                  {{ $t('common.reset') }}
+                </NButton>
+                <NButton type="primary" ghost @click="search">
+                  <template #icon>
+                    <icon-ic-round-search class="text-icon" />
+                  </template>
+                  {{ $t('common.search') }}
+                </NButton>
+              </NSpace>
+            </NFormItemGi>
+          </NGrid>
+        </NForm>
+      </NCollapseItem>
+    </NCollapse>
+  </NCard>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/md/mat/index.vue b/ruoyi-plus-soybean/src/views/md/mat/index.vue
new file mode 100644
index 0000000..b292a2e
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/md/mat/index.vue
@@ -0,0 +1,283 @@
+<script setup lang="tsx">
+import { onMounted, ref } from 'vue';
+import { NDivider } from 'naive-ui';
+import { fetchBatchDeleteMat, fetchGetMatList } from '@/service/api/md/mat';
+import { fetchGetMatTypeList } from '@/service/api/md/mat-type';
+import { useAppStore } from '@/store/modules/app';
+import { useAuth } from '@/hooks/business/auth';
+import { useDownload } from '@/hooks/business/download';
+import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
+import { $t } from '@/locales';
+import ButtonIcon from '@/components/custom/button-icon.vue';
+import MatOperateDrawer from './modules/mat-operate-drawer.vue';
+import MatSearch from './modules/mat-search.vue';
+
+defineOptions({
+  name: 'MatList'
+});
+
+
+const appStore = useAppStore();
+const { download } = useDownload();
+const { hasAuth } = useAuth();
+
+const matTypeOptions = ref<CommonType.Option[]>([]);
+
+async function getMatTypeOptions() {
+  const { data: typeData } = await fetchGetMatTypeList();
+  if (typeData) {
+    matTypeOptions.value = typeData.rows.map(item => ({
+      label: item.name,
+      value: item.code
+    }));
+  }
+}
+
+onMounted(() => {
+  getMatTypeOptions();
+});
+
+const searchParams = ref<Api.Md.MatSearchParams>({
+  pageNum: 1,
+  pageSize: 10,
+  code: null,
+  name: null,
+  simpleName: null,
+  enable: 1,
+  del: '0',
+  tid: null,
+  params: {}
+});
+
+const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
+  useNaivePaginatedTable({
+  api: () => fetchGetMatList(searchParams.value),
+  transform: response => defaultTransform(response),
+  onPaginationParamsChange: params => {
+    searchParams.value.pageNum = params.page;
+    searchParams.value.pageSize = params.pageSize;
+  },
+  columns: () => [
+    {
+      type: 'selection',
+      align: 'center',
+      width: 48
+    },
+    {
+      key: 'index',
+      title: $t('common.index'),
+      align: 'center',
+      width: 64,
+      render: (_, index) => index + 1
+    },
+    {
+      key: 'code',
+      title: '鐗╂枡浠g爜',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'name',
+      title: '鍏ㄧО',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'simpleName',
+      title: '绠�绉�',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'des',
+      title: '鎻忚堪',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'uid',
+      title: '鍗曚綅',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'lastUpdateTime',
+      title: '鏈�鍚庢洿鏂版椂闂�',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'enable',
+      title: '鍚敤',
+      align: 'center',
+      minWidth: 120,
+      render: row => (row.enable === 1 ? '鏄�' : '鍚�')
+    },
+    {
+      key: 'del',
+      title: '鍒犻櫎',
+      align: 'center',
+      minWidth: 120,
+      render: row => (row.del === '1' ? '鏄�' : '鍚�')
+    },
+    {
+      key: 'tid',
+      title: '鐗╂枡绫诲瀷',
+      align: 'center',
+      minWidth: 120,
+      render: row => {
+        if (row.tid) {
+          return matTypeOptions.value.find(item => String(item.value) === String(row.tid))?.label || row.tid;
+        }
+        return '';
+      }
+    },
+    {
+      key: 'createUserName',
+      title: '鍒涘缓浜�',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'createUserTime',
+      title: '鍒涘缓鏃堕棿',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'updateUserName',
+      title: '鏇存柊浜�',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'updateUserTime',
+      title: '鏇存柊鏃堕棿',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'operate',
+      title: $t('common.operate'),
+      align: 'center',
+      fixed: 'right',
+      width: 130,
+      render: row => {
+        const divider = () => {
+          if (!hasAuth('md:mat:edit') || !hasAuth('md:mat:remove')) {
+            return null;
+          }
+          return <NDivider vertical />;
+        };
+
+        const editBtn = () => {
+          if (!hasAuth('md:mat:edit')) {
+            return null;
+          }
+          return (
+            <ButtonIcon
+              text
+              type="primary"
+              icon="material-symbols:drive-file-rename-outline-outline"
+              tooltipContent={$t('common.edit')}
+              onClick={() => edit(row.id)}
+            />
+          );
+        };
+
+        const deleteBtn = () => {
+          if (!hasAuth('md:mat:remove')) {
+            return null;
+          }
+          return (
+            <ButtonIcon
+              text
+              type="error"
+              icon="material-symbols:delete-outline"
+              tooltipContent={$t('common.delete')}
+              popconfirmContent={$t('common.confirmDelete')}
+              onPositiveClick={() => handleDelete(row.id)}
+            />
+          );
+        };
+
+        return (
+          <div class="flex-center gap-8px">
+            {editBtn()}
+            {divider()}
+            {deleteBtn()}
+          </div>
+        );
+      }
+    }
+  ]
+});
+
+const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
+  useTableOperate(data, 'id', getData);
+
+async function handleBatchDelete() {
+  // request
+  const { error } = await fetchBatchDeleteMat(checkedRowKeys.value);
+  if (error) return;
+  onBatchDeleted();
+}
+
+async function handleDelete(id: CommonType.IdType) {
+  // request
+  const { error } = await fetchBatchDeleteMat([id]);
+  if (error) return;
+  onDeleted();
+}
+
+function edit(id: CommonType.IdType) {
+  handleEdit(id);
+}
+
+function handleExport() {
+  download('/md/mat/export', searchParams.value, `鐗╂枡_${new Date().getTime()}.xlsx`);
+}
+</script>
+
+<template>
+  <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
+    <MatSearch v-model:model="searchParams" @search="getDataByPage" />
+    <NCard title="鐗╂枡鍒楄〃" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
+      <template #header-extra>
+        <TableHeaderOperation
+          v-model:columns="columnChecks"
+          :disabled-delete="checkedRowKeys.length === 0"
+          :loading="loading"
+          :show-add="hasAuth('md:mat:add')"
+          :show-delete="hasAuth('md:mat:remove')"
+          :show-export="hasAuth('md:mat:export')"
+          @add="handleAdd"
+          @delete="handleBatchDelete"
+          @export="handleExport"
+          @refresh="getData"
+        />
+      </template>
+      <NDataTable
+        v-model:checked-row-keys="checkedRowKeys"
+        :columns="columns"
+        :data="data"
+        size="small"
+        :flex-height="!appStore.isMobile"
+        :scroll-x="scrollX"
+        :loading="loading"
+        remote
+        :row-key="row => row.id"
+        :pagination="mobilePagination"
+        class="sm:h-full"
+      />
+      <MatOperateDrawer
+        v-model:visible="drawerVisible"
+        :operate-type="operateType"
+        :row-data="editingData"
+        @submitted="getDataByPage"
+      />
+    </NCard>
+  </div>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/md/mat/modules/mat-operate-drawer.vue b/ruoyi-plus-soybean/src/views/md/mat/modules/mat-operate-drawer.vue
new file mode 100644
index 0000000..4977e2b
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/md/mat/modules/mat-operate-drawer.vue
@@ -0,0 +1,184 @@
+<script setup lang="ts">
+import { computed, ref, watch } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { fetchCreateMat, fetchUpdateMat } from '@/service/api/md/mat';
+import { useFormRules, useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+  name: 'MatOperateDrawer'
+});
+
+interface Props {
+  /** the type of operation */
+  operateType: NaiveUI.TableOperateType;
+  /** the edit row data */
+  rowData?: Api.Md.Mat | null;
+}
+
+const props = defineProps<Props>();
+
+interface Emits {
+  (e: 'submitted'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const visible = defineModel<boolean>('visible', {
+  default: false
+});
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+const { createRequiredRule } = useFormRules();
+
+const title = computed(() => {
+  const titles: Record<NaiveUI.TableOperateType, string> = {
+    add: '鏂板鐗╂枡',
+    edit: '缂栬緫鐗╂枡'
+  };
+  return titles[props.operateType];
+});
+
+type Model = Api.Md.MatOperateParams;
+
+const model = ref<Model>(createDefaultModel());
+
+function createDefaultModel(): Model {
+  return {
+      id: '',
+      code: '',
+      name: '',
+      simpleName: '',
+      des: '',
+      uid: '',
+      lastUpdateTime: null,
+      enable: null,
+      del: '',
+      tid: '',
+      createUserName: '',
+      createUserTime: null,
+      updateUserName: '',
+      updateUserTime: null
+  };
+}
+
+type RuleKey = Extract<
+  keyof Model,
+  | 'id'
+>;
+
+const rules: Record<RuleKey, App.Global.FormRule> = {
+  id: createRequiredRule('id涓嶈兘涓虹┖'),
+};
+
+function handleUpdateModelWhenEdit() {
+  model.value = createDefaultModel();
+
+  if (props.operateType === 'edit' && props.rowData) {
+    Object.assign(model.value, jsonClone(props.rowData));
+  }
+}
+
+function closeDrawer() {
+  visible.value = false;
+}
+
+async function handleSubmit() {
+  await validate();
+
+  const { id, code, name, simpleName, des, uid, lastUpdateTime, enable, del, tid, createUserName, createUserTime, updateUserName, updateUserTime } = model.value;
+
+  // request
+  if (props.operateType === 'add') {
+    const { error } = await fetchCreateMat({ code, name, simpleName, des, uid, lastUpdateTime, enable, del, tid, createUserName, createUserTime, updateUserName, updateUserTime });
+    if (error) return;
+  }
+
+  if (props.operateType === 'edit') {
+    const { error } = await fetchUpdateMat({ id, code, name, simpleName, des, uid, lastUpdateTime, enable, del, tid, createUserName, createUserTime, updateUserName, updateUserTime });
+    if (error) return;
+  }
+
+  window.$message?.success($t('common.updateSuccess'));
+  closeDrawer();
+  emit('submitted');
+}
+
+watch(visible, () => {
+  if (visible.value) {
+    handleUpdateModelWhenEdit();
+    restoreValidation();
+  }
+});
+</script>
+
+<template>
+  <NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
+    <NDrawerContent :title="title" :native-scrollbar="false" closable>
+      <NForm ref="formRef" :model="model" :rules="rules">
+        <NFormItem label="鐗╂枡浠g爜" path="code">
+          <NInput v-model:value="model.code" placeholder="璇疯緭鍏ョ墿鏂欎唬鐮�" />
+        </NFormItem>
+        <NFormItem label="鍏ㄧО" path="name">
+          <NInput v-model:value="model.name" placeholder="璇疯緭鍏ュ叏绉�" />
+        </NFormItem>
+        <NFormItem label="绠�绉�" path="simpleName">
+          <NInput v-model:value="model.simpleName" placeholder="璇疯緭鍏ョ畝绉�" />
+        </NFormItem>
+        <NFormItem label="鎻忚堪" path="des">
+          <NInput v-model:value="model.des" placeholder="璇疯緭鍏ユ弿杩�" />
+        </NFormItem>
+        <NFormItem label="鍗曚綅" path="uid">
+          <NInput v-model:value="model.uid" placeholder="璇疯緭鍏ュ崟浣�" />
+        </NFormItem>
+        <NFormItem label="鏈�鍚庢洿鏂版椂闂�" path="lastUpdateTime">
+          <NDatePicker
+            v-model:formatted-value="model.lastUpdateTime"
+            type="datetime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            clearable
+          />
+        </NFormItem>
+        <NFormItem label="鍚敤" path="enable">
+          <NInput v-model:value="model.enable" placeholder="璇疯緭鍏ュ惎鐢�" />
+        </NFormItem>
+        <NFormItem label="鍒犻櫎" path="del">
+          <NInput v-model:value="model.del" placeholder="璇疯緭鍏ュ垹闄�" />
+        </NFormItem>
+        <NFormItem label="鐗╂枡绫诲瀷" path="tid">
+          <NInput v-model:value="model.tid" placeholder="璇疯緭鍏ョ墿鏂欑被鍨�" />
+        </NFormItem>
+        <NFormItem label="鍒涘缓浜�" path="createUserName">
+          <NInput v-model:value="model.createUserName" placeholder="璇疯緭鍏ュ垱寤轰汉" />
+        </NFormItem>
+        <NFormItem label="鍒涘缓鏃堕棿" path="createUserTime">
+          <NDatePicker
+            v-model:formatted-value="model.createUserTime"
+            type="datetime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            clearable
+          />
+        </NFormItem>
+        <NFormItem label="鏇存柊浜�" path="updateUserName">
+          <NInput v-model:value="model.updateUserName" placeholder="璇疯緭鍏ユ洿鏂颁汉" />
+        </NFormItem>
+        <NFormItem label="鏇存柊鏃堕棿" path="updateUserTime">
+          <NDatePicker
+            v-model:formatted-value="model.updateUserTime"
+            type="datetime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            clearable
+          />
+        </NFormItem>
+      </NForm>
+      <template #footer>
+        <NSpace :size="16">
+          <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
+          <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
+        </NSpace>
+      </template>
+    </NDrawerContent>
+  </NDrawer>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/md/mat/modules/mat-search.vue b/ruoyi-plus-soybean/src/views/md/mat/modules/mat-search.vue
new file mode 100644
index 0000000..36f9d22
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/md/mat/modules/mat-search.vue
@@ -0,0 +1,119 @@
+<script setup lang="ts">
+import { onMounted, ref, toRaw } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { fetchGetMatTypeList } from '@/service/api/md/mat-type';
+import { useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+  name: 'MatSearch'
+});
+
+interface Emits {
+  (e: 'search'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+
+const model = defineModel<Api.Md.MatSearchParams>('model', { required: true });
+
+const defaultModel = jsonClone(toRaw(model.value));
+
+const matTypeOptions = ref<CommonType.Option[]>([]);
+
+async function getMatTypeOptions() {
+  const { data } = await fetchGetMatTypeList();
+  if (data) {
+    matTypeOptions.value = data.rows.map(item => ({
+      label: item.name,
+      value: item.code
+    }));
+  }
+}
+
+onMounted(() => {
+  getMatTypeOptions();
+});
+
+function resetModel() {
+  Object.assign(model.value, defaultModel);
+}
+
+async function reset() {
+  await restoreValidation();
+  resetModel();
+  emit('search');
+}
+
+async function search() {
+  await validate();
+  emit('search');
+}
+</script>
+
+<template>
+  <NCard :bordered="false" size="small" class="card-wrapper">
+    <NCollapse>
+      <NCollapseItem :title="$t('common.search')" name="md-mat-search">
+        <NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
+          <NGrid responsive="screen" item-responsive>
+            <NFormItemGi span="24 s:12 m:6" label="鐗╂枡浠g爜" label-width="auto" path="code" class="pr-24px">
+              <NInput v-model:value="model.code" placeholder="璇疯緭鍏ョ墿鏂欎唬鐮�" />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="鍏ㄧО" label-width="auto" path="name" class="pr-24px">
+              <NInput v-model:value="model.name" placeholder="璇疯緭鍏ュ叏绉�" />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="绠�绉�" label-width="auto" path="simpleName" class="pr-24px">
+              <NInput v-model:value="model.simpleName" placeholder="璇疯緭鍏ョ畝绉�" />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="鍚敤" label-width="auto" path="enable" class="pr-24px">
+              <NSelect
+                v-model:value="model.enable"
+                placeholder="璇烽�夋嫨鍚敤"
+                :options="[
+                  { label: '鏄�', value: 1 },
+                  { label: '鍚�', value: 0 }
+                ]"
+                clearable
+              />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="鍒犻櫎" label-width="auto" path="del" class="pr-24px">
+              <NSelect
+                v-model:value="model.del"
+                placeholder="璇烽�夋嫨鍒犻櫎"
+                :options="[
+                  { label: '鏄�', value: '1' },
+                  { label: '鍚�', value: '0' }
+                ]"
+                clearable
+              />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="鐗╂枡绫诲瀷" label-width="auto" path="tid" class="pr-24px">
+              <NSelect v-model:value="model.tid" placeholder="璇烽�夋嫨鐗╂枡绫诲瀷" :options="matTypeOptions" clearable />
+            </NFormItemGi>
+            <NFormItemGi :show-feedback="false" span="24" class="pr-24px">
+              <NSpace class="w-full" justify="end">
+                <NButton @click="reset">
+                  <template #icon>
+                    <icon-ic-round-refresh class="text-icon" />
+                  </template>
+                  {{ $t('common.reset') }}
+                </NButton>
+                <NButton type="primary" ghost @click="search">
+                  <template #icon>
+                    <icon-ic-round-search class="text-icon" />
+                  </template>
+                  {{ $t('common.search') }}
+                </NButton>
+              </NSpace>
+            </NFormItemGi>
+          </NGrid>
+        </NForm>
+      </NCollapseItem>
+    </NCollapse>
+  </NCard>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/qm/batch/index.vue b/ruoyi-plus-soybean/src/views/qm/batch/index.vue
index 96d7c52..e25ab9c 100755
--- a/ruoyi-plus-soybean/src/views/qm/batch/index.vue
+++ b/ruoyi-plus-soybean/src/views/qm/batch/index.vue
@@ -1,12 +1,14 @@
 <script setup lang="tsx">
-import { ref } from 'vue';
-import { NDivider } from 'naive-ui';
-import { fetchBatchDeleteBatch, fetchGetBatchList } from '@/service/api/qm/batch';
-import { useAppStore } from '@/store/modules/app';
-import { useAuth } from '@/hooks/business/auth';
-import { useDownload } from '@/hooks/business/download';
-import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
-import { $t } from '@/locales';
+import {nextTick, ref} from 'vue';
+import {useRouter} from 'vue-router';
+import {NDivider, NDropdown} from 'naive-ui';
+import {fetchBatchDeleteBatch, fetchGetBatchList} from '@/service/api/qm/batch';
+import {useAppStore} from '@/store/modules/app';
+import {useAuth} from '@/hooks/business/auth';
+import {useDownload} from '@/hooks/business/download';
+import {useSvgIcon} from '@/hooks/common/icon';
+import {defaultTransform, useNaivePaginatedTable, useTableOperate} from '@/hooks/common/table';
+import {$t} from '@/locales';
 import ButtonIcon from '@/components/custom/button-icon.vue';
 import BatchOperateDrawer from './modules/batch-operate-drawer.vue';
 import BatchSearch from './modules/batch-search.vue';
@@ -16,18 +18,145 @@
 });
 
 const appStore = useAppStore();
-const { download } = useDownload();
-const { hasAuth } = useAuth();
+const router = useRouter();
+const {download} = useDownload();
+const {hasAuth} = useAuth();
+const {SvgIconVNode} = useSvgIcon();
+
+// 鍙抽敭鑿滃崟鐩稿叧
+const showDropdown = ref(false);
+const x = ref(0);
+const y = ref(0);
+const currentRow = ref<Api.Qm.Batch | null>(null);
+
+const dropdownOptions = [
+  {
+    label: '鍘熷鏁版嵁缁存姢',
+    key: 'raw-data-maintenance',
+    icon: SvgIconVNode({icon: 'mdi:database-edit-outline', fontSize: 18})
+  },
+  {
+    label: '缁煎悎娴嬭瘯鍙版暟鎹淮鎶�',
+    key: 'test-bench-maintenance',
+    icon: SvgIconVNode({icon: 'mdi:monitor-dashboard', fontSize: 18})
+  },
+  {
+    label: '鏂板缓澶嶆鎵规',
+    key: 'new-recheck-batch',
+    icon: SvgIconVNode({icon: 'mdi:plus-circle-outline', fontSize: 18})
+  },
+  {
+    type: 'divider',
+    key: 'd1'
+  },
+  {
+    label: '鍗峰寘鍗峰埗妫�楠岀粨鏋滄姤鍛�',
+    key: 'report-rolling',
+    icon: SvgIconVNode({icon: 'mdi:file-document-outline', fontSize: 18})
+  },
+  {
+    label: '鍖呰鏍囪瘑妫�楠屽師濮嬭褰�',
+    key: 'record-packaging',
+    icon: SvgIconVNode({icon: 'mdi:barcode-scan', fontSize: 18})
+  },
+  {
+    label: '鐔勭伀銆佸惈姘寸巼銆佸惈鏈巼鍘熷璁板綍',
+    key: 'record-quality',
+    icon: SvgIconVNode({icon: 'mdi:water-percent', fontSize: 18})
+  },
+  {
+    label: '绔儴钀戒笣鍘熷璁板綍',
+    key: 'record-silk',
+    icon: SvgIconVNode({icon: 'mdi:format-list-bulleted-type', fontSize: 18})
+  },
+  {
+    label: '缁煎悎娴嬭瘯鍙板師濮嬭褰�',
+    key: 'record-bench',
+    icon: SvgIconVNode({icon: 'mdi:chart-line', fontSize: 18})
+  },
+  {
+    label: '澶栬妫�楠屽師濮嬭褰�',
+    key: 'record-appearance',
+    icon: SvgIconVNode({icon: 'mdi:eye-outline', fontSize: 18})
+  },
+  {
+    type: 'divider',
+    key: 'd2'
+  },
+  {
+    label: $t('common.edit'),
+    key: 'edit',
+    icon: SvgIconVNode({icon: 'material-symbols:drive-file-rename-outline-outline', fontSize: 18}),
+    show: hasAuth('qm:batch:edit')
+  },
+  {
+    label: $t('common.delete'),
+    key: 'delete',
+    icon: SvgIconVNode({icon: 'material-symbols:delete-outline', fontSize: 18}),
+    show: hasAuth('qm:batch:remove')
+  }
+];
+
+function handleSelect(key: string) {
+  showDropdown.value = false;
+  if (!currentRow.value) return;
+
+  if (key === 'edit') {
+    edit(currentRow.value.id);
+  } else if (key === 'delete') {
+    window.$dialog?.error({
+      title: $t('common.confirmDelete'),
+      content: $t('common.confirmDelete'),
+      positiveText: $t('common.confirm'),
+      negativeText: $t('common.cancel'),
+      onPositiveClick: () => {
+        handleDelete(currentRow.value!.id);
+      }
+    });
+  } else if (key === 'raw-data-maintenance') {
+    // 璺宠浆鍒� matcheck 椤甸潰
+    if (!currentRow.value.judgeCode) {
+      window.$message?.warning('璇ユ壒娆℃病鏈夊垽瀹氫緷鎹�');
+      return;
+    }
+    router.push({
+      path: '/qm/matcheck',
+      query: {
+        judgeCode: currentRow.value.judgeCode,
+        batchCode: currentRow.value.batchCode,
+        matCode: currentRow.value.matCode
+      }
+    });
+  } else {
+    // 澶勭悊鍏朵粬涓氬姟鎿嶄綔
+    window.$message?.info(`鐐瑰嚮浜�: ${key}`);
+  }
+}
+
+function handleRowProps(row: Api.Qm.Batch) {
+  return {
+    onContextmenu: (e: MouseEvent) => {
+      e.preventDefault();
+      showDropdown.value = false;
+      nextTick().then(() => {
+        currentRow.value = row;
+        x.value = e.clientX;
+        y.value = e.clientY;
+        showDropdown.value = true;
+      });
+    }
+  };
+}
 
 // 绫诲瀷/鍙嶉MES/绫诲埆鐨� value->label 鏄犲皠锛堢敤浜庤〃鏍兼樉绀猴級
-const TYP_MAP: Record<string, string> = { A: '鍒朵笣', B: '鎴愬瀷', C: '鍗峰寘', D: '灏佺', E: '绯栭鏂�' };
-const FLAG_MAP: Record<string, string> = { '0': '鏈笂浼爉es', '1': '宸蹭笂浼�', '3': '浠嶮ES涓嬭浇' };
-const CATEGORY_MAP: Record<string, string> = { '0': '鎴愬搧', '1': '杈呮潗' };
+const FLAG_MAP: Record<string, string> = {'0': '鏈笂浼爉es', '1': '宸蹭笂浼�', '3': '浠嶮ES涓嬭浇'};
+const CATEGORY_MAP: Record<string, string> = {'0': '鎴愬搧', '1': '杈呮潗'};
 
 const searchParams = ref<Api.Qm.BatchSearchParams>({
   pageNum: 1,
   pageSize: 10,
   batchCode: null,
+  isflag: '1',
   typ: null,
   eqpCode: null,
   matCode: null,
@@ -35,13 +164,17 @@
   flag: null,
   toMesDate: null,
   fromMesDate: null,
-  deleted: null,
-  category: null,
+  enabled: '1',
+  deleted: 0,
+  category: '0',
   state: null,
-  params: {}
+  params: {
+    beginBatchDate: `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, '0')}-${String(new Date().getDate()).padStart(2, '0')} 00:00:00`,
+    endBatchDate: `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, '0')}-${String(new Date().getDate()).padStart(2, '0')} 23:59:59`
+  }
 });
 
-const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
+const {columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX} =
   useNaivePaginatedTable({
     api: () => fetchGetBatchList(searchParams.value),
     transform: response => defaultTransform(response),
@@ -63,45 +196,20 @@
         render: (_, index) => index + 1
       },
       {
-        key: 'id',
-        title: '缂栫爜',
-        align: 'center',
-        minWidth: 120
-      },
-      {
         key: 'batchCode',
-        title: '鎵规浠g爜',
+        title: '鎵规鍙�',
         align: 'center',
         minWidth: 120
       },
       {
-        key: 'batchName',
-        title: '鎵规鍚嶇О',
-        align: 'center',
-        minWidth: 120
-      },
-      {
-        key: 'typ',
-        title: '绫诲瀷',
-        align: 'center',
-        minWidth: 120,
-        render: row => TYP_MAP[row.typ] ?? row.typ
-      },
-      {
-        key: 'eqpCode',
-        title: '鏈哄彴浠g爜',
-        align: 'center',
-        minWidth: 120
-      },
-      {
-        key: 'matCode',
+        key: 'matName',
         title: '鐗屽彿',
         align: 'center',
         minWidth: 120
       },
       {
-        key: 'judgeCode',
-        title: '鍒ゅ畾渚濇嵁浠g爜',
+        key: 'judgeName',
+        title: '鍒ゅ畾渚濇嵁',
         align: 'center',
         minWidth: 120
       },
@@ -115,13 +223,15 @@
         key: 'isflag',
         title: '浣跨敤鏍囧織',
         align: 'center',
-        minWidth: 120
+        minWidth: 120,
+        render: row => (row.isflag == '1' ? '鏄�' : '鍚�')
       },
       {
         key: 'enabled',
         title: '鍚敤鏍囧織',
         align: 'center',
-        minWidth: 120
+        minWidth: 120,
+        render: row => (row.enabled == '1' ? '鏄�' : '鍚�')
       },
       {
         key: 'totalNum',
@@ -200,7 +310,8 @@
         key: 'deleted',
         title: '鍒犻櫎鏍囧織',
         align: 'center',
-        minWidth: 120
+        minWidth: 120,
+        render: row => (row.deleted == 1 ? '鏄�' : '鍚�')
       },
       {
         key: 'batchDes',
@@ -350,6 +461,7 @@
       {
         key: 'operate',
         title: $t('common.operate'),
+        fixed: 'right',
         align: 'center',
         width: 130,
         render: row => {
@@ -357,7 +469,7 @@
             if (!hasAuth('qm:batch:edit') || !hasAuth('qm:batch:remove')) {
               return null;
             }
-            return <NDivider vertical />;
+            return <NDivider vertical/>;
           };
 
           const editBtn = () => {
@@ -403,19 +515,19 @@
     ]
   });
 
-const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
+const {drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted} =
   useTableOperate(data, 'id', getData);
 
 async function handleBatchDelete() {
   // request
-  const { error } = await fetchBatchDeleteBatch(checkedRowKeys.value);
+  const {error} = await fetchBatchDeleteBatch(checkedRowKeys.value);
   if (error) return;
   onBatchDeleted();
 }
 
 async function handleDelete(id: CommonType.IdType) {
   // request
-  const { error } = await fetchBatchDeleteBatch([id]);
+  const {error} = await fetchBatchDeleteBatch([id]);
   if (error) return;
   onDeleted();
 }
@@ -431,7 +543,7 @@
 
 <template>
   <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
-    <BatchSearch v-model:model="searchParams" @search="getDataByPage" />
+    <BatchSearch v-model:model="searchParams" @search="getDataByPage"/>
     <NCard title="妫�楠屾壒娆″垪琛�" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
       <template #header-extra>
         <TableHeaderOperation
@@ -458,8 +570,19 @@
         remote
         :row-key="row => row.id"
         :pagination="mobilePagination"
+        :row-props="handleRowProps"
         class="sm:h-full"
       />
+      <NDropdown
+        placement="bottom-start"
+        trigger="manual"
+        :x="x"
+        :y="y"
+        :options="dropdownOptions"
+        :show="showDropdown"
+        :on-clickoutside="() => (showDropdown = false)"
+        @select="handleSelect"
+      />
       <BatchOperateDrawer
         v-model:visible="drawerVisible"
         :operate-type="operateType"
diff --git a/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-operate-drawer.vue b/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-operate-drawer.vue
index bccc726..2af78f4 100755
--- a/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-operate-drawer.vue
+++ b/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-operate-drawer.vue
@@ -1,7 +1,9 @@
 <script setup lang="ts">
-import { computed, ref, watch } from 'vue';
+import { computed, onMounted, ref, watch } from 'vue';
 import { jsonClone } from '@sa/utils';
 import { fetchCreateBatch, fetchUpdateBatch } from '@/service/api/qm/batch';
+import { fetchGetMatList } from '@/service/api/md/mat';
+import { fetchGetJudgeList } from '@/service/api/qm/judge';
 import { useFormRules, useNaiveForm } from '@/hooks/common/form';
 import { $t } from '@/locales';
 
@@ -31,27 +33,41 @@
 const { formRef, validate, restoreValidation } = useNaiveForm();
 const { createRequiredRule } = useFormRules();
 
-// 绫诲瀷閫夐」锛欰-鍒朵笣 B-鎴愬瀷 C-鍗峰寘 D-灏佺 E-绯栭鏂�
-const typOptions = [
-  { label: '鍒朵笣', value: 'A' },
-  { label: '鎴愬瀷', value: 'B' },
-  { label: '鍗峰寘', value: 'C' },
-  { label: '灏佺', value: 'D' },
-  { label: '绯栭鏂�', value: 'E' }
+const matOptions = ref<CommonType.Option[]>([]);
+const judgeOptions = ref<CommonType.Option[]>([]);
+const stateOptions = [
+  { label: '姝e父', value: '0' },
+  { label: '鍋滅敤', value: '1' }
 ];
 
-// 鍙嶉MES閫夐」锛�0-鏈笂浼爉es 1-宸蹭笂浼� 3-浠嶮ES涓嬭浇
-const flagOptions = [
-  { label: '鏈笂浼爉es', value: '0' },
-  { label: '宸蹭笂浼�', value: '1' },
-  { label: '浠嶮ES涓嬭浇', value: '3' }
-];
+async function getMatOptions() {
+  const { data, error } = await fetchGetMatList({ tid: '1' as any, pageSize: 1000 });
+  if (!error) {
+    matOptions.value = data.rows.map(item => ({
+      label: item.name,
+      value: item.code
+    }));
+  }
+}
 
-// 绫诲埆閫夐」锛�0-鎴愬搧 1-杈呮潗
-const categoryOptions = [
-  { label: '鎴愬搧', value: '0' },
-  { label: '杈呮潗', value: '1' }
-];
+async function getJudgeOptions(matCode?: string | null) {
+  if (!matCode) {
+    judgeOptions.value = [];
+    return;
+  }
+  const params: Api.Qm.JudgeSearchParams = { category: 0, pageSize: 1000, matCode };
+  const { data, error } = await fetchGetJudgeList(params);
+  if (!error) {
+    judgeOptions.value = data.rows.map(item => ({
+      label: item.judgeName,
+      value: String(item.id)
+    })) as CommonType.Option[];
+  }
+}
+
+onMounted(() => {
+  getMatOptions();
+});
 
 const title = computed(() => {
   const titles: Record<NaiveUI.TableOperateType, string> = {
@@ -70,13 +86,13 @@
     id: '',
     batchCode: '',
     batchName: '',
-    typ: '',
+    typ: '0',
     eqpCode: '',
-    matCode: '',
+    matCode: null,
     judgeCode: '',
     batchDate: null,
-    isflag: '',
-    enabled: '',
+    isflag: '0',
+    enabled: '1',
     totalNum: null,
     results: '',
     approver: '',
@@ -86,19 +102,19 @@
     verName: '',
     verCode: '',
     archDate: '',
-    flag: '',
+    flag: '0',
     toMesDate: null,
     fromMesDate: null,
-    deleted: null,
+    deleted: 0,
     batchDes: '',
-    category: '',
+    category: '0',
     makeno: '',
     shifteqpno: '',
     boxno: '',
     pid: '',
     reviewer: '',
     rvcount: null,
-    state: '',
+    state: '0',
     reviewTime: null,
     auditTime: null,
     spec: '',
@@ -117,10 +133,11 @@
   };
 }
 
-type RuleKey = Extract<keyof Model, 'id'>;
+type RuleKey = Extract<keyof Model, 'batchCode' | 'matCode'>;
 
 const rules: Record<RuleKey, App.Global.FormRule> = {
-  id: createRequiredRule('缂栫爜涓嶈兘涓虹┖')
+  batchCode: createRequiredRule('鎵规鍙蜂笉鑳戒负绌�'),
+  matCode: createRequiredRule('鐗屽彿涓嶈兘涓虹┖')
 };
 
 function handleUpdateModelWhenEdit() {
@@ -303,201 +320,54 @@
   if (visible.value) {
     handleUpdateModelWhenEdit();
     restoreValidation();
+    getJudgeOptions(model.value.matCode);
   }
 });
+
+watch(
+  () => model.value.matCode,
+  newVal => {
+    if (visible.value) {
+      model.value.judgeCode = '';
+      getJudgeOptions(newVal);
+    }
+  }
+);
 </script>
 
 <template>
   <NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
     <NDrawerContent :title="title" :native-scrollbar="false" closable>
-      <NForm ref="formRef" :model="model" :rules="rules">
-        <NFormItem label="鎵规浠g爜" path="batchCode">
-          <NInput v-model:value="model.batchCode" placeholder="璇疯緭鍏ユ壒娆′唬鐮�" />
-        </NFormItem>
-        <NFormItem label="鎵规鍚嶇О" path="batchName">
-          <NInput v-model:value="model.batchName" placeholder="璇疯緭鍏ユ壒娆″悕绉�" />
-        </NFormItem>
-        <NFormItem label="绫诲瀷" path="typ">
-          <NSelect v-model:value="model.typ" :options="typOptions" placeholder="璇烽�夋嫨绫诲瀷" clearable />
-        </NFormItem>
-        <NFormItem label="鏈哄彴浠g爜" path="eqpCode">
-          <NInput v-model:value="model.eqpCode" placeholder="璇疯緭鍏ユ満鍙颁唬鐮�" />
+      <NForm ref="formRef" :model="model" :rules="rules" label-placement="left" :label-width="100">
+        <NFormItem label="鎵规鍙�" path="batchCode">
+          <NInput v-model:value="model.batchCode" placeholder="璇疯緭鍏ユ壒娆″彿" />
         </NFormItem>
         <NFormItem label="鐗屽彿" path="matCode">
-          <NInput v-model:value="model.matCode" placeholder="璇疯緭鍏ョ墝鍙�" />
+          <NSelect v-model:value="model.matCode" :options="matOptions" placeholder="璇烽�夋嫨鐗屽彿" clearable filterable />
         </NFormItem>
-        <NFormItem label="鍒ゅ畾渚濇嵁浠g爜" path="judgeCode">
-          <NInput v-model:value="model.judgeCode" placeholder="璇疯緭鍏ュ垽瀹氫緷鎹唬鐮�" />
-        </NFormItem>
-        <NFormItem label="鎵规鐢熸垚鏃ユ湡" path="batchDate">
-          <NDatePicker
-            v-model:formatted-value="model.batchDate"
-            type="datetime"
-            value-format="yyyy-MM-dd HH:mm:ss"
+        <NFormItem label="鍒ゅ畾渚濇嵁" path="judgeCode">
+          <NSelect
+            v-model:value="model.judgeCode"
+            :options="judgeOptions"
+            placeholder="璇烽�夋嫨鍒ゅ畾渚濇嵁"
             clearable
-          />
-        </NFormItem>
-        <NFormItem label="浣跨敤鏍囧織" path="isflag">
-          <NInput v-model:value="model.isflag" placeholder="璇疯緭鍏ヤ娇鐢ㄦ爣蹇�" />
-        </NFormItem>
-        <NFormItem label="鍚敤鏍囧織" path="enabled">
-          <NInput v-model:value="model.enabled" placeholder="璇疯緭鍏ュ惎鐢ㄦ爣蹇�" />
-        </NFormItem>
-        <NFormItem label="鍒拌揣鎬婚噺" path="totalNum">
-          <NInputNumber v-model:value="model.totalNum" placeholder="璇疯緭鍏ュ埌璐ф�婚噺" class="w-full" />
-        </NFormItem>
-        <NFormItem label="缁煎悎鍒ゅ畾" path="results">
-          <NInput v-model:value="model.results" placeholder="璇疯緭鍏ョ患鍚堝垽瀹�" />
-        </NFormItem>
-        <NFormItem label="鎵瑰噯浜�" path="approver">
-          <NInput v-model:value="model.approver" placeholder="璇疯緭鍏ユ壒鍑嗕汉" />
-        </NFormItem>
-        <NFormItem label="瀹℃牳浜�" path="auditor">
-          <NInput v-model:value="model.auditor" placeholder="璇疯緭鍏ュ鏍镐汉" />
-        </NFormItem>
-        <NFormItem label="鍒涘缓浜�" path="creater">
-          <NInput v-model:value="model.creater" placeholder="璇疯緭鍏ュ垱寤轰汉" />
-        </NFormItem>
-        <NFormItem label="鍒惰〃鏃ユ湡" path="tabDate">
-          <NDatePicker
-            v-model:formatted-value="model.tabDate"
-            type="datetime"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            clearable
-          />
-        </NFormItem>
-        <NFormItem label="鐗堟湰鍚嶇О" path="verName">
-          <NInput v-model:value="model.verName" placeholder="璇疯緭鍏ョ増鏈悕绉�" />
-        </NFormItem>
-        <NFormItem label="鐗堟湰缂栧彿" path="verCode">
-          <NInput v-model:value="model.verCode" placeholder="璇疯緭鍏ョ増鏈紪鍙�" />
-        </NFormItem>
-        <NFormItem label="淇濆瓨鏈�" path="archDate">
-          <NInput v-model:value="model.archDate" placeholder="璇疯緭鍏ヤ繚瀛樻湡" />
-        </NFormItem>
-        <NFormItem label="鍙嶉MES" path="flag">
-          <NSelect v-model:value="model.flag" :options="flagOptions" placeholder="璇烽�夋嫨鍙嶉MES" clearable />
-        </NFormItem>
-        <NFormItem label="涓婁紶MES鏃堕棿" path="toMesDate">
-          <NDatePicker
-            v-model:formatted-value="model.toMesDate"
-            type="datetime"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            clearable
-          />
-        </NFormItem>
-        <NFormItem label="浠嶮ES鏃堕棿涓嬭浇" path="fromMesDate">
-          <NDatePicker
-            v-model:formatted-value="model.fromMesDate"
-            type="datetime"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            clearable
-          />
-        </NFormItem>
-        <NFormItem label="鍒犻櫎鏍囧織" path="deleted">
-          <NInputNumber v-model:value="model.deleted" placeholder="璇疯緭鍏ュ垹闄ゆ爣蹇�" class="w-full" />
-        </NFormItem>
-        <NFormItem label="鎵规鎻忚堪" path="batchDes">
-          <NInput v-model:value="model.batchDes" placeholder="璇疯緭鍏ユ壒娆℃弿杩�" />
-        </NFormItem>
-        <NFormItem label="绫诲埆" path="category">
-          <NSelect v-model:value="model.category" :options="categoryOptions" placeholder="璇烽�夋嫨绫诲埆" clearable />
-        </NFormItem>
-        <NFormItem label="鍗峰埗宸ュ彿" path="makeno">
-          <NInput v-model:value="model.makeno" placeholder="璇疯緭鍏ュ嵎鍒跺伐鍙�" />
-        </NFormItem>
-        <NFormItem label="鐝鏈哄彿" path="shifteqpno">
-          <NInput v-model:value="model.shifteqpno" placeholder="璇疯緭鍏ョ彮娆℃満鍙�" />
-        </NFormItem>
-        <NFormItem label="瑁呯鍙�" path="boxno">
-          <NInput v-model:value="model.boxno" placeholder="璇疯緭鍏ヨ绠卞彿" />
-        </NFormItem>
-        <NFormItem label="鐖舵壒娆″彿" path="pid">
-          <NInput v-model:value="model.pid as any" placeholder="璇疯緭鍏ョ埗鎵规鍙�" />
-        </NFormItem>
-        <NFormItem label="澶嶆牳浜�" path="reviewer">
-          <NInput v-model:value="model.reviewer" placeholder="璇疯緭鍏ュ鏍镐汉" />
-        </NFormItem>
-        <NFormItem label="澶嶆娆℃暟" path="rvcount">
-          <NInputNumber v-model:value="model.rvcount" placeholder="璇疯緭鍏ュ妫�娆℃暟" class="w-full" />
-        </NFormItem>
-        <NFormItem label="鎵规鐘舵��" path="state">
-          <NInput v-model:value="model.state" placeholder="璇疯緭鍏ユ壒娆$姸鎬�" />
-        </NFormItem>
-        <NFormItem label="澶嶆牳鏃ユ湡" path="reviewTime">
-          <NDatePicker
-            v-model:formatted-value="model.reviewTime"
-            type="datetime"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            clearable
-          />
-        </NFormItem>
-        <NFormItem label="瀹℃牳鏃ユ湡" path="auditTime">
-          <NDatePicker
-            v-model:formatted-value="model.auditTime"
-            type="datetime"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            clearable
+            filterable
           />
         </NFormItem>
         <NFormItem label="瑙勬牸" path="spec">
           <NInput v-model:value="model.spec" placeholder="璇疯緭鍏ヨ鏍�" />
         </NFormItem>
-        <NFormItem label="鎵瑰噯鏃堕棿" path="approveTime">
-          <NDatePicker
-            v-model:formatted-value="model.approveTime"
-            type="datetime"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            clearable
-          />
+        <NFormItem label="瑁呯鍙�" path="boxno">
+          <NInput v-model:value="model.boxno" placeholder="璇疯緭鍏ヨ绠卞彿" />
         </NFormItem>
-        <NFormItem label="鍒拌揣鍗曚綅" path="unit">
-          <NInput v-model:value="model.unit" placeholder="璇疯緭鍏ュ埌璐у崟浣�" />
+        <NFormItem label="鐝鏈哄彿" path="shifteqpno">
+          <NInput v-model:value="model.shifteqpno" placeholder="璇疯緭鍏ョ彮娆℃満鍙�" />
         </NFormItem>
-        <NFormItem label="鍒拌揣鏃ユ湡" path="arrivalTime">
-          <NDatePicker
-            v-model:formatted-value="model.arrivalTime"
-            type="datetime"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            clearable
-          />
+        <NFormItem label="鎻忚堪" path="batchDes">
+          <NInput v-model:value="model.batchDes" placeholder="璇疯緭鍏ユ弿杩�" />
         </NFormItem>
-        <NFormItem label="瀛樻斁鍦扮偣" path="storagePlace">
-          <NInput v-model:value="model.storagePlace" placeholder="璇疯緭鍏ュ瓨鏀惧湴鐐�" />
-        </NFormItem>
-        <NFormItem label="妫�楠屽憳" path="checker">
-          <NInput v-model:value="model.checker" placeholder="璇疯緭鍏ユ楠屽憳" />
-        </NFormItem>
-        <NFormItem label="鎺ュ崟鏃ユ湡" path="receiveTime">
-          <NDatePicker
-            v-model:formatted-value="model.receiveTime"
-            type="datetime"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            clearable
-          />
-        </NFormItem>
-        <NFormItem label="鎶ユ鏃ユ湡" path="inspTime">
-          <NDatePicker
-            v-model:formatted-value="model.inspTime"
-            type="datetime"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            clearable
-          />
-        </NFormItem>
-        <NFormItem label="浠撳簱淇濈鍛�" path="storer">
-          <NInput v-model:value="model.storer" placeholder="璇疯緭鍏ヤ粨搴撲繚绠″憳" />
-        </NFormItem>
-        <NFormItem label="鏄惁楠岃瘉" path="isverify">
-          <NInput v-model:value="model.isverify" placeholder="璇疯緭鍏ユ槸鍚﹂獙璇�" />
-        </NFormItem>
-        <NFormItem label="鏄惁妫�楠�" path="ischk">
-          <NInput v-model:value="model.ischk" placeholder="璇疯緭鍏ユ槸鍚︽楠�" />
-        </NFormItem>
-        <NFormItem label="澶囩敤1" path="bak1">
-          <NInput v-model:value="model.bak1" placeholder="璇疯緭鍏ュ鐢�1" />
-        </NFormItem>
-        <NFormItem label="澶囩敤2" path="bak2">
-          <NInput v-model:value="model.bak2" placeholder="璇疯緭鍏ュ鐢�2" />
+        <NFormItem label="鐘舵��" path="state">
+          <NSelect v-model:value="model.state" :options="stateOptions" placeholder="璇烽�夋嫨鐘舵��" clearable />
         </NFormItem>
       </NForm>
       <template #footer>
diff --git a/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-search.vue b/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-search.vue
index 77400be..3397bf9 100755
--- a/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-search.vue
+++ b/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-search.vue
@@ -1,6 +1,7 @@
 <script setup lang="ts">
-import { ref, toRaw } from 'vue';
+import { onMounted, ref, toRaw, watch } from 'vue';
 import { jsonClone } from '@sa/utils';
+import { fetchGetMatList } from '@/service/api/md/mat';
 import { useNaiveForm } from '@/hooks/common/form';
 import { $t } from '@/locales';
 
@@ -16,38 +17,53 @@
 
 const { formRef, validate, restoreValidation } = useNaiveForm();
 
-const dateRangeToMesDate = ref<[string, string] | null>(null);
-const dateRangeFromMesDate = ref<[string, string] | null>(null);
 const model = defineModel<Api.Qm.BatchSearchParams>('model', { required: true });
+
+const dateRangeBatchDate = ref<[string, string] | null>(null);
+
+const matOptions = ref<CommonType.Option[]>([]);
+
+async function getMatOptions() {
+  const { data } = await fetchGetMatList({ tid: '1' as any, pageSize: 1000 });
+  if (data) {
+    matOptions.value = data.rows.map(item => ({
+      label: item.name,
+      value: item.code
+    }));
+  }
+}
+
+onMounted(() => {
+  getMatOptions();
+});
+
+// sync model params to dateRangeBatchDate
+watch(
+  () => model.value.params,
+  val => {
+    if (val?.beginBatchDate && val?.endBatchDate) {
+      dateRangeBatchDate.value = [val.beginBatchDate, val.endBatchDate];
+    } else {
+      dateRangeBatchDate.value = null;
+    }
+  },
+  { immediate: true, deep: true }
+);
 
 const defaultModel = jsonClone(toRaw(model.value));
 
-// 绫诲瀷閫夐」锛欰-鍒朵笣 B-鎴愬瀷 C-鍗峰寘 D-灏佺 E-绯栭鏂�
-const typOptions = [
-  { label: '鍒朵笣', value: 'A' },
-  { label: '鎴愬瀷', value: 'B' },
-  { label: '鍗峰寘', value: 'C' },
-  { label: '灏佺', value: 'D' },
-  { label: '绯栭鏂�', value: 'E' }
-];
-
-// 鍙嶉MES閫夐」锛�0-鏈笂浼爉es 1-宸蹭笂浼� 3-浠嶮ES涓嬭浇
-const flagOptions = [
-  { label: '鏈笂浼爉es', value: '0' },
-  { label: '宸蹭笂浼�', value: '1' },
-  { label: '浠嶮ES涓嬭浇', value: '3' }
-];
-
-// 绫诲埆閫夐」锛�0-鎴愬搧 1-杈呮潗
-const categoryOptions = [
-  { label: '鎴愬搧', value: '0' },
-  { label: '杈呮潗', value: '1' }
-];
+function onDateRangeBatchDateUpdate(value: [string, string] | null) {
+  if (value && value.length === 2) {
+    model.value.params!.beginBatchDate = value[0];
+    model.value.params!.endBatchDate = value[1];
+  } else {
+    model.value.params!.beginBatchDate = undefined;
+    model.value.params!.endBatchDate = undefined;
+  }
+}
 
 function resetModel() {
-  dateRangeToMesDate.value = null;
-  dateRangeFromMesDate.value = null;
-  Object.assign(model.value, defaultModel);
+  Object.assign(model.value, jsonClone(defaultModel));
 }
 
 async function reset() {
@@ -58,14 +74,6 @@
 
 async function search() {
   await validate();
-  if (dateRangeToMesDate.value?.length) {
-    model.value.params!.beginToMesDate = dateRangeToMesDate.value[0];
-    model.value.params!.endToMesDate = dateRangeToMesDate.value[1];
-  }
-  if (dateRangeFromMesDate.value?.length) {
-    model.value.params!.beginFromMesDate = dateRangeFromMesDate.value[0];
-    model.value.params!.endFromMesDate = dateRangeFromMesDate.value[1];
-  }
   emit('search');
 }
 </script>
@@ -74,70 +82,68 @@
   <NCard :bordered="false" size="small" class="card-wrapper">
     <NCollapse>
       <NCollapseItem :title="$t('common.search')" name="qm-batch-search">
-        <NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
+        <NForm ref="formRef" :model="model" label-placement="left" :label-width="110">
           <NGrid responsive="screen" item-responsive>
-            <NFormItemGi span="24 s:12 m:8" label="鎵规浠g爜" label-width="auto" path="batchCode" class="pr-24px">
-              <NInput v-model:value="model.batchCode" placeholder="璇疯緭鍏ユ壒娆′唬鐮�" />
-            </NFormItemGi>
-            <NFormItemGi span="24 s:12 m:8" label="绫诲瀷" label-width="auto" path="typ" class="pr-24px">
-              <NSelect v-model:value="model.typ" :options="typOptions" placeholder="璇烽�夋嫨绫诲瀷" clearable />
-            </NFormItemGi>
-            <NFormItemGi span="24 s:12 m:8" label="鏈哄彴浠g爜" label-width="auto" path="eqpCode" class="pr-24px">
-              <NInput v-model:value="model.eqpCode" placeholder="璇疯緭鍏ユ満鍙颁唬鐮�" />
-            </NFormItemGi>
-            <NFormItemGi span="24 s:12 m:8" label="鐗屽彿" label-width="auto" path="matCode" class="pr-24px">
-              <NInput v-model:value="model.matCode" placeholder="璇疯緭鍏ョ墝鍙�" />
-            </NFormItemGi>
             <NFormItemGi span="24 s:12 m:8" label="鎵规鐢熸垚鏃ユ湡" label-width="auto" path="batchDate" class="pr-24px">
               <NDatePicker
-                v-model:formatted-value="model.batchDate"
-                type="datetime"
-                value-format="yyyy-MM-dd HH:mm:ss"
-                clearable
-              />
-            </NFormItemGi>
-            <NFormItemGi span="24 s:12 m:8" label="鍙嶉MES" label-width="auto" path="flag" class="pr-24px">
-              <NSelect v-model:value="model.flag" :options="flagOptions" placeholder="璇烽�夋嫨鍙嶉MES" clearable />
-            </NFormItemGi>
-            <NFormItemGi span="24 s:12 m:8" label="涓婁紶MES鏃堕棿" label-width="auto" path="toMesDate" class="pr-24px">
-              <NDatePicker
-                v-model:formatted-value="dateRangeToMesDate"
+                v-model:formatted-value="dateRangeBatchDate"
                 type="datetimerange"
                 value-format="yyyy-MM-dd HH:mm:ss"
                 clearable
+                :default-time="['00:00:00', '23:59:59']"
+                @update:formatted-value="onDateRangeBatchDateUpdate"
               />
             </NFormItemGi>
-            <NFormItemGi span="24 s:12 m:8" label="浠嶮ES鏃堕棿涓嬭浇" label-width="auto" path="fromMesDate" class="pr-24px">
-              <NDatePicker
-                v-model:formatted-value="dateRangeFromMesDate"
-                type="datetimerange"
-                value-format="yyyy-MM-dd HH:mm:ss"
+            <NFormItemGi span="24 s:12 m:8" label="鐗屽彿" label-width="auto" path="matCode" class="pr-24px">
+              <NSelect v-model:value="model.matCode" placeholder="璇烽�夋嫨鐗屽彿" :options="matOptions" clearable />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:8" label="浣跨敤鏍囧織" label-width="auto" path="isflag" class="pr-24px">
+              <NSelect
+                v-model:value="model.isflag"
+                placeholder="璇烽�夋嫨浣跨敤鏍囧織"
+                :options="[
+                  { label: '鏄�', value: '1' },
+                  { label: '鍚�', value: '0' }
+                ]"
+                clearable
+              />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:8" label="鍚敤鏍囧織" label-width="auto" path="enabled" class="pr-24px">
+              <NSelect
+                v-model:value="model.enabled"
+                placeholder="璇烽�夋嫨鍚敤鏍囧織"
+                :options="[
+                  { label: '鏄�', value: '1' },
+                  { label: '鍚�', value: '0' }
+                ]"
                 clearable
               />
             </NFormItemGi>
             <NFormItemGi span="24 s:12 m:8" label="鍒犻櫎鏍囧織" label-width="auto" path="deleted" class="pr-24px">
-              <NInputNumber v-model:value="model.deleted" placeholder="璇疯緭鍏ュ垹闄ゆ爣蹇�" class="w-full" />
+              <NSelect
+                v-model:value="model.deleted"
+                placeholder="璇烽�夋嫨鍒犻櫎鏍囧織"
+                :options="[
+                  { label: '鏄�', value: 1 },
+                  { label: '鍚�', value: 0 }
+                ]"
+                clearable
+              />
             </NFormItemGi>
-            <NFormItemGi span="24 s:12 m:8" label="绫诲埆" label-width="auto" path="category" class="pr-24px">
-              <NSelect v-model:value="model.category" :options="categoryOptions" placeholder="璇烽�夋嫨绫诲埆" clearable />
-            </NFormItemGi>
-            <NFormItemGi span="24 s:12 m:8" label="鎵规鐘舵��" label-width="auto" path="state" class="pr-24px">
-              <NInput v-model:value="model.state" placeholder="璇疯緭鍏ユ壒娆$姸鎬�" />
-            </NFormItemGi>
-            <NFormItemGi :show-feedback="false" span="24" class="pr-24px">
-              <NSpace class="w-full" justify="end">
-                <NButton @click="reset">
-                  <template #icon>
-                    <icon-ic-round-refresh class="text-icon" />
-                  </template>
-                  {{ $t('common.reset') }}
-                </NButton>
+            <NFormItemGi :show-feedback="false" span="24 s:12 m:8" class="pr-24px">
+              <NSpace class="w-full" justify="start">
                 <NButton type="primary" ghost @click="search">
                   <template #icon>
                     <icon-ic-round-search class="text-icon" />
                   </template>
                   {{ $t('common.search') }}
                 </NButton>
+                <NButton @click="reset">
+                  <template #icon>
+                    <icon-ic-round-refresh class="text-icon" />
+                  </template>
+                  {{ $t('common.reset') }}
+                </NButton>
               </NSpace>
             </NFormItemGi>
           </NGrid>
diff --git a/ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-operate-drawer.vue b/ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-operate-drawer.vue
index f573bb8..55fcf0d 100644
--- a/ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-operate-drawer.vue
+++ b/ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-operate-drawer.vue
@@ -39,6 +39,13 @@
   return titles[props.operateType];
 });
 
+const clsOptions = [
+  { label: 'A', value: 'A' },
+  { label: 'B', value: 'B' },
+  { label: 'C', value: 'C' },
+  { label: 'D', value: 'D' }
+];
+
 type Model = Api.Qm.JudgeDetailsOperateParams;
 
 const model = ref<Model>(createDefaultModel());
@@ -65,12 +72,14 @@
 
 type RuleKey = Extract<keyof Model, 'id'>;
 
-const rules: Record<RuleKey, App.Global.FormRule> = {};
+const rules: Record<RuleKey, App.Global.FormRule | App.Global.FormRule[]> = {
+  id: createRequiredRule('璇疯緭鍏ョ紪鐮�')
+};
 
 function handleUpdateModelWhenEdit() {
   model.value = createDefaultModel();
 
-  if (props.operateType === 'edit' && props.rowData) {
+  if (props.rowData) {
     Object.assign(model.value, jsonClone(props.rowData));
   }
 }
@@ -160,59 +169,26 @@
   <NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
     <NDrawerContent :title="title" :native-scrollbar="false" closable>
       <NForm ref="formRef" :model="model" :rules="rules">
-        <NFormItem label="缂栫爜" path="id">
-          <NInput v-model:value="model.id" placeholder="璇疯緭鍏ョ紪鐮�" />
-        </NFormItem>
-        <NFormItem label="鍒ゅ畾涓绘爣璇�" path="judgeId">
-          <NInput v-model:value="model.judgeId" placeholder="璇疯緭鍏ュ垽瀹氫富鏍囪瘑" />
-        </NFormItem>
-        <NFormItem label="鍒ゅ畾椤笽TEM" path="itemCod">
-          <NInput v-model:value="model.itemCod" placeholder="璇疯緭鍏ュ垽瀹氶」ITEM" />
-        </NFormItem>
-        <NFormItem label="鍒ゅ畾椤筃AME" path="itemName">
-          <NInput v-model:value="model.itemName" placeholder="璇疯緭鍏ュ垽瀹氶」NAME" />
+        <NFormItem label="鍒ゅ畾椤�" path="itemName">
+          <NInput v-model:value="(model.itemName as any)" placeholder="璇疯緭鍏ュ垽瀹氶」" :disabled="operateType === 'edit'" />
         </NFormItem>
         <NFormItem label="鏍囧噯鍊�" path="value3">
-          <NInput v-model:value="model.value3" placeholder="璇疯緭鍏ユ爣鍑嗗��" />
+          <NInputNumber v-model:value="(model.value3 as any)" placeholder="璇疯緭鍏ユ爣鍑嗗��" class="w-full" />
         </NFormItem>
-        <NFormItem label="鍒ゅ畾鍊�1" path="value1">
-          <NInput v-model:value="model.value1" placeholder="璇疯緭鍏ュ垽瀹氬��1" />
+        <NFormItem label="涓嬮檺鍊�" path="value1">
+          <NInputNumber v-model:value="(model.value1 as any)" placeholder="璇疯緭鍏ヤ笅闄愬��" class="w-full" />
         </NFormItem>
-        <NFormItem label="鍒ゅ畾鍊�2" path="value2">
-          <NInput v-model:value="model.value2" placeholder="璇疯緭鍏ュ垽瀹氬��2" />
+        <NFormItem label="涓婇檺鍊�" path="value2">
+          <NInputNumber v-model:value="(model.value2 as any)" placeholder="璇疯緭鍏ヤ笂闄愬��" class="w-full" />
         </NFormItem>
-        <NFormItem label="缂洪櫡浣嶇疆" path="location">
-          <NInput v-model:value="model.location" placeholder="璇疯緭鍏ョ己闄蜂綅缃�" />
+        <NFormItem label="鍒嗗��" path="stdscore">
+          <NInputNumber v-model:value="(model.stdscore as any)" placeholder="璇疯緭鍏ュ垎鍊�" class="w-full" />
         </NFormItem>
-        <NFormItem label="鍒ゅ畾绾у埆 (A,B,C,D)" path="cls">
-          <NInput v-model:value="model.cls" placeholder="璇疯緭鍏ュ垽瀹氱骇鍒� (A,B,C,D)" />
-        </NFormItem>
-        <NFormItem label="鍒嗗�兼爣鍑� (鎵e垎鏍囧噯锛屽緱鍒嗘爣鍑�),姣斿涓嶅悎鏍间竴娆℃墸澶氬皯鍒�" path="stdscore">
-          <NInput
-            v-model:value="model.stdscore"
-            placeholder="璇疯緭鍏ュ垎鍊兼爣鍑� (鎵e垎鏍囧噯锛屽緱鍒嗘爣鍑�),姣斿涓嶅悎鏍间竴娆℃墸澶氬皯鍒�"
-          />
-        </NFormItem>
-        <NFormItem label="鏍囪姝ら」鏄惁涓哄悎鎴愰」鐩紝姣斿澶栬锛屽疄闄呬笂鍏宠仈浜嗗緢澶氬瓙椤圭洰" path="ismix">
-          <NInput
-            v-model:value="model.ismix"
-            placeholder="璇疯緭鍏ユ爣璁版椤规槸鍚︿负鍚堟垚椤圭洰锛屾瘮濡傚瑙傦紝瀹為檯涓婂叧鑱斾簡寰堝瀛愰」鐩�"
-          />
-        </NFormItem>
-        <NFormItem label="鑻ユ瀛楁鏈塙UID鍊硷紝琛ㄦ槑瀹冨彲鑳戒负鍏朵粬椤圭洰鐨勫瓙椤癸紝姣斿鈥滅┖澶粹��,瀹冧负鐑熸敮澶栬椤圭洰鐨勫瓙椤�" path="rid">
-          <NInput
-            v-model:value="model.rid"
-            placeholder="璇疯緭鍏ヨ嫢姝ゅ瓧娈垫湁UUID鍊硷紝琛ㄦ槑瀹冨彲鑳戒负鍏朵粬椤圭洰鐨勫瓙椤癸紝姣斿鈥滅┖澶粹��,瀹冧负鐑熸敮澶栬椤圭洰鐨勫瓙椤�"
-          />
-        </NFormItem>
-        <NFormItem label="鑼冨洿-澶囩敤" path="category">
-          <NInput v-model:value="model.category" placeholder="璇疯緭鍏ヨ寖鍥�-澶囩敤" />
+        <NFormItem label="鍒ゅ畾绾у埆" path="cls">
+          <NSelect v-model:value="(model.cls as any)" :options="clsOptions" placeholder="璇烽�夋嫨鍒ゅ畾绾у埆" />
         </NFormItem>
         <NFormItem label="澶囨敞" path="decisionDes">
-          <NInput v-model:value="model.decisionDes" placeholder="璇疯緭鍏ュ娉�" />
-        </NFormItem>
-        <NFormItem label="淇敼浜�" path="updateUser">
-          <NInput v-model:value="model.updateUser" placeholder="璇疯緭鍏ヤ慨鏀逛汉" />
+          <NInput v-model:value="(model.decisionDes as any)" type="textarea" placeholder="璇疯緭鍏ュ娉�" />
         </NFormItem>
       </NForm>
       <template #footer>
diff --git a/ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-sub-table.vue b/ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-sub-table.vue
new file mode 100644
index 0000000..67101a2
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-sub-table.vue
@@ -0,0 +1,414 @@
+<script setup lang="tsx">
+import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
+import type { DataTableRowKey } from 'naive-ui';
+import { NDivider } from 'naive-ui';
+import { jsonClone } from '@sa/utils';
+import { fetchBatchDeleteJudgeDetails, fetchGetJudgeDetailsTree } from '@/service/api/qm/judge-details';
+import { useAuth } from '@/hooks/business/auth';
+import { useNaiveTable } from '@/hooks/common/table';
+import { $t } from '@/locales';
+import ButtonIcon from '@/components/custom/button-icon.vue';
+import JudgeDetailsOperateDrawer from './judge-details-operate-drawer.vue';
+
+defineOptions({
+  name: 'JudgeDetailsSubTable'
+});
+
+interface Props {
+  judgeId?: CommonType.IdType | null;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  judgeId: null
+});
+
+interface JudgeDetailsSubRow extends Api.Qm.JudgeDetails {
+  children?: JudgeDetailsSubRow[];
+}
+
+const { hasAuth } = useAuth();
+
+const checkedRowKeys = ref<CommonType.IdType[]>([]);
+const drawerVisible = ref(false);
+const operateType = ref<NaiveUI.TableOperateType>('add');
+const editingData = ref<Api.Qm.JudgeDetails | null>(null);
+const showFullscreen = ref(false);
+const fullscreenStyle = ref<Record<string, string>>({});
+
+function handleAdd() {
+  if (!props.judgeId) {
+    window.$message?.warning('璇峰厛閫夋嫨鍒ゅ畾渚濇嵁');
+    return;
+  }
+  operateType.value = 'add';
+  editingData.value = { judgeId: props.judgeId } as any;
+  drawerVisible.value = true;
+}
+
+function handleEdit(row: JudgeDetailsSubRow) {
+  operateType.value = 'edit';
+  editingData.value = jsonClone(row);
+  drawerVisible.value = true;
+}
+
+async function handleBatchDelete() {
+  if (checkedRowKeys.value.length === 0) return;
+  const { error } = await fetchBatchDeleteJudgeDetails(checkedRowKeys.value);
+  if (error) return;
+  window.$message?.success($t('common.deleteSuccess'));
+  checkedRowKeys.value = [];
+  await getData();
+}
+
+async function handleDelete(id: CommonType.IdType) {
+  const { error } = await fetchBatchDeleteJudgeDetails([id]);
+  if (error) return;
+  window.$message?.success($t('common.deleteSuccess'));
+  await getData();
+}
+
+const {
+  columns,
+  columnChecks,
+  data: rows,
+  loading,
+  getData,
+  scrollX
+} = useNaiveTable<Api.Common.PaginatingQueryRecord<Api.Qm.JudgeDetails>, Api.Qm.JudgeDetails>({
+  api: async () => {
+    if (!props.judgeId) return { rows: [], total: 0, pageNum: 1 } as any;
+    const { data } = await fetchGetJudgeDetailsTree({
+      pageNum: 1,
+      pageSize: 9999,
+      judgeId: props.judgeId
+    });
+    return data;
+  },
+  columns: () => [
+    {
+      type: 'selection',
+      align: 'center',
+      width: 48
+    },
+    {
+      key: 'index',
+      title: $t('common.index'),
+      align: 'center',
+      width: 56,
+      render: (_: any, index: number) => index + 1
+    },
+    {
+      key: 'itemName',
+      title: '鍒ゅ畾椤�',
+      align: 'left',
+      width: 250,
+      tree: true
+    } as any,
+    {
+      key: 'value3',
+      title: '鏍囧噯鍊�',
+      align: 'center',
+      width: 100
+    },
+    {
+      key: 'value1',
+      title: '涓嬮檺鍊�',
+      align: 'center',
+      width: 100
+    },
+    {
+      key: 'value2',
+      title: '涓婇檺鍊�',
+      align: 'center',
+      width: 100
+    },
+    {
+      key: 'cls',
+      title: '绾у埆',
+      align: 'center',
+      width: 80
+    },
+    {
+      key: 'stdscore',
+      title: '鍒嗗��',
+      align: 'center',
+      minWidth: 150
+    },
+    {
+      key: 'decisionDes',
+      title: '澶囨敞',
+      align: 'center',
+      minWidth: 150
+    },
+    {
+      key: 'updateUser',
+      title: '淇敼浜�',
+      align: 'center',
+      minWidth: 150
+    },
+    {
+      key: 'operate',
+      title: $t('common.operate'),
+      fixed: 'right',
+      align: 'center',
+      width: 130,
+      render: (row: any) => {
+        const divider = () => {
+          if (!hasAuth('qm:judgeDetails:edit') || !hasAuth('qm:judgeDetails:remove')) {
+            return null;
+          }
+          return <NDivider vertical />;
+        };
+
+        const editBtn = () => {
+          if (!hasAuth('qm:judgeDetails:edit')) {
+            return null;
+          }
+          return (
+            <ButtonIcon
+              text
+              type="primary"
+              icon="material-symbols:drive-file-rename-outline-outline"
+              tooltipContent={$t('common.edit')}
+              onClick={() => handleEdit(row)}
+            />
+          );
+        };
+
+        const deleteBtn = () => {
+          if (!hasAuth('qm:judgeDetails:remove')) {
+            return null;
+          }
+          return (
+            <ButtonIcon
+              text
+              type="error"
+              icon="material-symbols:delete-outline"
+              tooltipContent={$t('common.delete')}
+              popconfirmContent={$t('common.confirmDelete')}
+              onPositiveClick={() => handleDelete(row.id)}
+            />
+          );
+        };
+
+        return (
+          <div class="flex-center gap-8px">
+            {editBtn()}
+            {divider()}
+            {deleteBtn()}
+          </div>
+        );
+      }
+    }
+  ],
+  transform: response => {
+    return response?.rows || [];
+  }
+});
+
+const onFullscreenKeydown = (event: KeyboardEvent) => {
+  if (event.key === 'Escape') {
+    showFullscreen.value = false;
+  }
+};
+
+const cardTitle = computed(() => `鍒ゅ畾鏄庣粏缁存姢`);
+
+watch(
+  () => props.judgeId,
+  async () => {
+    checkedRowKeys.value = [];
+    await getData();
+  },
+  { immediate: true }
+);
+
+watch(
+  showFullscreen,
+  visible => {
+    if (visible) {
+      updateFullscreenStyle();
+      window.addEventListener('keydown', onFullscreenKeydown);
+      window.addEventListener('resize', updateFullscreenStyle);
+      window.addEventListener('scroll', updateFullscreenStyle, true);
+      return;
+    }
+    window.removeEventListener('keydown', onFullscreenKeydown);
+    window.removeEventListener('resize', updateFullscreenStyle);
+    window.removeEventListener('scroll', updateFullscreenStyle, true);
+  },
+  { immediate: true }
+);
+
+onBeforeUnmount(() => {
+  window.removeEventListener('keydown', onFullscreenKeydown);
+  window.removeEventListener('resize', updateFullscreenStyle);
+  window.removeEventListener('scroll', updateFullscreenStyle, true);
+});
+
+onMounted(() => {
+  updateFullscreenStyle();
+});
+
+function updateFullscreenStyle() {
+  const container = document.querySelector<HTMLElement>('.judge-content-area');
+  if (!container) {
+    fullscreenStyle.value = {
+      position: 'fixed',
+      inset: '0',
+      zIndex: '20'
+    };
+    return;
+  }
+  const rect = container.getBoundingClientRect();
+  fullscreenStyle.value = {
+    position: 'fixed',
+    left: `${rect.left}px`,
+    top: `${rect.top}px`,
+    width: `${rect.width}px`,
+    height: `${rect.height}px`,
+    zIndex: '20'
+  };
+}
+
+function rowKey(row: JudgeDetailsSubRow): DataTableRowKey {
+  return String(row.id);
+}
+</script>
+
+<template>
+  <div class="flex-col-stretch">
+    <NCard
+      :title="cardTitle"
+      :bordered="false"
+      size="small"
+      class="flex-col-stretch card-wrapper flex-1-hidden"
+      :content-style="{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }"
+    >
+      <template #header-extra>
+        <NSpace align="center">
+          <TableHeaderOperation
+            v-model:columns="columnChecks"
+            :disabled-delete="checkedRowKeys.length === 0"
+            :loading="loading"
+            :show-add="hasAuth('qm:judgeDetails:add')"
+            :show-delete="hasAuth('qm:judgeDetails:remove')"
+            :show-export="false"
+            @add="handleAdd"
+            @delete="handleBatchDelete"
+            @refresh="getData"
+          />
+          <NButton size="small" @click="showFullscreen = true">
+            <template #icon>
+              <icon-mdi-fullscreen class="text-icon" />
+            </template>
+            鍏ㄥ睆
+          </NButton>
+        </NSpace>
+      </template>
+
+      <NSpin :show="loading" class="h-full" content-class="h-full flex-col-stretch flex-1-hidden">
+        <div v-if="!props.judgeId" class="h-full flex-center text-gray-400">璇风偣鍑讳笂鏂硅〃鏍艰鏌ョ湅鏄庣粏</div>
+        <NDataTable
+          v-else
+          v-model:checked-row-keys="checkedRowKeys"
+          :columns="columns"
+          :data="rows"
+          size="small"
+          flex-height
+          children-key="children"
+          :row-key="rowKey"
+          default-expand-all
+          striped
+          class="flex-1-hidden"
+        />
+      </NSpin>
+    </NCard>
+
+    <Teleport to="body">
+      <div v-if="showFullscreen" class="fullscreen-mask" :style="fullscreenStyle" @click.self="showFullscreen = false">
+        <NCard
+          :title="cardTitle"
+          :bordered="false"
+          size="small"
+          class="fullscreen-card flex-col-stretch"
+          :content-style="{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }"
+        >
+          <template #header-extra>
+            <NSpace align="center">
+              <TableHeaderOperation
+                v-model:columns="columnChecks"
+                :disabled-delete="checkedRowKeys.length === 0"
+                :loading="loading"
+                :show-add="hasAuth('qm:judgeDetails:add')"
+                :show-delete="hasAuth('qm:judgeDetails:remove')"
+                :show-export="false"
+                @add="handleAdd"
+                @delete="handleBatchDelete"
+                @refresh="getData"
+              />
+              <NButton size="small" ghost type="error" @click="showFullscreen = false">
+                <template #icon>
+                  <icon-mdi-close class="text-icon" />
+                </template>
+                鍏抽棴
+              </NButton>
+            </NSpace>
+          </template>
+
+          <NSpin :show="loading" class="h-full" content-class="h-full">
+            <div v-if="!props.judgeId" class="h-full flex-center text-gray-400">璇风偣鍑讳笂鏂硅〃鏍艰鏌ョ湅鏄庣粏</div>
+            <NDataTable
+              v-else
+              v-model:checked-row-keys="checkedRowKeys"
+              :columns="columns"
+              :data="rows"
+              size="small"
+              flex-height
+              children-key="children"
+              :row-key="rowKey"
+              striped
+              class="fullscreen-table"
+            />
+          </NSpin>
+        </NCard>
+      </div>
+    </Teleport>
+
+    <JudgeDetailsOperateDrawer
+      v-model:visible="drawerVisible"
+      :operate-type="operateType"
+      :row-data="editingData"
+      @submitted="getData"
+    />
+  </div>
+</template>
+
+<style scoped>
+:deep(.n-card__content) {
+  padding: 8px 12px;
+}
+
+:deep(.n-data-table-th),
+:deep(.n-data-table-td) {
+  padding: 4px 6px;
+}
+
+.fullscreen-mask {
+  position: absolute;
+  inset: 0;
+  z-index: 20;
+  background: #fff;
+  padding: 0;
+  display: flex;
+}
+
+.fullscreen-card {
+  width: 100%;
+  height: 100%;
+}
+
+.fullscreen-table {
+  height: 100%;
+}
+</style>
diff --git a/ruoyi-plus-soybean/src/views/qm/judge/index.vue b/ruoyi-plus-soybean/src/views/qm/judge/index.vue
index 84b5e37..13fe5c0 100644
--- a/ruoyi-plus-soybean/src/views/qm/judge/index.vue
+++ b/ruoyi-plus-soybean/src/views/qm/judge/index.vue
@@ -10,6 +10,8 @@
 import ButtonIcon from '@/components/custom/button-icon.vue';
 import JudgeOperateDrawer from './modules/judge-operate-drawer.vue';
 import JudgeSearch from './modules/judge-search.vue';
+import JudgeDetailsSubTable from '../judge-details/modules/judge-details-sub-table.vue';
+import StdSubTable from "@/views/qm/std/modules/std-sub-table.vue";
 
 defineOptions({
   name: 'JudgeList'
@@ -19,6 +21,8 @@
 const { download } = useDownload();
 const { hasAuth } = useAuth();
 
+const selectedJudgeId = ref<CommonType.IdType | null>(null);
+
 const searchParams = ref<Api.Qm.JudgeSearchParams>({
   pageNum: 1,
   pageSize: 10,
@@ -26,7 +30,7 @@
   matName: null,
   judgeName: null,
   category: 0, // 榛樿閫夋嫨鎴愬搧
-  status: -1, // 榛樿閫夋嫨鍏ㄩ儴
+  status: 1, // 榛樿鏌ヨ鍚敤
   params: {}
 });
 
@@ -276,47 +280,74 @@
 function handleExport() {
   download('/qm/judge/export', searchParams.value, `鍒ゅ畾渚濇嵁_${new Date().getTime()}.xlsx`);
 }
+
+function handleRowClick(row: any) {
+  return {
+    onClick: (e: MouseEvent) => {
+      const target = e.target as HTMLElement | null;
+      if (target?.closest('.n-checkbox') || target?.closest('.n-button') || target?.closest('a')) return;
+      selectedJudgeId.value = row.id;
+    },
+    style: 'cursor: pointer;'
+  };
+}
 </script>
 
 <template>
   <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
     <JudgeSearch v-model:model="searchParams" @search="getDataByPage" />
-    <NCard title="鍒ゅ畾渚濇嵁鍒楄〃" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
-      <template #header-extra>
-        <TableHeaderOperation
-          v-model:columns="columnChecks"
-          :disabled-delete="checkedRowKeys.length === 0"
-          :loading="loading"
-          :show-add="hasAuth('qm:judge:add')"
-          :show-delete="hasAuth('qm:judge:remove')"
-          :show-export="hasAuth('qm:judge:export')"
-          @add="handleAdd"
-          @delete="handleBatchDelete"
-          @export="handleExport"
-          @refresh="getData"
-        />
-      </template>
-      <NDataTable
-        v-model:checked-row-keys="checkedRowKeys"
-        :columns="columns"
-        :data="data"
+    <div class="judge-content-area relative flex-col-stretch gap-16px sm:flex-1-hidden">
+      <NCard
+        title="鍒ゅ畾渚濇嵁鍒楄〃"
+        :bordered="false"
         size="small"
-        :flex-height="!appStore.isMobile"
-        :scroll-x="scrollX"
-        :loading="loading"
-        remote
-        :row-key="row => row.id"
-        :pagination="mobilePagination"
-        class="sm:h-full"
-      />
-      <JudgeOperateDrawer
-        v-model:visible="drawerVisible"
-        :operate-type="operateType"
-        :row-data="editingData"
-        @submitted="getDataByPage"
-      />
-    </NCard>
+        class="flex-col-stretch card-wrapper sm:flex-1-hidden"
+        :content-style="{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }"
+      >
+        <template #header-extra>
+          <TableHeaderOperation
+            v-model:columns="columnChecks"
+            :disabled-delete="checkedRowKeys.length === 0"
+            :loading="loading"
+            :show-add="hasAuth('qm:judge:add')"
+            :show-delete="hasAuth('qm:judge:remove')"
+            :show-export="hasAuth('qm:judge:export')"
+            @add="handleAdd"
+            @delete="handleBatchDelete"
+            @export="handleExport"
+            @refresh="getData"
+          />
+        </template>
+        <NDataTable
+          v-model:checked-row-keys="checkedRowKeys"
+          :columns="columns"
+          :data="data"
+          size="small"
+          :flex-height="!appStore.isMobile"
+          :scroll-x="scrollX"
+          :loading="loading"
+          remote
+          :row-key="row => row.id"
+          :pagination="mobilePagination"
+          :row-props="handleRowClick"
+          class="flex-1-hidden"
+        />
+        <JudgeOperateDrawer
+          v-model:visible="drawerVisible"
+          :operate-type="operateType"
+          :row-data="editingData"
+          @submitted="getDataByPage"
+        />
+      </NCard>
+      <JudgeDetailsSubTable :judge-id="selectedJudgeId" class="sm:flex-1-hidden"  />
+    </div>
   </div>
 </template>
 
-<style scoped></style>
+<style scoped>
+:deep(.n-data-table-th),
+:deep(.n-data-table-td) {
+  padding: 4px 6px;
+  overflow: hidden;
+}
+</style>
diff --git a/ruoyi-plus-soybean/src/views/qm/judge/modules/judge-operate-drawer.vue b/ruoyi-plus-soybean/src/views/qm/judge/modules/judge-operate-drawer.vue
index 82a891e..28bfabd 100644
--- a/ruoyi-plus-soybean/src/views/qm/judge/modules/judge-operate-drawer.vue
+++ b/ruoyi-plus-soybean/src/views/qm/judge/modules/judge-operate-drawer.vue
@@ -1,10 +1,11 @@
 <script setup lang="ts">
-import { computed, onMounted, ref, watch } from 'vue';
+import { computed, ref, watch } from 'vue';
 import type { SelectOption } from 'naive-ui';
 import { NSelect } from 'naive-ui';
 import { jsonClone } from '@sa/utils';
 import { fetchCreateJudge, fetchUpdateJudge } from '@/service/api/qm/judge';
 import { fetchGetStdList } from '@/service/api/qm/std';
+import { fetchGetMatList } from '@/service/api/md/mat';
 import { useFormRules, useNaiveForm } from '@/hooks/common/form';
 import { $t } from '@/locales';
 
@@ -53,6 +54,7 @@
 ];
 
 const stdOptions = ref<SelectOption[]>([]);
+const matOptions = ref<SelectOption[]>([]);
 
 type Model = Api.Qm.JudgeOperateParams;
 
@@ -102,6 +104,20 @@
   }
 }
 
+async function fetchMatOptions() {
+  if (model.value.category === 1) {
+    matOptions.value = [];
+    return;
+  }
+  const { data } = await fetchGetMatList({ tid: 1, pageSize: 1000 });
+  if (data) {
+    matOptions.value = data.rows.map(item => ({
+      label: item.name,
+      value: item.code
+    }));
+  }
+}
+
 async function handleSubmit() {
   await validate();
 
@@ -147,20 +163,39 @@
   emit('submitted');
 }
 
-watch(visible, () => {
+watch(visible, async () => {
   if (visible.value) {
     handleUpdateModelWhenEdit();
     restoreValidation();
 
-    // Fetch stdOptions when the drawer becomes visible
-    fetchStdOptions();
+    await fetchStdOptions();
+    await fetchMatOptions();
   }
 });
 
 watch(
   () => model.value.category,
-  () => {
+  async () => {
     fetchStdOptions();
+    model.value.matName = '';
+    model.value.matCode = '';
+    await fetchMatOptions();
+  }
+);
+
+watch(
+  () => model.value.matCode,
+  val => {
+    if (val) {
+      const selectedOption = matOptions.value.find(opt => opt.value === val);
+      if (selectedOption && typeof selectedOption.label === 'string') {
+        const name = selectedOption.label as string;
+        model.value.matName = name;
+        model.value.judgeName = name;
+      }
+    } else {
+      model.value.matName = '';
+    }
   }
 );
 </script>
@@ -172,15 +207,17 @@
         <NFormItem label="鍒ゅ畾鍚嶇О" path="judgeName">
           <NInput v-model:value="model.judgeName" placeholder="璇疯緭鍏ュ垽瀹氬悕绉�" />
         </NFormItem>
-        <NFormItem label="鐗╂枡鐗屽彿浠g爜" path="matCode">
-          <NInput v-model:value="model.matCode" placeholder="璇疯緭鍏ョ墿鏂欑墝鍙蜂唬鐮�" />
-        </NFormItem>
-        <NFormItem label="鐗╂枡鐗屽彿" path="matName">
-          <NInput v-model:value="model.matName" placeholder="璇疯緭鍏ョ墿鏂欑墝鍙�" />
-        </NFormItem>
         <NFormItem label="鐗╂枡绫诲瀷" path="category">
           <NSelect v-model:value="model.category" :options="categoryOptions" placeholder="璇烽�夋嫨鐗╂枡绫诲瀷" />
         </NFormItem>
+        <NFormItem label="鐗╂枡鐗屽彿" path="matName">
+          <NSelect
+            v-model:value="model.matCode"
+            :options="matOptions"
+            placeholder="璇烽�夋嫨鐗╂枡鐗屽彿"
+            :disabled="model.category === 1"
+          />
+        </NFormItem>
         <NFormItem label="鐘舵��" path="status">
           <NSelect v-model:value="model.status" :options="statusOptions" placeholder="璇烽�夋嫨鐘舵��" />
         </NFormItem>
diff --git a/ruoyi-plus-soybean/src/views/qm/judge/modules/judge-search.vue b/ruoyi-plus-soybean/src/views/qm/judge/modules/judge-search.vue
index 235b8a3..ba7c5dd 100644
--- a/ruoyi-plus-soybean/src/views/qm/judge/modules/judge-search.vue
+++ b/ruoyi-plus-soybean/src/views/qm/judge/modules/judge-search.vue
@@ -1,6 +1,7 @@
 <script setup lang="ts">
-import { toRaw } from 'vue';
+import { onMounted, ref, toRaw, watch } from 'vue';
 import { jsonClone } from '@sa/utils';
+import { fetchGetMatList } from '@/service/api/md/mat';
 import { useNaiveForm } from '@/hooks/common/form';
 import { $t } from '@/locales';
 
@@ -19,6 +20,43 @@
 const model = defineModel<Api.Qm.JudgeSearchParams>('model', { required: true });
 
 const defaultModel = jsonClone(toRaw(model.value));
+
+const matOptions = ref<CommonType.Option[]>([]);
+
+async function getMatOptions() {
+  if (model.value.category !== 0) {
+    matOptions.value = [];
+    model.value.matName = null;
+    model.value.matCode = null;
+    return;
+  }
+  const { data } = await fetchGetMatList({ tid: 1, pageSize: 1000 });
+  if (data) {
+    matOptions.value = data.rows.map(item => ({
+      label: item.name,
+      value: item.code
+    }));
+  }
+}
+
+watch(
+  () => model.value.category,
+  newVal => {
+    if (newVal === 0) {
+      getMatOptions();
+    } else {
+      matOptions.value = [];
+      model.value.matName = null;
+      model.value.matCode = null;
+    }
+  }
+);
+
+onMounted(() => {
+  if (model.value.category === 0) {
+    getMatOptions();
+  }
+});
 
 function resetModel() {
   Object.assign(model.value, defaultModel);
@@ -53,11 +91,15 @@
               />
             </NFormItemGi>
 
-            <NFormItemGi span="24 s:12 m:6" label="鐗╂枡鐗屽彿浠g爜" label-width="auto" path="matCode" class="pr-24px">
-              <NInput v-model:value="model.matCode" placeholder="璇疯緭鍏ョ墿鏂欑墝鍙蜂唬鐮�" />
-            </NFormItemGi>
-            <NFormItemGi span="24 s:12 m:6" label="鐗╂枡鐗屽彿" label-width="auto" path="matName" class="pr-24px">
-              <NInput v-model:value="model.matName" placeholder="璇疯緭鍏ョ墿鏂欑墝鍙�" />
+            <NFormItemGi span="24 s:12 m:6" label="鐗╂枡鐗屽彿" label-width="auto" path="matCode" class="pr-24px">
+              <NSelect
+                v-model:value="model.matCode"
+                :options="matOptions"
+                placeholder="璇烽�夋嫨鐗╂枡鐗屽彿"
+                :disabled="model.category !== 0"
+                clearable
+                filterable
+              />
             </NFormItemGi>
             <NFormItemGi span="24 s:12 m:6" label="鍒ゅ畾鍚嶇О" label-width="auto" path="judgeName" class="pr-24px">
               <NInput v-model:value="model.judgeName" placeholder="璇疯緭鍏ュ垽瀹氬悕绉�" />
diff --git a/ruoyi-plus-soybean/src/views/qm/matcheck/index.vue b/ruoyi-plus-soybean/src/views/qm/matcheck/index.vue
new file mode 100644
index 0000000..6203c03
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/qm/matcheck/index.vue
@@ -0,0 +1,268 @@
+<script setup lang="tsx">
+import { ref } from 'vue';
+import { NDivider } from 'naive-ui';
+import { fetchBatchDeleteMatcheck, fetchGetQmMatcheckList } from '@/service/api/qm/matcheck';
+import { useAppStore } from '@/store/modules/app';
+import { useAuth } from '@/hooks/business/auth';
+import { useDownload } from '@/hooks/business/download';
+import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
+import { $t } from '@/locales';
+import ButtonIcon from '@/components/custom/button-icon.vue';
+import MatcheckOperateDrawer from './modules/matcheck-operate-drawer.vue';
+import { useRoute } from 'vue-router';
+
+defineOptions({
+  name: 'MatcheckList'
+});
+
+
+const appStore = useAppStore();
+const { download } = useDownload();
+const { hasAuth } = useAuth();
+
+const route = useRoute();
+function getSingleQueryValue(query: string | string[] | null | undefined) {
+  if (Array.isArray(query)) return query[0] || '';
+  return query || '';
+}
+
+const judgeCode = getSingleQueryValue(route.query.judgeCode);
+const batchCode = getSingleQueryValue(route.query.batchCode);
+const matCode = getSingleQueryValue(route.query.matCode);
+
+const searchParams = ref<Api.Qm.MatcheckSearchParams>({
+  pageNum: 1,
+  pageSize: 10,
+  batchCode,
+  judgeCode,
+  matCode,
+  checkName: null,
+  checkTime: null,
+  reviewName: null,
+  reviewTiem: null,
+  params: {}
+});
+
+const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
+  useNaivePaginatedTable({
+  api: () => fetchGetQmMatcheckList(searchParams.value),
+  transform: response => defaultTransform(response),
+  onPaginationParamsChange: params => {
+    searchParams.value.pageNum = params.page;
+    searchParams.value.pageSize = params.pageSize;
+  },
+  columns: () => [
+    {
+      type: 'selection',
+      align: 'center',
+      width: 48
+    },
+    {
+      key: 'index',
+      title: $t('common.index'),
+      align: 'center',
+      width: 64,
+      render: (_, index) => index + 1
+    },
+    {
+      key: 'itemName',
+      title: '妫�楠岄」',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'maxval',
+      title: '鏈�澶у��/鐑熶笣璐ㄩ噺(鍚湯鐜�)',
+      align: 'center',
+      minWidth: 170
+    },
+    {
+      key: 'minval',
+      title: '鏈�灏忓��/鐑熸湯璐ㄩ噺(鍚湯鐜�)',
+      align: 'center',
+      minWidth: 170
+    },
+    {
+      key: 'avgval',
+      title: '骞冲潎鍊�/鍚湯鐜�',
+      align: 'center',
+      minWidth: 130
+    },
+    {
+      key: 'sdval',
+      title: 'SD鍊�',
+      align: 'center',
+      minWidth: 100
+    },
+    {
+      key: 'cvval',
+      title: 'CV鍊�',
+      align: 'center',
+      minWidth: 100
+    },
+    {
+      key: 'cpkval',
+      title: 'CPK鍊�',
+      align: 'center',
+      minWidth: 100
+    },
+    {
+      key: 'badval',
+      title: '瓒呮爣鏁�',
+      align: 'center',
+      minWidth: 100
+    },
+    {
+      key: 'checker',
+      title: '妫�楠屽憳',
+      align: 'center',
+      minWidth: 100
+    },
+    {
+      key: 'checkTime',
+      title: '妫�楠屾椂闂�',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'reviewName',
+      title: '澶嶆鍛�',
+      align: 'center',
+      minWidth: 100
+    },
+    {
+      key: 'reviewTime',
+      title: '澶嶆鏃堕棿',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'chkDes',
+      title: '鎻忚堪',
+      align: 'center',
+      minWidth: 120
+    },
+    {
+      key: 'operate',
+      title: $t('common.operate'),
+      align: 'center',
+      fixed: 'right',
+      width: 130,
+      render: row => {
+        const divider = () => {
+          if (!hasAuth('qm:matcheck:edit') || !hasAuth('qm:matcheck:remove')) {
+            return null;
+          }
+          return <NDivider vertical />;
+        };
+
+        const editBtn = () => {
+          if (!hasAuth('qm:matcheck:edit')) {
+            return null;
+          }
+          return (
+            <ButtonIcon
+              text
+              type="primary"
+              icon="material-symbols:drive-file-rename-outline-outline"
+              tooltipContent={$t('common.edit')}
+              onClick={() => edit(row.id)}
+            />
+          );
+        };
+
+        const deleteBtn = () => {
+          if (!hasAuth('qm:matcheck:remove')) {
+            return null;
+          }
+          return (
+            <ButtonIcon
+              text
+              type="error"
+              icon="material-symbols:delete-outline"
+              tooltipContent={$t('common.delete')}
+              popconfirmContent={$t('common.confirmDelete')}
+              onPositiveClick={() => handleDelete(row.id)}
+            />
+          );
+        };
+
+        return (
+          <div class="flex-center gap-8px">
+            {editBtn()}
+            {divider()}
+            {deleteBtn()}
+          </div>
+        );
+      }
+    }
+  ]
+});
+
+const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
+  useTableOperate(data, 'id', getData);
+
+async function handleBatchDelete() {
+  // request
+  const { error } = await fetchBatchDeleteMatcheck(checkedRowKeys.value);
+  if (error) return;
+  onBatchDeleted();
+}
+
+async function handleDelete(id: CommonType.IdType) {
+  // request
+  const { error } = await fetchBatchDeleteMatcheck([id]);
+  if (error) return;
+  onDeleted();
+}
+
+function edit(id: CommonType.IdType) {
+  handleEdit(id);
+}
+
+function handleExport() {
+  download('/qm/matcheck/export', searchParams.value, `鏉愭枡妫�楠岀粺璁${new Date().getTime()}.xlsx`);
+}
+</script>
+
+<template>
+  <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
+    <NCard title="鏉愭枡妫�楠岀粺璁″垪琛�" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
+      <template #header-extra>
+        <TableHeaderOperation
+          v-model:columns="columnChecks"
+          :disabled-delete="checkedRowKeys.length === 0"
+          :loading="loading"
+          :show-add="hasAuth('qm:matcheck:add')"
+          :show-delete="hasAuth('qm:matcheck:remove')"
+          :show-export="hasAuth('qm:matcheck:export')"
+          @add="handleAdd"
+          @delete="handleBatchDelete"
+          @export="handleExport"
+          @refresh="getData"
+        />
+      </template>
+      <NDataTable
+        v-model:checked-row-keys="checkedRowKeys"
+        :columns="columns"
+        :data="data"
+        size="small"
+        :flex-height="!appStore.isMobile"
+        :scroll-x="scrollX"
+        :loading="loading"
+        remote
+        :row-key="row => row.id"
+        :pagination="mobilePagination"
+        class="sm:h-full"
+      />
+      <MatcheckOperateDrawer
+        v-model:visible="drawerVisible"
+        :operate-type="operateType"
+        :row-data="editingData"
+        @submitted="getDataByPage"
+      />
+    </NCard>
+  </div>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/qm/matcheck/modules/matcheck-operate-drawer.vue b/ruoyi-plus-soybean/src/views/qm/matcheck/modules/matcheck-operate-drawer.vue
new file mode 100644
index 0000000..8115cdf
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/qm/matcheck/modules/matcheck-operate-drawer.vue
@@ -0,0 +1,266 @@
+<script setup lang="ts">
+import { computed, onMounted, ref, watch } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { fetchCreateMatcheck, fetchUpdateMatcheck, fetchCheckItemList } from '@/service/api/qm/matcheck';
+import { useFormRules, useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+import { useRoute } from 'vue-router';
+
+defineOptions({
+  name: 'MatcheckOperateDrawer'
+});
+
+interface Props {
+  /** the type of operation */
+  operateType: NaiveUI.TableOperateType;
+  /** the edit row data */
+  rowData?: Api.Qm.Matcheck | null;
+}
+
+const props = defineProps<Props>();
+
+interface Emits {
+  (e: 'submitted'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const visible = defineModel<boolean>('visible', {
+  default: false
+});
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+const { createRequiredRule } = useFormRules();
+const route = useRoute();
+
+// 妫�楠岄」閫夐」
+const checkItemOptions = ref<CommonType.Option[]>([]);
+
+// 鑾峰彇妫�楠岄」閫夐」
+async function getCheckItemOptions() {
+  const judgeCode = Array.isArray(route.query.judgeCode) ? route.query.judgeCode[0] : route.query.judgeCode;
+  if (!judgeCode) {
+    checkItemOptions.value = [];
+    return;
+  }
+
+  const { data, error } = await fetchCheckItemList({ judgeId: judgeCode });
+  if (!error && data) {
+    checkItemOptions.value = data.map(item => ({
+      label: item.itemName, // 鎺ュ彛杩斿洖鐨勫瓧娈垫槸 item_name
+      value: item.itemCode // 鎺ュ彛杩斿洖鐨勫瓧娈垫槸 item_code
+    }));
+  }
+}
+
+const title = computed(() => {
+  const titles: Record<NaiveUI.TableOperateType, string> = {
+    add: '鏂板鏉愭枡妫�楠岀粺璁�',
+    edit: '缂栬緫鏉愭枡妫�楠岀粺璁�'
+  };
+  return titles[props.operateType];
+});
+
+type Model = Api.Qm.MatcheckOperateParams;
+
+const model = ref<Model>(createDefaultModel());
+
+const generateDetailsChecked = computed<string | number | boolean | undefined>({
+  get() {
+    return model.value.generateDetails ?? '0';
+  },
+  set(value) {
+    model.value.generateDetails = String(value ?? '0');
+  }
+});
+
+
+function createDefaultModel(): Model {
+  // 鑾峰彇褰撳墠鏃ユ湡锛屾牸寮忎负 yyyy-MM-dd
+  const today = new Date().toISOString().split('T')[0];
+  const matCode = (route.query.matCode as string) || '';
+
+  return {
+      id: '',
+      pid: '',
+      batchCode: route.query.batchCode as string || '',
+      matCode,
+      instrumentCode: '',
+      techReq: '',
+      checkStd: '',
+      testEnv: '',
+      itemCode: '',
+      subBatchCode: '',
+      sampleNumber: null,
+      sampleType: null,
+      checkName: '',
+      checkTime: today,
+      reviewName: '',
+      reviewTime: null,
+      maxval: null,
+      minval: null,
+      avgval: null,
+      sdval: null,
+      cvval: null,
+      cpkval: null,
+      badval: null,
+      judge: '',
+      singlejudge: '',
+      verName: '',
+      verCode: '',
+      archDate: '',
+      del: null,
+      flag: '',
+      toMesTime: null,
+      chkDes: '',
+      generateDetails: '0'
+  };
+}
+
+type RuleKey = Extract<
+  keyof Model,
+  | 'id'
+>;
+
+const rules: Record<RuleKey, App.Global.FormRule> = {
+  id: createRequiredRule('涓婚敭锛岀紪鐮佷笉鑳戒负绌�'),
+};
+
+function handleUpdateModelWhenEdit() {
+  model.value = createDefaultModel();
+
+  if (props.operateType === 'edit' && props.rowData) {
+    Object.assign(model.value, jsonClone(props.rowData));
+    model.value.generateDetails = model.value.generateDetails ?? '0';
+  }
+}
+
+function closeDrawer() {
+  visible.value = false;
+}
+
+async function handleSubmit() {
+  await validate();
+
+  const { id, pid, batchCode, matCode, instrumentCode, techReq, checkStd, testEnv, itemCode, subBatchCode, sampleNumber, sampleType, checkName, checkTime, reviewName, reviewTime, maxval, minval, avgval, sdval, cvval, cpkval, badval, judge, singlejudge, verName, verCode, archDate, del, flag, toMesTime, chkDes, generateDetails } = model.value;
+
+  // request
+  if (props.operateType === 'add') {
+    const { error } = await fetchCreateMatcheck({ id, pid, batchCode, matCode, instrumentCode, techReq, checkStd, testEnv, itemCode, subBatchCode, sampleNumber, sampleType, checkName, checkTime, reviewName, reviewTime, maxval, minval, avgval, sdval, cvval, cpkval, badval, judge, singlejudge, verName, verCode, archDate, del, flag, toMesTime, chkDes, generateDetails });
+    if (error) return;
+  }
+
+  if (props.operateType === 'edit') {
+    const { error } = await fetchUpdateMatcheck({ id, pid, batchCode, matCode, instrumentCode, techReq, checkStd, testEnv, itemCode, subBatchCode, sampleNumber, sampleType, checkName, checkTime, reviewName, reviewTime, maxval, minval, avgval, sdval, cvval, cpkval, badval, judge, singlejudge, verName, verCode, archDate, del, flag, toMesTime, chkDes, generateDetails });
+    if (error) return;
+  }
+
+  window.$message?.success($t('common.updateSuccess'));
+  closeDrawer();
+  emit('submitted');
+}
+
+onMounted(() => {
+  getCheckItemOptions();
+});
+
+watch(visible, () => {
+  if (visible.value) {
+    handleUpdateModelWhenEdit();
+    restoreValidation();
+    getCheckItemOptions();
+  }
+});
+</script>
+
+<template>
+  <NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
+    <NDrawerContent :title="title" :native-scrollbar="false" closable>
+      <NForm ref="formRef" :model="model" :rules="rules" label-placement="left" :label-width="180">
+        <NFormItem label="鎵规鍙�" path="batchCode">
+          <NInput v-model:value="model.batchCode" placeholder="鎵规鍙�" :disabled="true" />
+        </NFormItem>
+        <NFormItem label="妫�楠岄」" path="itemCode">
+          <NSelect
+            v-model:value="model.itemCode"
+            placeholder="璇烽�夋嫨妫�楠岄」"
+            :options="checkItemOptions"
+            clearable
+            filterable
+          />
+        </NFormItem>
+        <NFormItem label="鐩樺彿" path="subBatchCode">
+          <NInput v-model:value="model.subBatchCode" placeholder="璇疯緭鍏ョ洏鍙�" />
+        </NFormItem>
+        <NFormItem path="maxval">
+          <template #label>
+            鏈�澶у��/<br>
+            鐑熶笣璐ㄩ噺/<br>
+            (鍚湯鐜�)
+          </template>
+          <NInputNumber v-model:value="model.maxval" placeholder="璇疯緭鍏ユ渶澶у��" class="w-full" />
+        </NFormItem>
+        <NFormItem path="minval">
+          <template #label>
+            鏈�灏忓��/<br>
+            鐑熸湯璐ㄩ噺/<br>
+            (鍚湯鐜�)
+          </template>
+          <NInputNumber v-model:value="model.minval" placeholder="璇疯緭鍏ユ渶灏忓��" class="w-full" />
+        </NFormItem>
+        <NFormItem path="avgval">
+          <template #label>
+            骞冲潎鍊�/<br>
+            鍚湯鐜�
+          </template>
+          <NInputNumber v-model:value="model.avgval" placeholder="璇疯緭鍏ュ钩鍧囧��" class="w-full" />
+        </NFormItem>
+        <NFormItem label="SD鍊�" path="sdval">
+          <NInputNumber v-model:value="model.sdval" placeholder="璇疯緭鍏D鍊�" class="w-full" />
+        </NFormItem>
+        <NFormItem label="CV鍊�" path="cvval">
+          <NInputNumber v-model:value="model.cvval" placeholder="璇疯緭鍏V鍊�" class="w-full" />
+        </NFormItem>
+        <NFormItem label="CPK鍊�" path="cpkval">
+          <NInputNumber v-model:value="model.cpkval" placeholder="璇疯緭鍏PK鍊�" class="w-full" />
+        </NFormItem>
+        <NFormItem label="瓒呮爣鏁�" path="badval">
+          <NInputNumber v-model:value="model.badval" placeholder="璇疯緭鍏ヨ秴鏍囨暟" class="w-full" />
+        </NFormItem>
+        <NFormItem label="妫�楠屾棩鏈�" path="checkTime">
+          <NDatePicker
+            v-model:formatted-value="model.checkTime"
+            type="date"
+            value-format="yyyy-MM-dd"
+            clearable
+          />
+        </NFormItem>
+        <NFormItem label="鍒ゅ畾" path="judge">
+          <NInput v-model:value="model.judge" placeholder="璇疯緭鍏ュ垽瀹�" />
+        </NFormItem>
+        <NFormItem label="鍗曢」鍒ゅ畾" path="singlejudge">
+          <NInput v-model:value="model.singlejudge" placeholder="璇疯緭鍏ュ崟椤瑰垽瀹�" />
+        </NFormItem>
+        <NFormItem label="鎻忚堪" path="chkDes">
+          <NInput v-model:value="model.chkDes" placeholder="璇疯緭鍏ユ弿杩�" />
+        </NFormItem>
+        <NFormItem label="鐢熸垚鏄庣粏" path="generateDetails">
+          <NCheckbox v-model:checked="generateDetailsChecked" checked-value="1" unchecked-value="0" />
+        </NFormItem>
+      </NForm>
+      <template #footer>
+        <NSpace :size="16">
+          <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
+          <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
+        </NSpace>
+      </template>
+    </NDrawerContent>
+  </NDrawer>
+</template>
+
+<style scoped>
+.n-form-item-label {
+  white-space: pre-line;
+  line-height: 1.4;
+}
+</style>
diff --git a/ruoyi-plus-soybean/src/views/qm/matcheck/modules/matcheck-search.vue b/ruoyi-plus-soybean/src/views/qm/matcheck/modules/matcheck-search.vue
new file mode 100644
index 0000000..bc73db1
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/qm/matcheck/modules/matcheck-search.vue
@@ -0,0 +1,93 @@
+<script setup lang="ts">
+import { toRaw } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+  name: 'MatcheckSearch'
+});
+
+interface Emits {
+  (e: 'search'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+
+const model = defineModel<Api.Qm.MatcheckSearchParams>('model', { required: true });
+
+const defaultModel = jsonClone(toRaw(model.value));
+
+function resetModel() {
+  Object.assign(model.value, defaultModel);
+}
+
+async function reset() {
+  await restoreValidation();
+  resetModel();
+  emit('search');
+}
+
+async function search() {
+  await validate();
+  emit('search');
+}
+</script>
+
+<template>
+  <NCard :bordered="false" size="small" class="card-wrapper">
+    <NCollapse>
+      <NCollapseItem :title="$t('common.search')" name="qm-matcheck-search">
+        <NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
+          <NGrid responsive="screen" item-responsive>
+            <NFormItemGi span="24 s:12 m:6" label="鐗屽彿" label-width="auto" path="matCode" class="pr-24px">
+              <NInput v-model:value="model.matCode" placeholder="璇疯緭鍏ョ墝鍙�" />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="妫�楠屽憳" label-width="auto" path="checkName" class="pr-24px">
+              <NInput v-model:value="model.checkName" placeholder="璇疯緭鍏ユ楠屽憳" />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="妫�楠屾椂闂�" label-width="auto" path="checkTime" class="pr-24px">
+              <NDatePicker
+                v-model:formatted-value="model.checkTime"
+                type="datetime"
+                value-format="yyyy-MM-dd HH:mm:ss"
+                clearable
+              />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="澶嶆牳鍛�" label-width="auto" path="reviewName" class="pr-24px">
+              <NInput v-model:value="model.reviewName" placeholder="璇疯緭鍏ュ鏍稿憳" />
+            </NFormItemGi>
+            <NFormItemGi span="24 s:12 m:6" label="澶嶆牳鏃堕棿" label-width="auto" path="reviewTiem" class="pr-24px">
+              <NDatePicker
+                v-model:formatted-value="model.reviewTiem"
+                type="datetime"
+                value-format="yyyy-MM-dd HH:mm:ss"
+                clearable
+              />
+            </NFormItemGi>
+            <NFormItemGi :show-feedback="false" span="24" class="pr-24px">
+              <NSpace class="w-full" justify="end">
+                <NButton @click="reset">
+                  <template #icon>
+                    <icon-ic-round-refresh class="text-icon" />
+                  </template>
+                  {{ $t('common.reset') }}
+                </NButton>
+                <NButton type="primary" ghost @click="search">
+                  <template #icon>
+                    <icon-ic-round-search class="text-icon" />
+                  </template>
+                  {{ $t('common.search') }}
+                </NButton>
+              </NSpace>
+            </NFormItemGi>
+          </NGrid>
+        </NForm>
+      </NCollapseItem>
+    </NCollapse>
+  </NCard>
+</template>
+
+<style scoped></style>

--
Gitblit v1.9.3