广丰卷烟厂数采质量分析系统
feat: 1.新增物料、物料类型、材料检验统计等表维护功能  2.完善判定依据-判断依据明细  3.新增判断依据、物料管理等字典翻译类  4.成品物料批次-原始数据维护页面
已添加43个文件
4970 ■■■■■ 文件已修改
RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/MatNameTranslationImpl.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmMatcheckController.java 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmMatcheck.java 184 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmMatcheckBo.java 183 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmMatcheckVo.java 255 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmMatcheckMapper.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmMatcheckService.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmMatcheckServiceImpl.java 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/controller/MdMatController.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/controller/MdMatTypeController.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/MdMat.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/MdMatType.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/bo/MdMatBo.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/bo/MdMatTypeBo.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/vo/MdMatTypeVo.java 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/domain/vo/MdMatVo.java 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/mapper/MdMatMapper.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/mapper/MdMatTypeMapper.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/IMdMatService.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/IMdMatTypeService.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/impl/MdMatServiceImpl.java 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/md/service/impl/MdMatTypeServiceImpl.java 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/test 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmMatcheckMapper.xml 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/md/MdMatMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/md/MdMatTypeMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/test 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/service/api/md/mat-type.ts 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/service/api/md/mat.ts 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/service/api/qm/matcheck.ts 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/typings/api/md.mat-type.api.d.ts 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/typings/api/md.mat.api.d.ts 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/typings/api/qm.matcheck.api.d.ts 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/md/mat-type/index.vue 241 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/md/mat-type/modules/mat-type-operate-drawer.vue 171 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/md/mat-type/modules/mat-type-search.vue 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/md/mat/index.vue 283 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/md/mat/modules/mat-operate-drawer.vue 184 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/md/mat/modules/mat-search.vue 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-sub-table.vue 414 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/matcheck/index.vue 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/matcheck/modules/matcheck-operate-drawer.vue 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/matcheck/modules/matcheck-search.vue 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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());
    }
}
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));
    }
}
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;
    /**
     * æ£€éªŒé¡¹ç›®COD
     */
    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-未上传mes   1-已上传
     */
    private String flag;
    /**
     * ä¸Šä¼ mes时间
     */
    private Date toMesTime;
    /**
     * å¤‡æ³¨
     */
    private String chkDes;
}
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;
    /**
     * æ£€éªŒé¡¹ç›®COD
     */
    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-未上传mes   1-已上传
     */
    private String flag;
    /**
     * ä¸Šä¼ mes时间
     */
    private Date toMesTime;
    /**
     * å¤‡æ³¨
     */
    private String chkDes;
}
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;
    /**
     * æ£€éªŒé¡¹ç›®COD
     */
    @ExcelProperty(value = "检验项目COD")
    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-未上传mes   1-已上传
     */
    @ExcelProperty(value = "0-未上传mes   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;
}
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;
/**
 * ææ–™æ£€éªŒç»Ÿè®¡Mapper接口
 *
 * @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);
}
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;
/**
 * ææ–™æ£€éªŒç»Ÿè®¡Service接口
 *
 * @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);
}
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;
/**
 * ææ–™æ£€éªŒç»Ÿè®¡Service业务层处理
 *
 * @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);
    }
}
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));
    }
}
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));
    }
}
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;
    /**
     * ç‰©æ–™ä»£ç 
     */
    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;
}
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;
}
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;
    /**
     * ç‰©æ–™ä»£ç 
     */
    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;
}
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;
}
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;
}
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;
    /**
     * ç‰©æ–™ä»£ç 
     */
    @ExcelProperty(value = "物料代码")
    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;
}
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> {
}
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> {
}
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);
}
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);
}
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();
    }
}
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;
    }
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/sc/test
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>
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>
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>
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/sc/test
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'
    });
}
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'
    });
}
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'
    });
}
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>;
    }
}
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;
            /** ç‰©æ–™ä»£ç  */
                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>;
    }
}
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;
            /** æ£€éªŒé¡¹ç›®COD */
                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-未上传mes 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 & {
                /** æ£€éªŒé¡¹ä¸‹æ‹‰ç­‰æŽ¥å£ä½¿ç”¨çš„判定规程 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;
        };
    }
}
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>
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="请输入mes编码" />
        </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>
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="请输入mes编码" />
            </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>
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: '物料代码',
      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>
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="物料代码" 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>
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="物料代码" 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>
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>
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>
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="请输入SD值" class="w-full" />
        </NFormItem>
        <NFormItem label="CV值" path="cvval">
          <NInputNumber v-model:value="model.cvval" placeholder="请输入CV值" class="w-full" />
        </NFormItem>
        <NFormItem label="CPK值" path="cpkval">
          <NInputNumber v-model:value="model.cpkval" placeholder="请输入CPK值" 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>
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>