From 06f6eb3b6159323a26e55cc15ef3000786931e24 Mon Sep 17 00:00:00 2001
From: zhuguifei <312353457@qq.com>
Date: 星期五, 13 三月 2026 13:14:14 +0800
Subject: [PATCH] feat(新增基础数据判断规程、以及判定规程明细):
---
ruoyi-plus-soybean/src/router/elegant/routes.ts | 9
.gitignore | 4
ruoyi-plus-soybean/src/views/qm/std/index.vue | 109 ++-
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmCheckitemService.java | 70 ++
ruoyi-plus-soybean/src/typings/api/qm.checkitem.api.d.ts | 88 +++
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmCheckitemMapper.java | 15
ruoyi-plus-soybean/src/views/qm/std/modules/std-sub-table.vue | 151 +++++
ruoyi-plus-soybean/src/service/api/qm/checkitem.ts | 45 +
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmCheckitemController.java | 114 ++++
ruoyi-plus-soybean/src/views/qm/checkitem/index.vue | 223 ++++++++
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmCheckitemVo.java | 130 ++++
ruoyi-plus-soybean/src/router/elegant/imports.ts | 1
ruoyi-plus-soybean/src/typings/elegant-router.d.ts | 2
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmCheckitemMapper.xml | 6
ruoyi-plus-soybean/src/views/qm/checkitem/modules/checkitem-operate-drawer.vue | 178 ++++++
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmCheckitemBo.java | 105 +++
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmCheckitemServiceImpl.java | 164 ++++++
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmCheckitem.java | 105 +++
ruoyi-plus-soybean/src/views/qm/checkitem/modules/checkitem-search.vue | 74 ++
ruoyi-plus-soybean/src/router/elegant/transform.ts | 1
20 files changed, 1,556 insertions(+), 38 deletions(-)
diff --git a/.gitignore b/.gitignore
index 37ef30b..28e2b8a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,6 @@
**/logs
**/target
**/.vscode
-**/.flattened-pom.xml
\ No newline at end of file
+**/.flattened-pom.xml
+RuoYi-Vue-Plus/.msp
+RuoYi-Vue-Plus/gzdams
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmCheckitemController.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmCheckitemController.java
new file mode 100644
index 0000000..f7f7c51
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmCheckitemController.java
@@ -0,0 +1,114 @@
+package org.dromara.qa.qm.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.qa.qm.domain.vo.QmCheckitemVo;
+import org.dromara.qa.qm.domain.bo.QmCheckitemBo;
+import org.dromara.qa.qm.service.IQmCheckitemService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 瑙勭▼妫�楠岄」鐩�
+ *
+ * @author zhuguifei
+ * @date 2026-03-12
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/qm/checkitem")
+public class QmCheckitemController extends BaseController {
+
+ private final IQmCheckitemService qmCheckitemService;
+
+ /**
+ * 鏌ヨ瑙勭▼妫�楠岄」鐩垪琛�
+ */
+ @SaCheckPermission("qm:checkitem:list")
+ @GetMapping("/list")
+ public TableDataInfo<QmCheckitemVo> list(QmCheckitemBo bo, PageQuery pageQuery) {
+ return qmCheckitemService.queryPageList(bo, pageQuery);
+ }
+
+ @SaCheckPermission("qm:checkitem:list")
+ @GetMapping("/tree")
+ public TableDataInfo<QmCheckitemVo> tree(@RequestParam @NotBlank(message = "stdCode涓嶈兘涓虹┖") String stdCode,
+ @RequestParam(required = false) Integer page,
+ @RequestParam(required = false) Integer rows) {
+ List<QmCheckitemVo> list = qmCheckitemService.queryTreeListByStdCode(stdCode);
+ return TableDataInfo.build(list);
+ }
+
+ /**
+ * 瀵煎嚭瑙勭▼妫�楠岄」鐩垪琛�
+ */
+ @SaCheckPermission("qm:checkitem:export")
+ @Log(title = "瑙勭▼妫�楠岄」鐩�", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(QmCheckitemBo bo, HttpServletResponse response) {
+ List<QmCheckitemVo> list = qmCheckitemService.queryList(bo);
+ ExcelUtil.exportExcel(list, "瑙勭▼妫�楠岄」鐩�", QmCheckitemVo.class, response);
+ }
+
+ /**
+ * 鑾峰彇瑙勭▼妫�楠岄」鐩缁嗕俊鎭�
+ *
+ * @param id 涓婚敭
+ */
+ @SaCheckPermission("qm:checkitem:query")
+ @GetMapping("/{id}")
+ public R<QmCheckitemVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+ @PathVariable String id) {
+ return R.ok(qmCheckitemService.queryById(id));
+ }
+
+ /**
+ * 鏂板瑙勭▼妫�楠岄」鐩�
+ */
+ @SaCheckPermission("qm:checkitem:add")
+ @Log(title = "瑙勭▼妫�楠岄」鐩�", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R<Void> add(@Validated(AddGroup.class) @RequestBody QmCheckitemBo bo) {
+ return toAjax(qmCheckitemService.insertByBo(bo));
+ }
+
+ /**
+ * 淇敼瑙勭▼妫�楠岄」鐩�
+ */
+ @SaCheckPermission("qm:checkitem:edit")
+ @Log(title = "瑙勭▼妫�楠岄」鐩�", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R<Void> edit(@Validated(EditGroup.class) @RequestBody QmCheckitemBo bo) {
+ return toAjax(qmCheckitemService.updateByBo(bo));
+ }
+
+ /**
+ * 鍒犻櫎瑙勭▼妫�楠岄」鐩�
+ *
+ * @param ids 涓婚敭涓�
+ */
+ @SaCheckPermission("qm:checkitem:remove")
+ @Log(title = "瑙勭▼妫�楠岄」鐩�", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+ @PathVariable String[] ids) {
+ return toAjax(qmCheckitemService.deleteWithValidByIds(List.of(ids), true));
+ }
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmCheckitem.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmCheckitem.java
new file mode 100644
index 0000000..b98ae97
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmCheckitem.java
@@ -0,0 +1,105 @@
+package org.dromara.qa.qm.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 瑙勭▼妫�楠岄」鐩璞� qm_checkitem
+ *
+ * @author zhuguifei
+ * @date 2026-03-12
+ */
+@Data
+@TableName("qm_checkitem")
+public class QmCheckitem {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 缂栫爜
+ */
+ @TableId(value = "id")
+ private String id;
+
+ /**
+ * 妫�楠岄」鐩唬鐮�
+ */
+ private String itemCode;
+
+ /**
+ * 妫�楠岄」鐩悕绉�
+ */
+ private String itemName;
+
+ /**
+ * 鍗曚綅
+ */
+ private String unit;
+
+ /**
+ * 鍚敤
+ */
+ private Long enable;
+
+ /**
+ * 鍒犻櫎
+ */
+ private Long del;
+
+ /**
+ * 妫�楠岄」鎻忚堪
+ */
+ private String itemDes;
+
+ /**
+ * 瑙勭▼浠g爜
+ */
+ private String stdCode;
+
+ /**
+ * 浠櫒鎻忚堪
+ */
+ private String instrumentDes;
+
+ /**
+ * 缂洪櫡浣嶇疆-澶栬鐢�
+ */
+ private String location;
+
+ /**
+ * 鍒咥,B,C,D鍥涗釜绾у埆
+ */
+ private String checkLevel;
+
+ /**
+ * 鏄惁鍚堟垚椤�
+ */
+ private Long ismix;
+
+ /**
+ * 鍏宠仈椤笽D
+ */
+ private String rid;
+
+ /**
+ * 绫诲埆 0:鎴愬搧 1杈呮枡
+ */
+ private Long category;
+
+ /**
+ * 浠櫒缂栫爜
+ */
+ private String instrumentCode;
+
+ /**
+ * 鍒嗗��
+ */
+ private Long score;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmCheckitemBo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmCheckitemBo.java
new file mode 100644
index 0000000..20900a2
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmCheckitemBo.java
@@ -0,0 +1,105 @@
+package org.dromara.qa.qm.domain.bo;
+
+import org.dromara.qa.qm.domain.QmCheckitem;
+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.*;
+
+/**
+ * 瑙勭▼妫�楠岄」鐩笟鍔″璞� qm_checkitem
+ *
+ * @author zhuguifei
+ * @date 2026-03-12
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = QmCheckitem.class, reverseConvertGenerate = false)
+public class QmCheckitemBo extends BaseEntity {
+
+ /**
+ * 缂栫爜
+ */
+ @NotBlank(message = "缂栫爜涓嶈兘涓虹┖", groups = { EditGroup.class })
+ private String id;
+
+ /**
+ * 妫�楠岄」鐩唬鐮�
+ */
+ private String itemCode;
+
+ /**
+ * 妫�楠岄」鐩悕绉�
+ */
+ private String itemName;
+
+ /**
+ * 鍗曚綅
+ */
+ private String unit;
+
+ /**
+ * 鍚敤
+ */
+ private Long enable;
+
+ /**
+ * 鍒犻櫎
+ */
+ private Long del;
+
+ /**
+ * 妫�楠岄」鎻忚堪
+ */
+ private String itemDes;
+
+ /**
+ * 瑙勭▼浠g爜
+ */
+ private String stdCode;
+
+ /**
+ * 浠櫒鎻忚堪
+ */
+ private String instrumentDes;
+
+ /**
+ * 缂洪櫡浣嶇疆-澶栬鐢�
+ */
+ private String location;
+
+ /**
+ * 鍒咥,B,C,D鍥涗釜绾у埆
+ */
+ private String checkLevel;
+
+ /**
+ * 鏄惁鍚堟垚椤�
+ */
+ private Long ismix;
+
+ /**
+ * 鍏宠仈椤笽D
+ */
+ private String rid;
+
+ /**
+ * 绫诲埆 0:鎴愬搧 1杈呮枡
+ */
+ private Long category;
+
+ /**
+ * 浠櫒缂栫爜
+ */
+ private String instrumentCode;
+
+ /**
+ * 鍒嗗��
+ */
+ private Long score;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmCheckitemVo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmCheckitemVo.java
new file mode 100644
index 0000000..3c8d5e4
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmCheckitemVo.java
@@ -0,0 +1,130 @@
+package org.dromara.qa.qm.domain.vo;
+
+import org.dromara.qa.qm.domain.QmCheckitem;
+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;
+import java.util.List;
+
+
+
+/**
+ * 瑙勭▼妫�楠岄」鐩鍥惧璞� qm_checkitem
+ *
+ * @author zhuguifei
+ * @date 2026-03-12
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = QmCheckitem.class)
+public class QmCheckitemVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 缂栫爜
+ */
+ @ExcelProperty(value = "缂栫爜")
+ private String id;
+
+ /**
+ * 妫�楠岄」鐩唬鐮�
+ */
+ @ExcelProperty(value = "妫�楠岄」鐩唬鐮�")
+ private String itemCode;
+
+ /**
+ * 妫�楠岄」鐩悕绉�
+ */
+ @ExcelProperty(value = "妫�楠岄」鐩悕绉�")
+ private String itemName;
+
+ /**
+ * 鍗曚綅
+ */
+ @ExcelProperty(value = "鍗曚綅")
+ private String unit;
+
+ /**
+ * 鍚敤
+ */
+ @ExcelProperty(value = "鍚敤")
+ private Long enable;
+
+ /**
+ * 鍒犻櫎
+ */
+ @ExcelProperty(value = "鍒犻櫎")
+ private Long del;
+
+ /**
+ * 妫�楠岄」鎻忚堪
+ */
+ @ExcelProperty(value = "妫�楠岄」鎻忚堪")
+ private String itemDes;
+
+ /**
+ * 瑙勭▼浠g爜
+ */
+ @ExcelProperty(value = "瑙勭▼浠g爜")
+ private String stdCode;
+
+ /**
+ * 浠櫒鎻忚堪
+ */
+ @ExcelProperty(value = "浠櫒鎻忚堪")
+ private String instrumentDes;
+
+ /**
+ * 缂洪櫡浣嶇疆-澶栬鐢�
+ */
+ @ExcelProperty(value = "缂洪櫡浣嶇疆-澶栬鐢�")
+ private String location;
+
+ /**
+ * 鍒咥,B,C,D鍥涗釜绾у埆
+ */
+ @ExcelProperty(value = "鍒咥,B,C,D鍥涗釜绾у埆")
+ private String checkLevel;
+
+ /**
+ * 鏄惁鍚堟垚椤�
+ */
+ @ExcelProperty(value = "鏄惁鍚堟垚椤�")
+ private Long ismix;
+
+ /**
+ * 鍏宠仈椤笽D
+ */
+ @ExcelProperty(value = "鍏宠仈椤笽D")
+ private String rid;
+
+ /**
+ * 绫诲埆 0:鎴愬搧 1杈呮枡
+ */
+ @ExcelProperty(value = "绫诲埆 0:鎴愬搧 1杈呮枡")
+ private Long category;
+
+ /**
+ * 浠櫒缂栫爜
+ */
+ @ExcelProperty(value = "浠櫒缂栫爜")
+ private String instrumentCode;
+
+ /**
+ * 鍒嗗��
+ */
+ @ExcelProperty(value = "鍒嗗��")
+ private Long score;
+
+ private List<QmCheckitemVo> children;
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmCheckitemMapper.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmCheckitemMapper.java
new file mode 100644
index 0000000..4994563
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmCheckitemMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.qa.qm.mapper;
+
+import org.dromara.qa.qm.domain.QmCheckitem;
+import org.dromara.qa.qm.domain.vo.QmCheckitemVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 瑙勭▼妫�楠岄」鐩甅apper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2026-03-12
+ */
+public interface QmCheckitemMapper extends BaseMapperPlus<QmCheckitem, QmCheckitemVo> {
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmCheckitemService.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmCheckitemService.java
new file mode 100644
index 0000000..c201b8b
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmCheckitemService.java
@@ -0,0 +1,70 @@
+package org.dromara.qa.qm.service;
+
+import org.dromara.qa.qm.domain.vo.QmCheckitemVo;
+import org.dromara.qa.qm.domain.bo.QmCheckitemBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 瑙勭▼妫�楠岄」鐩甋ervice鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2026-03-12
+ */
+public interface IQmCheckitemService {
+
+ /**
+ * 鏌ヨ瑙勭▼妫�楠岄」鐩�
+ *
+ * @param id 涓婚敭
+ * @return 瑙勭▼妫�楠岄」鐩�
+ */
+ QmCheckitemVo queryById(String id);
+
+ /**
+ * 鍒嗛〉鏌ヨ瑙勭▼妫�楠岄」鐩垪琛�
+ *
+ * @param bo 鏌ヨ鏉′欢
+ * @param pageQuery 鍒嗛〉鍙傛暟
+ * @return 瑙勭▼妫�楠岄」鐩垎椤靛垪琛�
+ */
+ TableDataInfo<QmCheckitemVo> queryPageList(QmCheckitemBo bo, PageQuery pageQuery);
+
+ /**
+ * 鏌ヨ绗﹀悎鏉′欢鐨勮绋嬫楠岄」鐩垪琛�
+ *
+ * @param bo 鏌ヨ鏉′欢
+ * @return 瑙勭▼妫�楠岄」鐩垪琛�
+ */
+ List<QmCheckitemVo> queryList(QmCheckitemBo bo);
+
+ List<QmCheckitemVo> queryTreeListByStdCode(String stdCode);
+
+ /**
+ * 鏂板瑙勭▼妫�楠岄」鐩�
+ *
+ * @param bo 瑙勭▼妫�楠岄」鐩�
+ * @return 鏄惁鏂板鎴愬姛
+ */
+ Boolean insertByBo(QmCheckitemBo bo);
+
+ /**
+ * 淇敼瑙勭▼妫�楠岄」鐩�
+ *
+ * @param bo 瑙勭▼妫�楠岄」鐩�
+ * @return 鏄惁淇敼鎴愬姛
+ */
+ Boolean updateByBo(QmCheckitemBo 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/qa/qm/service/impl/QmCheckitemServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmCheckitemServiceImpl.java
new file mode 100644
index 0000000..a8299aa
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmCheckitemServiceImpl.java
@@ -0,0 +1,164 @@
+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.QmCheckitemBo;
+import org.dromara.qa.qm.domain.vo.QmCheckitemVo;
+import org.dromara.qa.qm.domain.QmCheckitem;
+import org.dromara.qa.qm.mapper.QmCheckitemMapper;
+import org.dromara.qa.qm.service.IQmCheckitemService;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 瑙勭▼妫�楠岄」鐩甋ervice涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2026-03-12
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class QmCheckitemServiceImpl implements IQmCheckitemService {
+
+ private final QmCheckitemMapper baseMapper;
+
+ /**
+ * 鏌ヨ瑙勭▼妫�楠岄」鐩�
+ *
+ * @param id 涓婚敭
+ * @return 瑙勭▼妫�楠岄」鐩�
+ */
+ @Override
+ public QmCheckitemVo queryById(String id){
+ return baseMapper.selectVoById(id);
+ }
+
+ /**
+ * 鍒嗛〉鏌ヨ瑙勭▼妫�楠岄」鐩垪琛�
+ *
+ * @param bo 鏌ヨ鏉′欢
+ * @param pageQuery 鍒嗛〉鍙傛暟
+ * @return 瑙勭▼妫�楠岄」鐩垎椤靛垪琛�
+ */
+ @Override
+ public TableDataInfo<QmCheckitemVo> queryPageList(QmCheckitemBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper<QmCheckitem> lqw = buildQueryWrapper(bo);
+ Page<QmCheckitemVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(result);
+ }
+
+ /**
+ * 鏌ヨ绗﹀悎鏉′欢鐨勮绋嬫楠岄」鐩垪琛�
+ *
+ * @param bo 鏌ヨ鏉′欢
+ * @return 瑙勭▼妫�楠岄」鐩垪琛�
+ */
+ @Override
+ public List<QmCheckitemVo> queryList(QmCheckitemBo bo) {
+ LambdaQueryWrapper<QmCheckitem> lqw = buildQueryWrapper(bo);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ @Override
+ public List<QmCheckitemVo> queryTreeListByStdCode(String stdCode) {
+ List<QmCheckitemVo> roots = selectTreeNodes(stdCode, null);
+ for (QmCheckitemVo root : roots) {
+ List<QmCheckitemVo> children = selectTreeNodes(stdCode, root.getId());
+ for (QmCheckitemVo child : children) {
+ List<QmCheckitemVo> grandchildren = selectTreeNodes(stdCode, child.getId());
+ child.setChildren(grandchildren);
+ }
+ root.setChildren(children);
+ }
+ return roots;
+ }
+
+ private List<QmCheckitemVo> selectTreeNodes(String stdCode, String rid) {
+ if (StringUtils.isBlank(stdCode)) {
+ return new ArrayList<>();
+ }
+ LambdaQueryWrapper<QmCheckitem> lqw = Wrappers.lambdaQuery();
+ lqw.eq(QmCheckitem::getStdCode, stdCode);
+ lqw.ne(QmCheckitem::getDel, 1L);
+ if (rid == null) {
+ lqw.isNull(QmCheckitem::getRid);
+ } else {
+ lqw.eq(QmCheckitem::getRid, rid);
+ }
+ lqw.orderByAsc(QmCheckitem::getId);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper<QmCheckitem> buildQueryWrapper(QmCheckitemBo bo) {
+ Map<String, Object> params = bo.getParams();
+ LambdaQueryWrapper<QmCheckitem> lqw = Wrappers.lambdaQuery();
+ lqw.orderByAsc(QmCheckitem::getId);
+ lqw.like(StringUtils.isNotBlank(bo.getItemCode()), QmCheckitem::getItemCode, bo.getItemCode());
+ lqw.like(StringUtils.isNotBlank(bo.getItemName()), QmCheckitem::getItemName, bo.getItemName());
+ return lqw;
+ }
+
+ /**
+ * 鏂板瑙勭▼妫�楠岄」鐩�
+ *
+ * @param bo 瑙勭▼妫�楠岄」鐩�
+ * @return 鏄惁鏂板鎴愬姛
+ */
+ @Override
+ public Boolean insertByBo(QmCheckitemBo bo) {
+ QmCheckitem add = MapstructUtils.convert(bo, QmCheckitem.class);
+ validEntityBeforeSave(add);
+ boolean flag = baseMapper.insert(add) > 0;
+ if (flag) {
+ bo.setId(add.getId());
+ }
+ return flag;
+ }
+
+ /**
+ * 淇敼瑙勭▼妫�楠岄」鐩�
+ *
+ * @param bo 瑙勭▼妫�楠岄」鐩�
+ * @return 鏄惁淇敼鎴愬姛
+ */
+ @Override
+ public Boolean updateByBo(QmCheckitemBo bo) {
+ QmCheckitem update = MapstructUtils.convert(bo, QmCheckitem.class);
+ validEntityBeforeSave(update);
+ return baseMapper.updateById(update) > 0;
+ }
+
+ /**
+ * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+ */
+ private void validEntityBeforeSave(QmCheckitem 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/resources/mapper/qa/qm/QmCheckitemMapper.xml b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmCheckitemMapper.xml
new file mode 100644
index 0000000..b918fa2
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmCheckitemMapper.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.qa.qm.mapper.QmCheckitemMapper">
+</mapper>
diff --git a/ruoyi-plus-soybean/src/router/elegant/imports.ts b/ruoyi-plus-soybean/src/router/elegant/imports.ts
index 4d0ffc3..c268c52 100755
--- a/ruoyi-plus-soybean/src/router/elegant/imports.ts
+++ b/ruoyi-plus-soybean/src/router/elegant/imports.ts
@@ -38,6 +38,7 @@
monitor_online: () => import("@/views/monitor/online/index.vue"),
monitor_operlog: () => import("@/views/monitor/operlog/index.vue"),
qm_batch: () => import("@/views/qm/batch/index.vue"),
+ qm_checkitem: () => import("@/views/qm/checkitem/index.vue"),
qm_std: () => import("@/views/qm/std/index.vue"),
system_client: () => import("@/views/system/client/index.vue"),
system_config: () => import("@/views/system/config/index.vue"),
diff --git a/ruoyi-plus-soybean/src/router/elegant/routes.ts b/ruoyi-plus-soybean/src/router/elegant/routes.ts
index 35c99c3..28f3fb5 100755
--- a/ruoyi-plus-soybean/src/router/elegant/routes.ts
+++ b/ruoyi-plus-soybean/src/router/elegant/routes.ts
@@ -266,6 +266,15 @@
}
},
{
+ name: 'qm_checkitem',
+ path: '/qm/checkitem',
+ component: 'view.qm_checkitem',
+ meta: {
+ title: 'qm_checkitem',
+ i18nKey: 'route.qm_checkitem'
+ }
+ },
+ {
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 fac85aa..4c31383 100755
--- a/ruoyi-plus-soybean/src/router/elegant/transform.ts
+++ b/ruoyi-plus-soybean/src/router/elegant/transform.ts
@@ -193,6 +193,7 @@
"monitor_operlog": "/monitor/operlog",
"qm": "/qm",
"qm_batch": "/qm/batch",
+ "qm_checkitem": "/qm/checkitem",
"qm_std": "/qm/std",
"social-callback": "/social-callback",
"system": "/system",
diff --git a/ruoyi-plus-soybean/src/service/api/qm/checkitem.ts b/ruoyi-plus-soybean/src/service/api/qm/checkitem.ts
new file mode 100644
index 0000000..19497c5
--- /dev/null
+++ b/ruoyi-plus-soybean/src/service/api/qm/checkitem.ts
@@ -0,0 +1,45 @@
+import { request } from '@/service/request';
+
+/** 鑾峰彇瑙勭▼妫�楠岄」鐩垪琛� */
+export function fetchGetCheckitemList (params?: Api.Qm.CheckitemSearchParams) {
+ return request<Api.Qm.CheckitemList>({
+ url: '/qm/checkitem/list',
+ method: 'get',
+ params
+ });
+}
+
+/** 鑾峰彇瑙勭▼妫�楠岄」鐩垪琛� */
+export function fetchGetCheckitemTree (params?: Api.Qm.CheckitemSearchParams) {
+ return request<Api.Qm.CheckitemList>({
+ url: '/qm/checkitem/tree',
+ method: 'get',
+ params
+ });
+}
+
+/** 鏂板瑙勭▼妫�楠岄」鐩� */
+export function fetchCreateCheckitem (data: Api.Qm.CheckitemOperateParams) {
+ return request<boolean>({
+ url: '/qm/checkitem',
+ method: 'post',
+ data
+ });
+}
+
+/** 淇敼瑙勭▼妫�楠岄」鐩� */
+export function fetchUpdateCheckitem (data: Api.Qm.CheckitemOperateParams) {
+ return request<boolean>({
+ url: '/qm/checkitem',
+ method: 'put',
+ data
+ });
+}
+
+/** 鎵归噺鍒犻櫎瑙勭▼妫�楠岄」鐩� */
+export function fetchBatchDeleteCheckitem (ids: CommonType.IdType[]) {
+ return request<boolean>({
+ url: `/qm/checkitem/${ids.join(',')}`,
+ method: 'delete'
+ });
+}
diff --git a/ruoyi-plus-soybean/src/typings/api/qm.checkitem.api.d.ts b/ruoyi-plus-soybean/src/typings/api/qm.checkitem.api.d.ts
new file mode 100644
index 0000000..f92cc04
--- /dev/null
+++ b/ruoyi-plus-soybean/src/typings/api/qm.checkitem.api.d.ts
@@ -0,0 +1,88 @@
+/**
+ * Namespace Api
+ *
+ * All backend api type
+ */
+declare namespace Api {
+ /**
+ * namespace Qm
+ *
+ * backend api module: "Qm"
+ */
+ namespace Qm {
+ /** checkitem */
+ type Checkitem = Common.CommonRecord<{
+ /** 缂栫爜 */
+ id: CommonType.IdType;
+ /** 妫�楠岄」鐩唬鐮� */
+ itemCode: string;
+ /** 妫�楠岄」鐩悕绉� */
+ itemName: string;
+ /** 鍗曚綅 */
+ unit: string;
+ /** 鍚敤 */
+ enable: number;
+ /** 鍒犻櫎 */
+ del: number;
+ /** 妫�楠岄」鎻忚堪 */
+ itemDes: string;
+ /** 瑙勭▼浠g爜 */
+ stdCode: string;
+ /** 浠櫒鎻忚堪 */
+ instrumentDes: string;
+ /** 缂洪櫡浣嶇疆-澶栬鐢� */
+ location: string;
+ /** 鍒咥,B,C,D鍥涗釜绾у埆 */
+ checkLevel: string;
+ /** 鏄惁鍚堟垚椤� */
+ ismix: number;
+ /** 鍏宠仈椤笽D */
+ rid: CommonType.IdType;
+ /** 绫诲埆 0:鎴愬搧 1杈呮枡 */
+ category: number;
+ /** 浠櫒缂栫爜 */
+ instrumentCode: string;
+ /** 鍒嗗�� */
+ score: number;
+ /** 瀛愯妭鐐� */
+ children?: Api.Qm.Checkitem[];
+ }>;
+
+ /** checkitem search params */
+ type CheckitemSearchParams = CommonType.RecordNullable<
+ Pick<
+ Api.Qm.Checkitem,
+ | 'itemCode'
+ | 'itemName'
+ | 'stdCode'
+ > &
+ Api.Common.CommonSearchParams
+ >;
+
+ /** checkitem operate params */
+ type CheckitemOperateParams = CommonType.RecordNullable<
+ Pick<
+ Api.Qm.Checkitem,
+ | 'id'
+ | 'itemCode'
+ | 'itemName'
+ | 'unit'
+ | 'enable'
+ | 'del'
+ | 'itemDes'
+ | 'stdCode'
+ | 'instrumentDes'
+ | 'location'
+ | 'checkLevel'
+ | 'ismix'
+ | 'rid'
+ | 'category'
+ | 'instrumentCode'
+ | 'score'
+ >
+ >;
+
+ /** checkitem list */
+ type CheckitemList = Api.Common.PaginatingQueryRecord<Checkitem>;
+ }
+}
diff --git a/ruoyi-plus-soybean/src/typings/elegant-router.d.ts b/ruoyi-plus-soybean/src/typings/elegant-router.d.ts
index 013ab97..621aca8 100755
--- a/ruoyi-plus-soybean/src/typings/elegant-router.d.ts
+++ b/ruoyi-plus-soybean/src/typings/elegant-router.d.ts
@@ -47,6 +47,7 @@
"monitor_operlog": "/monitor/operlog";
"qm": "/qm";
"qm_batch": "/qm/batch";
+ "qm_checkitem": "/qm/checkitem";
"qm_std": "/qm/std";
"social-callback": "/social-callback";
"system": "/system";
@@ -157,6 +158,7 @@
| "monitor_online"
| "monitor_operlog"
| "qm_batch"
+ | "qm_checkitem"
| "qm_std"
| "system_client"
| "system_config"
diff --git a/ruoyi-plus-soybean/src/views/qm/checkitem/index.vue b/ruoyi-plus-soybean/src/views/qm/checkitem/index.vue
new file mode 100644
index 0000000..133ff75
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/qm/checkitem/index.vue
@@ -0,0 +1,223 @@
+<script setup lang="tsx">
+import { ref } from 'vue';
+import { NDivider } from 'naive-ui';
+import { fetchBatchDeleteCheckitem, fetchGetCheckitemList } from '@/service/api/qm/checkitem';
+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 CheckitemOperateDrawer from './modules/checkitem-operate-drawer.vue';
+import CheckitemSearch from './modules/checkitem-search.vue';
+
+defineOptions({
+ name: 'CheckitemList'
+});
+
+
+const appStore = useAppStore();
+const { download } = useDownload();
+const { hasAuth } = useAuth();
+
+const searchParams = ref<Api.Qm.CheckitemSearchParams>({
+ pageNum: 1,
+ pageSize: 10,
+ itemCode: null,
+ itemName: null,
+ params: {}
+});
+
+const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
+ useNaivePaginatedTable({
+ api: () => fetchGetCheckitemList(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: 'itemCode',
+ title: '椤圭洰浠g爜',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'itemName',
+ title: '椤圭洰鍚嶇О',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'location',
+ title: '浣嶇疆',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'instrumentDes',
+ title: '浠櫒鎻忚堪',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'itemDes',
+ title: '椤圭洰鎻忚堪',
+ align: 'center',
+ width: 200
+ },
+ {
+ key: 'ismix',
+ title: '鏄惁鍚堟垚椤�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'score',
+ title: '鍒嗗��',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'enable',
+ title: '鍚敤',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'operate',
+ title: $t('common.operate'),
+ align: 'center',
+ width: 130,
+ render: row => {
+ const divider = () => {
+ if (!hasAuth('qm:checkitem:edit') || !hasAuth('qm:checkitem:remove')) {
+ return null;
+ }
+ return <NDivider vertical />;
+ };
+
+ const editBtn = () => {
+ if (!hasAuth('qm:checkitem: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:checkitem: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 fetchBatchDeleteCheckitem(checkedRowKeys.value);
+ if (error) return;
+ onBatchDeleted();
+}
+
+async function handleDelete(id: CommonType.IdType) {
+ // request
+ const { error } = await fetchBatchDeleteCheckitem([id]);
+ if (error) return;
+ onDeleted();
+}
+
+function edit(id: CommonType.IdType) {
+ handleEdit(id);
+}
+
+function handleExport() {
+ download('/qm/checkitem/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">
+ <CheckitemSearch 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:checkitem:add')"
+ :show-delete="hasAuth('qm:checkitem:remove')"
+ :show-export="hasAuth('qm:checkitem: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"
+ />
+ <CheckitemOperateDrawer
+ 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/checkitem/modules/checkitem-operate-drawer.vue b/ruoyi-plus-soybean/src/views/qm/checkitem/modules/checkitem-operate-drawer.vue
new file mode 100644
index 0000000..54c4ccc
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/qm/checkitem/modules/checkitem-operate-drawer.vue
@@ -0,0 +1,178 @@
+<script setup lang="ts">
+import { computed, ref, watch } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { fetchCreateCheckitem, fetchUpdateCheckitem } from '@/service/api/qm/checkitem';
+import { useFormRules, useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+ name: 'CheckitemOperateDrawer'
+});
+
+interface Props {
+ /** the type of operation */
+ operateType: NaiveUI.TableOperateType;
+ /** the edit row data */
+ rowData?: Api.Qm.Checkitem | 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.Qm.CheckitemOperateParams;
+
+const model = ref<Model>(createDefaultModel());
+
+function createDefaultModel(): Model {
+ return {
+ id: '',
+ itemCode: '',
+ itemName: '',
+ unit: '',
+ enable: null,
+ del: null,
+ itemDes: '',
+ stdCode: '',
+ instrumentDes: '',
+ location: '',
+ checkLevel: '',
+ ismix: null,
+ rid: '',
+ category: null,
+ instrumentCode: '',
+ score: null
+ };
+}
+
+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));
+ }
+}
+
+function closeDrawer() {
+ visible.value = false;
+}
+
+async function handleSubmit() {
+ await validate();
+
+ const { id, itemCode, itemName, unit, enable, del, itemDes, stdCode, instrumentDes, location, checkLevel, ismix, rid, category, instrumentCode, score } = model.value;
+
+ // request
+ if (props.operateType === 'add') {
+ const { error } = await fetchCreateCheckitem({ itemCode, itemName, unit, enable, del, itemDes, stdCode, instrumentDes, location, checkLevel, ismix, rid, category, instrumentCode, score });
+ if (error) return;
+ }
+
+ if (props.operateType === 'edit') {
+ const { error } = await fetchUpdateCheckitem({ id, itemCode, itemName, unit, enable, del, itemDes, stdCode, instrumentDes, location, checkLevel, ismix, rid, category, instrumentCode, score });
+ if (error) return;
+ }
+
+ window.$message?.success($t('common.updateSuccess'));
+ closeDrawer();
+ emit('submitted');
+}
+
+watch(visible, () => {
+ if (visible.value) {
+ handleUpdateModelWhenEdit();
+ restoreValidation();
+ getTreeList();
+ }
+});
+</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="itemCode">
+ <NInput v-model:value="model.itemCode" placeholder="璇疯緭鍏ユ楠岄」鐩唬鐮�" />
+ </NFormItem>
+ <NFormItem label="妫�楠岄」鐩悕绉�" path="itemName">
+ <NInput v-model:value="model.itemName" placeholder="璇疯緭鍏ユ楠岄」鐩悕绉�" />
+ </NFormItem>
+ <NFormItem label="鍗曚綅" path="unit">
+ <NInput v-model:value="model.unit" 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="妫�楠岄」鎻忚堪" path="itemDes">
+ <NInput v-model:value="model.itemDes" placeholder="璇疯緭鍏ユ楠岄」鎻忚堪" />
+ </NFormItem>
+ <NFormItem label="瑙勭▼浠g爜" path="stdCode">
+ <NInput v-model:value="model.stdCode" placeholder="璇疯緭鍏ヨ绋嬩唬鐮�" />
+ </NFormItem>
+ <NFormItem label="浠櫒鎻忚堪" path="instrumentDes">
+ <NInput v-model:value="model.instrumentDes" placeholder="璇疯緭鍏ヤ华鍣ㄦ弿杩�" />
+ </NFormItem>
+ <NFormItem label="缂洪櫡浣嶇疆-澶栬鐢�" path="location">
+ <NInput v-model:value="model.location" placeholder="璇疯緭鍏ョ己闄蜂綅缃�-澶栬鐢�" />
+ </NFormItem>
+ <NFormItem label="鍒咥,B,C,D鍥涗釜绾у埆" path="checkLevel">
+ <NInput v-model:value="model.checkLevel" placeholder="璇疯緭鍏ュ垎A,B,C,D鍥涗釜绾у埆" />
+ </NFormItem>
+ <NFormItem label="鏄惁鍚堟垚椤�" path="ismix">
+ <NInput v-model:value="model.ismix" placeholder="璇疯緭鍏ユ槸鍚﹀悎鎴愰」" />
+ </NFormItem>
+ <NFormItem label="鍏宠仈椤笽D" path="rid">
+ <NInput v-model:value="model.rid" placeholder="璇疯緭鍏ュ叧鑱旈」ID" />
+ </NFormItem>
+ <NFormItem label="绫诲埆 0:鎴愬搧 1杈呮枡" path="category">
+ <NInput v-model:value="model.category" placeholder="璇疯緭鍏ョ被鍒� 0:鎴愬搧 1杈呮枡" />
+ </NFormItem>
+ <NFormItem label="浠櫒缂栫爜" path="instrumentCode">
+ <NInput v-model:value="model.instrumentCode" placeholder="璇疯緭鍏ヤ华鍣ㄧ紪鐮�" />
+ </NFormItem>
+ <NFormItem label="鍒嗗��" path="score">
+ <NInput v-model:value="model.score" placeholder="璇疯緭鍏ュ垎鍊�" />
+ </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/qm/checkitem/modules/checkitem-search.vue b/ruoyi-plus-soybean/src/views/qm/checkitem/modules/checkitem-search.vue
new file mode 100644
index 0000000..d940e0c
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/qm/checkitem/modules/checkitem-search.vue
@@ -0,0 +1,74 @@
+<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: 'CheckitemSearch'
+});
+
+interface Emits {
+ (e: 'search'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+
+const model = defineModel<Api.Qm.CheckitemSearchParams>('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-checkitem-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="itemCode" class="pr-24px">
+ <NInput v-model:value="model.itemCode" placeholder="璇疯緭鍏ユ楠岄」鐩唬鐮�" />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:6" label="妫�楠岄」鐩悕绉�" label-width="auto" path="itemName" class="pr-24px">
+ <NInput v-model:value="model.itemName" 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>
+ <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/std/index.vue b/ruoyi-plus-soybean/src/views/qm/std/index.vue
index f4f6b03..6eaee42 100644
--- a/ruoyi-plus-soybean/src/views/qm/std/index.vue
+++ b/ruoyi-plus-soybean/src/views/qm/std/index.vue
@@ -11,6 +11,7 @@
import ButtonIcon from '@/components/custom/button-icon.vue';
import StdOperateDrawer from './modules/std-operate-drawer.vue';
import StdSearch from './modules/std-search.vue';
+import StdSubTable from './modules/std-sub-table.vue';
defineOptions({
name: 'StdList'
@@ -20,6 +21,8 @@
const appStore = useAppStore();
const { download } = useDownload();
const { hasAuth } = useAuth();
+
+const selectedStdId = ref<CommonType.IdType | null>(null);
const searchParams = ref<Api.Qm.StdSearchParams>({
pageNum: 1,
@@ -76,7 +79,9 @@
minWidth: 120,
render: row => {
const v = String(row?.category ?? '');
- return v === '0' ? '鎴愬搧' : v === '1' ? '杈呮枡' : v;
+ if (v === '0') return '鎴愬搧';
+ if (v === '1') return '杈呮枡';
+ return v;
}
},
{
@@ -99,7 +104,9 @@
minWidth: 120,
render: row => {
const v = String(row?.enable ?? '');
- return v === '0' ? '鍋滅敤' : v === '1' ? '鍚敤' : v;
+ if (v === '0') return '鍋滅敤';
+ if (v === '1') return '鍚敤';
+ return v;
}
},
{
@@ -183,47 +190,75 @@
function handleExport() {
download('/qm/std/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;
+ selectedStdId.value = row.id;
+ },
+ style: 'cursor: pointer;'
+ };
+}
</script>
<template>
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
<StdSearch 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:std:add')"
- :show-delete="hasAuth('qm:std:remove')"
- :show-export="hasAuth('qm:std:export')"
- @add="handleAdd"
- @delete="handleBatchDelete"
- @export="handleExport"
- @refresh="getData"
- />
- </template>
- <NDataTable
- v-model:checked-row-keys="checkedRowKeys"
- :columns="columns"
- :data="data"
+ <div class="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"
- />
- <StdOperateDrawer
- v-model:visible="drawerVisible"
- :operate-type="operateType"
- :row-data="editingData"
- @submitted="getDataByPage"
- />
- </NCard>
+ class="card-wrapper flex-col-stretch 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:std:add')"
+ :show-delete="hasAuth('qm:std:remove')"
+ :show-export="hasAuth('qm:std: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"
+ />
+ <StdOperateDrawer
+ v-model:visible="drawerVisible"
+ :operate-type="operateType"
+ :row-data="editingData"
+ @submitted="getDataByPage"
+ />
+ </NCard>
+ <StdSubTable :std-id="selectedStdId" 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/std/modules/std-sub-table.vue b/ruoyi-plus-soybean/src/views/qm/std/modules/std-sub-table.vue
new file mode 100644
index 0000000..301a5c2
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/qm/std/modules/std-sub-table.vue
@@ -0,0 +1,151 @@
+<script setup lang="tsx">
+import { computed, ref, watch } from 'vue';
+import { useLoading } from '@sa/hooks';
+import { $t } from '@/locales';
+import { fetchGetCheckitemTree } from '@/service/api/qm/checkitem';
+import type { DataTableColumns, DataTableRowKey } from 'naive-ui';
+
+defineOptions({
+ name: 'StdSubTable'
+});
+
+interface Props {
+ stdId?: CommonType.IdType | null;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+ stdId: null
+});
+
+interface StdSubRow extends Api.Qm.Checkitem {
+ children?: StdSubRow[];
+}
+
+const { loading, startLoading, endLoading } = useLoading();
+const rows = ref<StdSubRow[]>([]);
+
+async function getSubList() {
+ if (!props.stdId) {
+ rows.value = [];
+ return;
+ }
+
+ startLoading();
+ try {
+ const { data, error } = await fetchGetCheckitemTree({
+ pageNum: 1,
+ pageSize: 9999,
+ stdCode: String(props.stdId)
+ });
+ if (error) {
+ rows.value = [];
+ return;
+ }
+
+ rows.value = data.rows;
+ } finally {
+ endLoading();
+ }
+}
+
+watch(
+ () => props.stdId,
+ async () => {
+ await getSubList();
+ },
+ { immediate: true }
+);
+
+const columns = computed<DataTableColumns<StdSubRow>>(() => [
+ {
+ key: 'index',
+ title: $t('common.index'),
+ align: 'center',
+ width: 56,
+ render: (_: any, index: number) => index + 1
+ },
+ {
+ key: 'itemName',
+ title: '椤圭洰鍚嶇О',
+ align: 'left',
+ width: 400,
+ tree: true
+ } as any,
+ {
+ key: 'itemCode',
+ title: '椤圭洰浠g爜',
+ align: 'center',
+ width: 180
+ },
+ {
+ key: 'unit',
+ title: '鍗曚綅',
+ align: 'center',
+ width: 80
+ },
+ {
+ key: 'enable',
+ title: '鍚敤',
+ align: 'center',
+ width: 72,
+ render: row => (String(row.enable) === '1' ? '鍚敤' : '鍋滅敤')
+ },
+ {
+ key: 'score',
+ title: '鍒嗗��',
+ align: 'center',
+ width: 80
+ },
+ {
+ key: 'itemDes',
+ title: '鎻忚堪',
+ align: 'center',
+ minWidth: 160
+ }
+]);
+
+function rowKey(row: StdSubRow): DataTableRowKey {
+ return String(row.id);
+}
+</script>
+
+<template>
+ <NCard
+ title="瑙勭▼鏄庣粏"
+ :bordered="false"
+ size="small"
+ class="flex-col-stretch card-wrapper"
+ :content-style="{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }"
+ >
+ <template #header-extra>
+ <span class="text-13px text-gray-500">{{ props.stdId ? `STD CODE锛�${props.stdId}` : '' }}</span>
+ </template>
+
+ <NSpin :show="loading" class="h-full" content-class="h-full">
+ <div v-if="!props.stdId" class="h-full flex-center text-gray-400">璇风偣鍑讳笂鏂硅〃鏍艰鏌ョ湅鏄庣粏</div>
+ <NDataTable
+ v-else
+ :columns="columns as any"
+ :data="rows"
+ size="small"
+ flex-height
+ children-key="children"
+ :row-key="rowKey"
+ default-expand-all
+ striped
+ style="height: 200px"
+ />
+ </NSpin>
+ </NCard>
+</template>
+
+<style scoped>
+:deep(.n-card__content) {
+ padding: 8px 12px;
+}
+
+:deep(.n-data-table-th),
+:deep(.n-data-table-td) {
+ padding: 4px 6px;
+}
+</style>
--
Gitblit v1.9.3