广丰卷烟厂数采质量分析系统
zhuguifei
2026-03-20 3471290659516cf21db3211a9053daff5f283e03
feat: 基础数据仪器管理、判定依据、判定依据明细
已添加38个文件
已修改6个文件
3893 ■■■■■ 文件已修改
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/controller/MdInstrumentController.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/domain/MdInstrument.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/domain/bo/MdInstrumentBo.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/domain/vo/MdInstrumentVo.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/mapper/MdInstrumentMapper.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/service/IMdInstrumentService.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/service/impl/MdInstrumentServiceImpl.java 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmJudgeController.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmJudgeDetailsController.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmJudge.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmJudgeDetails.java 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmJudgeBo.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmJudgeDetailsBo.java 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeDetailsVo.java 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeVo.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmJudgeDetailsMapper.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmJudgeMapper.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmJudgeDetailsService.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmJudgeService.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmJudgeDetailsServiceImpl.java 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmJudgeServiceImpl.java 174 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/md/MdInstrumentMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmJudgeDetailsMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/.gitignore 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/router/elegant/imports.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/router/elegant/routes.ts 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/router/elegant/transform.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/service/api/md/instrument.ts 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/service/api/qm/judge-details.ts 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/service/api/qm/judge.ts 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/typings/api/md.instrument.api.d.ts 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/typings/api/qm.judge-details.api.d.ts 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/typings/api/qm.judge.api.d.ts 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/typings/elegant-router.d.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/md/instrument/index.vue 247 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/md/instrument/modules/instrument-operate-drawer.vue 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/md/instrument/modules/instrument-search.vue 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/checkitem/modules/checkitem-operate-drawer.vue 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/judge-details/index.vue 262 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-operate-drawer.vue 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-search.vue 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/judge/index.vue 323 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/judge/modules/judge-operate-drawer.vue 212 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/judge/modules/judge-search.vue 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/controller/MdInstrumentController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
package org.dromara.qa.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.qa.md.domain.vo.MdInstrumentVo;
import org.dromara.qa.md.domain.bo.MdInstrumentBo;
import org.dromara.qa.md.service.IMdInstrumentService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
 * æµ‹é‡ä»ªå™¨
 *
 * @author zhuguifei
 * @date 2026-03-18
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/md/instrument")
public class MdInstrumentController extends BaseController {
    private final IMdInstrumentService mdInstrumentService;
    /**
     * æŸ¥è¯¢æµ‹é‡ä»ªå™¨åˆ—表
     */
    @SaCheckPermission("md:instrument:list")
    @GetMapping("/list")
    public TableDataInfo<MdInstrumentVo> list(MdInstrumentBo bo, PageQuery pageQuery) {
        return mdInstrumentService.queryPageList(bo, pageQuery);
    }
    /**
     * å¯¼å‡ºæµ‹é‡ä»ªå™¨åˆ—表
     */
    @SaCheckPermission("md:instrument:export")
    @Log(title = "测量仪器", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(MdInstrumentBo bo, HttpServletResponse response) {
        List<MdInstrumentVo> list = mdInstrumentService.queryList(bo);
        ExcelUtil.exportExcel(list, "测量仪器", MdInstrumentVo.class, response);
    }
    /**
     * èŽ·å–æµ‹é‡ä»ªå™¨è¯¦ç»†ä¿¡æ¯
     *
     * @param id ä¸»é”®
     */
    @SaCheckPermission("md:instrument:query")
    @GetMapping("/{id}")
    public R<MdInstrumentVo> getInfo(@NotNull(message = "主键不能为空")
                                     @PathVariable String id) {
        return R.ok(mdInstrumentService.queryById(id));
    }
    /**
     * æ–°å¢žæµ‹é‡ä»ªå™¨
     */
    @SaCheckPermission("md:instrument:add")
    @Log(title = "测量仪器", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping()
    public R<Void> add(@Validated(AddGroup.class) @RequestBody MdInstrumentBo bo) {
        return toAjax(mdInstrumentService.insertByBo(bo));
    }
    /**
     * ä¿®æ”¹æµ‹é‡ä»ªå™¨
     */
    @SaCheckPermission("md:instrument:edit")
    @Log(title = "测量仪器", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping()
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody MdInstrumentBo bo) {
        return toAjax(mdInstrumentService.updateByBo(bo));
    }
    /**
     * åˆ é™¤æµ‹é‡ä»ªå™¨
     *
     * @param ids ä¸»é”®ä¸²
     */
    @SaCheckPermission("md:instrument:remove")
    @Log(title = "测量仪器", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
                          @PathVariable String[] ids) {
        return toAjax(mdInstrumentService.deleteWithValidByIds(List.of(ids), true));
    }
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/domain/MdInstrument.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
package org.dromara.qa.md.domain;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
 * æµ‹é‡ä»ªå™¨å¯¹è±¡ md_instrument
 *
 * @author zhuguifei
 * @date 2026-03-18
 */
@Data
@TableName("md_instrument")
public class MdInstrument {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ç¼–码
     */
    private String id;
    /**
     * ä»ªå™¨ä»£ç 
     */
    private String instrumentCode;
    /**
     * ä»ªå™¨åç§°
     */
    private String instrumentName;
    /**
     * æŽ¥å£æ ‡å‡†
     */
    private String ifStd;
    /**
     * æŽ¥å£æ ‡å‡†ä»£ç 
     */
    private Long isc;
    /**
     * æ‰€å±žè½¦é—´
     */
    private String workShop;
    /**
     * å¯ç”¨
     */
    private Long enable;
    /**
     * åˆ é™¤
     */
    private Long del;
    /**
     * å¤‡æ³¨
     */
    private String instrumentDes;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/domain/bo/MdInstrumentBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
package org.dromara.qa.md.domain.bo;
import org.dromara.qa.md.domain.MdInstrument;
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.*;
/**
 * æµ‹é‡ä»ªå™¨ä¸šåŠ¡å¯¹è±¡ md_instrument
 *
 * @author zhuguifei
 * @date 2026-03-18
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = MdInstrument.class, reverseConvertGenerate = false)
public class MdInstrumentBo extends BaseEntity {
    /**
     * ç¼–码
     */
    private String id;
    /**
     * ä»ªå™¨ä»£ç 
     */
    private String instrumentCode;
    /**
     * ä»ªå™¨åç§°
     */
    private String instrumentName;
    /**
     * æŽ¥å£æ ‡å‡†
     */
    private String ifStd;
    /**
     * æŽ¥å£æ ‡å‡†ä»£ç 
     */
    private Long isc;
    /**
     * æ‰€å±žè½¦é—´
     */
    private String workShop;
    /**
     * å¯ç”¨
     */
    private Long enable;
    /**
     * åˆ é™¤
     */
    private Long del;
    /**
     * å¤‡æ³¨
     */
    private String instrumentDes;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/domain/vo/MdInstrumentVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,87 @@
package org.dromara.qa.md.domain.vo;
import org.dromara.qa.md.domain.MdInstrument;
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_instrument
 *
 * @author zhuguifei
 * @date 2026-03-18
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = MdInstrument.class)
public class MdInstrumentVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ç¼–码
     */
    @ExcelProperty(value = "编码")
    private String id;
    /**
     * ä»ªå™¨ä»£ç 
     */
    @ExcelProperty(value = "仪器代码")
    private String instrumentCode;
    /**
     * ä»ªå™¨åç§°
     */
    @ExcelProperty(value = "仪器名称")
    private String instrumentName;
    /**
     * æŽ¥å£æ ‡å‡†
     */
    @ExcelProperty(value = "接口标准")
    private String ifStd;
    /**
     * æŽ¥å£æ ‡å‡†ä»£ç 
     */
    @ExcelProperty(value = "接口标准代码")
    private Long isc;
    /**
     * æ‰€å±žè½¦é—´
     */
    @ExcelProperty(value = "所属车间")
    private String workShop;
    /**
     * å¯ç”¨
     */
    @ExcelProperty(value = "启用", converter = ExcelDictConvert.class)
    @ExcelDictFormat(dictType = "sys_yes_no")
    private Long enable;
    /**
     * åˆ é™¤
     */
    @ExcelProperty(value = "删除")
    private Long del;
    /**
     * å¤‡æ³¨
     */
    @ExcelProperty(value = "备注")
    private String instrumentDes;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/mapper/MdInstrumentMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
package org.dromara.qa.md.mapper;
import org.dromara.qa.md.domain.MdInstrument;
import org.dromara.qa.md.domain.vo.MdInstrumentVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * æµ‹é‡ä»ªå™¨Mapper接口
 *
 * @author zhuguifei
 * @date 2026-03-18
 */
public interface MdInstrumentMapper extends BaseMapperPlus<MdInstrument, MdInstrumentVo> {
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/md/service/IMdInstrumentService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
package org.dromara.qa.md.service;
import org.dromara.qa.md.domain.vo.MdInstrumentVo;
import org.dromara.qa.md.domain.bo.MdInstrumentBo;
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-03-18
 */
public interface IMdInstrumentService {
    /**
     * æŸ¥è¯¢æµ‹é‡ä»ªå™¨
     *
     * @param id ä¸»é”®
     * @return æµ‹é‡ä»ªå™¨
     */
    MdInstrumentVo queryById(String id);
    /**
     * åˆ†é¡µæŸ¥è¯¢æµ‹é‡ä»ªå™¨åˆ—表
     *
     * @param bo        æŸ¥è¯¢æ¡ä»¶
     * @param pageQuery åˆ†é¡µå‚æ•°
     * @return æµ‹é‡ä»ªå™¨åˆ†é¡µåˆ—表
     */
    TableDataInfo<MdInstrumentVo> queryPageList(MdInstrumentBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢ç¬¦åˆæ¡ä»¶çš„æµ‹é‡ä»ªå™¨åˆ—表
     *
     * @param bo æŸ¥è¯¢æ¡ä»¶
     * @return æµ‹é‡ä»ªå™¨åˆ—表
     */
    List<MdInstrumentVo> queryList(MdInstrumentBo bo);
    /**
     * æ–°å¢žæµ‹é‡ä»ªå™¨
     *
     * @param bo æµ‹é‡ä»ªå™¨
     * @return æ˜¯å¦æ–°å¢žæˆåŠŸ
     */
    Boolean insertByBo(MdInstrumentBo bo);
    /**
     * ä¿®æ”¹æµ‹é‡ä»ªå™¨
     *
     * @param bo æµ‹é‡ä»ªå™¨
     * @return æ˜¯å¦ä¿®æ”¹æˆåŠŸ
     */
    Boolean updateByBo(MdInstrumentBo 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/qa/md/service/impl/MdInstrumentServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,133 @@
package org.dromara.qa.md.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.md.domain.bo.MdInstrumentBo;
import org.dromara.qa.md.domain.vo.MdInstrumentVo;
import org.dromara.qa.md.domain.MdInstrument;
import org.dromara.qa.md.mapper.MdInstrumentMapper;
import org.dromara.qa.md.service.IMdInstrumentService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
 * æµ‹é‡ä»ªå™¨Service业务层处理
 *
 * @author zhuguifei
 * @date 2026-03-18
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class MdInstrumentServiceImpl implements IMdInstrumentService {
    private final MdInstrumentMapper baseMapper;
    /**
     * æŸ¥è¯¢æµ‹é‡ä»ªå™¨
     *
     * @param id ä¸»é”®
     * @return æµ‹é‡ä»ªå™¨
     */
    @Override
    public MdInstrumentVo queryById(String id){
        return baseMapper.selectVoById(id);
    }
    /**
     * åˆ†é¡µæŸ¥è¯¢æµ‹é‡ä»ªå™¨åˆ—表
     *
     * @param bo        æŸ¥è¯¢æ¡ä»¶
     * @param pageQuery åˆ†é¡µå‚æ•°
     * @return æµ‹é‡ä»ªå™¨åˆ†é¡µåˆ—表
     */
    @Override
    public TableDataInfo<MdInstrumentVo> queryPageList(MdInstrumentBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<MdInstrument> lqw = buildQueryWrapper(bo);
        Page<MdInstrumentVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * æŸ¥è¯¢ç¬¦åˆæ¡ä»¶çš„æµ‹é‡ä»ªå™¨åˆ—表
     *
     * @param bo æŸ¥è¯¢æ¡ä»¶
     * @return æµ‹é‡ä»ªå™¨åˆ—表
     */
    @Override
    public List<MdInstrumentVo> queryList(MdInstrumentBo bo) {
        LambdaQueryWrapper<MdInstrument> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    private LambdaQueryWrapper<MdInstrument> buildQueryWrapper(MdInstrumentBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<MdInstrument> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getInstrumentCode()), MdInstrument::getInstrumentCode, bo.getInstrumentCode());
        lqw.like(StringUtils.isNotBlank(bo.getInstrumentName()), MdInstrument::getInstrumentName, bo.getInstrumentName());
        lqw.eq(bo.getEnable() != null, MdInstrument::getEnable, bo.getEnable());
        return lqw;
    }
    /**
     * æ–°å¢žæµ‹é‡ä»ªå™¨
     *
     * @param bo æµ‹é‡ä»ªå™¨
     * @return æ˜¯å¦æ–°å¢žæˆåŠŸ
     */
    @Override
    public Boolean insertByBo(MdInstrumentBo bo) {
        MdInstrument add = MapstructUtils.convert(bo, MdInstrument.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }
    /**
     * ä¿®æ”¹æµ‹é‡ä»ªå™¨
     *
     * @param bo æµ‹é‡ä»ªå™¨
     * @return æ˜¯å¦ä¿®æ”¹æˆåŠŸ
     */
    @Override
    public Boolean updateByBo(MdInstrumentBo bo) {
        MdInstrument update = MapstructUtils.convert(bo, MdInstrument.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(MdInstrument 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/qa/qm/controller/QmJudgeController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
package org.dromara.qa.qm.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.qa.qm.domain.vo.QmJudgeVo;
import org.dromara.qa.qm.domain.bo.QmJudgeBo;
import org.dromara.qa.qm.service.IQmJudgeService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
 * åˆ¤å®šä¾æ®
 *
 * @author zhuguifei
 * @date 2026-03-18
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/qm/judge")
public class QmJudgeController extends BaseController {
    private final IQmJudgeService qmJudgeService;
    /**
     * æŸ¥è¯¢åˆ¤å®šä¾æ®åˆ—表
     */
    @SaCheckPermission("qm:judge:list")
    @GetMapping("/list")
    public TableDataInfo<QmJudgeVo> list(QmJudgeBo bo, PageQuery pageQuery) {
        return qmJudgeService.queryPageList(bo, pageQuery);
    }
    /**
     * å¯¼å‡ºåˆ¤å®šä¾æ®åˆ—表
     */
    @SaCheckPermission("qm:judge:export")
    @Log(title = "判定依据", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(QmJudgeBo bo, HttpServletResponse response) {
        List<QmJudgeVo> list = qmJudgeService.queryList(bo);
        ExcelUtil.exportExcel(list, "判定依据", QmJudgeVo.class, response);
    }
    /**
     * èŽ·å–åˆ¤å®šä¾æ®è¯¦ç»†ä¿¡æ¯
     *
     * @param id ä¸»é”®
     */
    @SaCheckPermission("qm:judge:query")
    @GetMapping("/{id}")
    public R<QmJudgeVo> getInfo(@NotNull(message = "主键不能为空")
                                     @PathVariable String id) {
        return R.ok(qmJudgeService.queryById(id));
    }
    /**
     * æ–°å¢žåˆ¤å®šä¾æ®
     */
    @SaCheckPermission("qm:judge:add")
    @Log(title = "判定依据", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping()
    public R<Void> add(@Validated(AddGroup.class) @RequestBody QmJudgeBo bo) {
        return toAjax(qmJudgeService.insertByBo(bo));
    }
    /**
     * ä¿®æ”¹åˆ¤å®šä¾æ®
     */
    @SaCheckPermission("qm:judge:edit")
    @Log(title = "判定依据", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping()
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody QmJudgeBo bo) {
        return toAjax(qmJudgeService.updateByBo(bo));
    }
    /**
     * åˆ é™¤åˆ¤å®šä¾æ®
     *
     * @param ids ä¸»é”®ä¸²
     */
    @SaCheckPermission("qm:judge:remove")
    @Log(title = "判定依据", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
                          @PathVariable String[] ids) {
        return toAjax(qmJudgeService.deleteWithValidByIds(List.of(ids), true));
    }
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmJudgeDetailsController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
package org.dromara.qa.qm.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.qa.qm.domain.vo.QmJudgeDetailsVo;
import org.dromara.qa.qm.domain.bo.QmJudgeDetailsBo;
import org.dromara.qa.qm.service.IQmJudgeDetailsService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
 * åˆ¤å®šæ¨¡æ¿æ˜Žç»†
 *
 * @author æœ±æ¡‚飞
 * @date 2026-03-20
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/qm/judgeDetails")
public class QmJudgeDetailsController extends BaseController {
    private final IQmJudgeDetailsService qmJudgeDetailsService;
    /**
     * æŸ¥è¯¢åˆ¤å®šæ¨¡æ¿æ˜Žç»†åˆ—表
     */
    @SaCheckPermission("qm:judgeDetails:list")
    @GetMapping("/list")
    public TableDataInfo<QmJudgeDetailsVo> list(QmJudgeDetailsBo bo, PageQuery pageQuery) {
        return qmJudgeDetailsService.queryPageList(bo, pageQuery);
    }
    /**
     * å¯¼å‡ºåˆ¤å®šæ¨¡æ¿æ˜Žç»†åˆ—表
     */
    @SaCheckPermission("qm:judgeDetails:export")
    @Log(title = "判定模板明细", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(QmJudgeDetailsBo bo, HttpServletResponse response) {
        List<QmJudgeDetailsVo> list = qmJudgeDetailsService.queryList(bo);
        ExcelUtil.exportExcel(list, "判定模板明细", QmJudgeDetailsVo.class, response);
    }
    /**
     * èŽ·å–åˆ¤å®šæ¨¡æ¿æ˜Žç»†è¯¦ç»†ä¿¡æ¯
     *
     * @param id ä¸»é”®
     */
    @SaCheckPermission("qm:judgeDetails:query")
    @GetMapping("/{id}")
    public R<QmJudgeDetailsVo> getInfo(@NotNull(message = "主键不能为空")
                                     @PathVariable String id) {
        return R.ok(qmJudgeDetailsService.queryById(id));
    }
    /**
     * æ–°å¢žåˆ¤å®šæ¨¡æ¿æ˜Žç»†
     */
    @SaCheckPermission("qm:judgeDetails:add")
    @Log(title = "判定模板明细", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping()
    public R<Void> add(@Validated(AddGroup.class) @RequestBody QmJudgeDetailsBo bo) {
        return toAjax(qmJudgeDetailsService.insertByBo(bo));
    }
    /**
     * ä¿®æ”¹åˆ¤å®šæ¨¡æ¿æ˜Žç»†
     */
    @SaCheckPermission("qm:judgeDetails:edit")
    @Log(title = "判定模板明细", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping()
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody QmJudgeDetailsBo bo) {
        return toAjax(qmJudgeDetailsService.updateByBo(bo));
    }
    /**
     * åˆ é™¤åˆ¤å®šæ¨¡æ¿æ˜Žç»†
     *
     * @param ids ä¸»é”®ä¸²
     */
    @SaCheckPermission("qm:judgeDetails:remove")
    @Log(title = "判定模板明细", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
                          @PathVariable String[] ids) {
        return toAjax(qmJudgeDetailsService.deleteWithValidByIds(List.of(ids), true));
    }
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmJudge.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@
package org.dromara.qa.qm.domain;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
 * åˆ¤å®šä¾æ®å¯¹è±¡ qm_judge
 *
 * @author zhuguifei
 * @date 2026-03-18
 */
@Data
@TableName("qm_judge")
public class QmJudge {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ç¼–码
     */
    private String id;
    /**
     * ç‰©æ–™ç‰Œå·ä»£ç 
     */
    private String matCode;
    /**
     * ç‰©æ–™ç‰Œå·
     */
    private String matName;
    /**
     * ç‰ˆæœ¬å·
     */
    @Version
    private Long version;
    /**
     * çŠ¶æ€
     */
    private Long status;
    /**
     * åˆ¤å®šè§„程COD
     */
    private String stdCod;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    private Date cdate;
    /**
     * ç”Ÿæ•ˆäºº/操作人员
     */
    private String oper;
    /**
     * å¤‡æ³¨
     */
    private String des;
    /**
     * ç‰©æ–™ç±»åž‹
     */
    private Long category;
    /**
     * è¾…料类型编码
     */
    private String typeCode;
    /**
     * è¾…料类型名称
     */
    private String typeName;
    /**
     * åˆ¤å®šåç§°
     */
    private String judgeName;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmJudgeDetails.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,100 @@
package org.dromara.qa.qm.domain;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
 * åˆ¤å®šæ¨¡æ¿æ˜Žç»†å¯¹è±¡ qm_judge_details
 *
 * @author æœ±æ¡‚飞
 * @date 2026-03-20
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("qm_judge_details")
public class QmJudgeDetails extends BaseEntity {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ç¼–码
     */
    private String id;
    /**
     * åˆ¤å®šä¸»æ ‡è¯†
     */
    private String judgeId;
    /**
     * åˆ¤å®šé¡¹ITEM
     */
    private String itemCod;
    /**
     * åˆ¤å®šé¡¹NAME
     */
    private String itemName;
    /**
     * æ ‡å‡†å€¼
     */
    private Long value3;
    /**
     * åˆ¤å®šå€¼1
     */
    private Long value1;
    /**
     * åˆ¤å®šå€¼2
     */
    private Long value2;
    /**
     * ç¼ºé™·ä½ç½®
     */
    private String location;
    /**
     * åˆ¤å®šçº§åˆ« (A,B,C,D)
     */
    private String cls;
    /**
     * åˆ†å€¼æ ‡å‡† (扣分标准,得分标准),比如不合格一次扣多少分
     */
    private Long stdscore;
    /**
     * æ ‡è®°æ­¤é¡¹æ˜¯å¦ä¸ºåˆæˆé¡¹ç›®ï¼Œæ¯”如外观,实际上关联了很多子项目
     */
    private Long ismix;
    /**
     * è‹¥æ­¤å­—段有UUID值,表明它可能为其他项目的子项,比如“空头”,它为烟支外观项目的子项
     */
    private String rid;
    /**
     * èŒƒå›´-备用
     */
    private Long category;
    /**
     * å¤‡æ³¨
     */
    private String decisionDes;
    /**
     * ä¿®æ”¹äºº
     */
    private String updateUser;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmJudgeBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
package org.dromara.qa.qm.domain.bo;
import org.dromara.qa.qm.domain.QmJudge;
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;
/**
 * åˆ¤å®šä¾æ®ä¸šåŠ¡å¯¹è±¡ qm_judge
 *
 * @author zhuguifei
 * @date 2026-03-18
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = QmJudge.class, reverseConvertGenerate = false)
public class QmJudgeBo extends BaseEntity {
    private String id;
    /**
     * ç‰©æ–™ç‰Œå·ä»£ç 
     */
    private String matCode;
    /**
     * ç‰©æ–™ç‰Œå·
     */
    private String matName;
    /**
     * çŠ¶æ€
     */
    private Long status;
    /**
     * åˆ¤å®šè§„程COD
     */
    private String stdCod;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    private Date cdate;
    /**
     * ç”Ÿæ•ˆäºº/操作人员
     */
    private String oper;
    /**
     * å¤‡æ³¨
     */
    private String des;
    /**
     * ç‰©æ–™ç±»åž‹
     */
    private Long category;
    /**
     * è¾…料类型编码
     */
    private String typeCode;
    /**
     * è¾…料类型名称
     */
    private String typeName;
    /**
     * åˆ¤å®šåç§°
     */
    private String judgeName;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmJudgeDetailsBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,99 @@
package org.dromara.qa.qm.domain.bo;
import org.dromara.qa.qm.domain.QmJudgeDetails;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
 * åˆ¤å®šæ¨¡æ¿æ˜Žç»†ä¸šåŠ¡å¯¹è±¡ qm_judge_details
 *
 * @author æœ±æ¡‚飞
 * @date 2026-03-20
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = QmJudgeDetails.class, reverseConvertGenerate = false)
public class QmJudgeDetailsBo extends BaseEntity {
    /**
     * ç¼–码
     */
    private String id;
    /**
     * åˆ¤å®šä¸»æ ‡è¯†
     */
    private String judgeId;
    /**
     * åˆ¤å®šé¡¹ITEM
     */
    private String itemCod;
    /**
     * åˆ¤å®šé¡¹NAME
     */
    private String itemName;
    /**
     * æ ‡å‡†å€¼
     */
    private Long value3;
    /**
     * åˆ¤å®šå€¼1
     */
    private Long value1;
    /**
     * åˆ¤å®šå€¼2
     */
    private Long value2;
    /**
     * ç¼ºé™·ä½ç½®
     */
    private String location;
    /**
     * åˆ¤å®šçº§åˆ« (A,B,C,D)
     */
    private String cls;
    /**
     * åˆ†å€¼æ ‡å‡† (扣分标准,得分标准),比如不合格一次扣多少分
     */
    private Long stdscore;
    /**
     * æ ‡è®°æ­¤é¡¹æ˜¯å¦ä¸ºåˆæˆé¡¹ç›®ï¼Œæ¯”如外观,实际上关联了很多子项目
     */
    private Long ismix;
    /**
     * è‹¥æ­¤å­—段有UUID值,表明它可能为其他项目的子项,比如“空头”,它为烟支外观项目的子项
     */
    private String rid;
    /**
     * èŒƒå›´-备用
     */
    private Long category;
    /**
     * å¤‡æ³¨
     */
    private String decisionDes;
    /**
     * ä¿®æ”¹äºº
     */
    private String updateUser;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeDetailsVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,116 @@
package org.dromara.qa.qm.domain.vo;
import org.dromara.qa.qm.domain.QmJudgeDetails;
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;
/**
 * åˆ¤å®šæ¨¡æ¿æ˜Žç»†è§†å›¾å¯¹è±¡ qm_judge_details
 *
 * @author æœ±æ¡‚飞
 * @date 2026-03-20
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = QmJudgeDetails.class)
public class QmJudgeDetailsVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * åˆ¤å®šä¸»æ ‡è¯†
     */
    @ExcelProperty(value = "判定主标识")
    private String judgeId;
    /**
     * åˆ¤å®šé¡¹ITEM
     */
    @ExcelProperty(value = "判定项ITEM")
    private String itemCod;
    /**
     * åˆ¤å®šé¡¹NAME
     */
    @ExcelProperty(value = "判定项NAME")
    private String itemName;
    /**
     * æ ‡å‡†å€¼
     */
    @ExcelProperty(value = "标准值")
    private Long value3;
    /**
     * åˆ¤å®šå€¼1
     */
    @ExcelProperty(value = "判定值1")
    private Long value1;
    /**
     * åˆ¤å®šå€¼2
     */
    @ExcelProperty(value = "判定值2")
    private Long value2;
    /**
     * ç¼ºé™·ä½ç½®
     */
    @ExcelProperty(value = "缺陷位置")
    private String location;
    /**
     * åˆ¤å®šçº§åˆ« (A,B,C,D)
     */
    @ExcelProperty(value = "判定级别 (A,B,C,D)")
    private String cls;
    /**
     * åˆ†å€¼æ ‡å‡† (扣分标准,得分标准),比如不合格一次扣多少分
     */
    @ExcelProperty(value = "分值标准 (扣分标准,得分标准),比如不合格一次扣多少分")
    private Long stdscore;
    /**
     * æ ‡è®°æ­¤é¡¹æ˜¯å¦ä¸ºåˆæˆé¡¹ç›®ï¼Œæ¯”如外观,实际上关联了很多子项目
     */
    @ExcelProperty(value = "标记此项是否为合成项目,比如外观,实际上关联了很多子项目")
    private Long ismix;
    /**
     * è‹¥æ­¤å­—段有UUID值,表明它可能为其他项目的子项,比如“空头”,它为烟支外观项目的子项
     */
    @ExcelProperty(value = "若此字段有UUID值,表明它可能为其他项目的子项,比如“空头”,它为烟支外观项目的子项")
    private String rid;
    /**
     * èŒƒå›´-备用
     */
    @ExcelProperty(value = "范围-备用")
    private Long category;
    /**
     * å¤‡æ³¨
     */
    @ExcelProperty(value = "备注")
    private String decisionDes;
    /**
     * ä¿®æ”¹äºº
     */
    @ExcelProperty(value = "修改人")
    private String updateUser;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmJudgeVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,114 @@
package org.dromara.qa.qm.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.qa.qm.domain.QmJudge;
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;
/**
 * åˆ¤å®šä¾æ®è§†å›¾å¯¹è±¡ qm_judge
 *
 * @author zhuguifei
 * @date 2026-03-18
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = QmJudge.class)
public class QmJudgeVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ç¼–码
     */
    @ExcelProperty(value = "编码")
    private String id;
    /**
     * ç‰©æ–™ç‰Œå·ä»£ç 
     */
    @ExcelProperty(value = "物料牌号代码")
    private String matCode;
    /**
     * ç‰©æ–™ç‰Œå·
     */
    @ExcelProperty(value = "物料牌号")
    private String matName;
    /**
     * çŠ¶æ€
     */
    @ExcelProperty(value = "状态")
    private Long status;
    /**
     * åˆ¤å®šè§„程COD
     */
    @ExcelProperty(value = "判定规程COD")
    private String stdCod;
    /**
     * åˆ¤å®šè§„程名称
     */
    @ExcelProperty(value = "判定规程名称")
    private String stdName;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    @ExcelProperty(value = "创建时间")
    private Date cdate;
    /**
     * ç”Ÿæ•ˆäºº/操作人员
     */
    @ExcelProperty(value = "生效人/操作人员")
    private String oper;
    /**
     * å¤‡æ³¨
     */
    @ExcelProperty(value = "备注")
    private String des;
    /**
     * ç‰©æ–™ç±»åž‹
     */
    @ExcelProperty(value = "物料类型")
    private Long category;
    /**
     * è¾…料类型编码
     */
    @ExcelProperty(value = "辅料类型编码")
    private String typeCode;
    /**
     * è¾…料类型名称
     */
    @ExcelProperty(value = "辅料类型名称")
    private String typeName;
    /**
     * åˆ¤å®šåç§°
     */
    @ExcelProperty(value = "判定名称")
    private String judgeName;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmJudgeDetailsMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
package org.dromara.qa.qm.mapper;
import org.dromara.qa.qm.domain.QmJudgeDetails;
import org.dromara.qa.qm.domain.vo.QmJudgeDetailsVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * åˆ¤å®šæ¨¡æ¿æ˜Žç»†Mapper接口
 *
 * @author æœ±æ¡‚飞
 * @date 2026-03-20
 */
public interface QmJudgeDetailsMapper extends BaseMapperPlus<QmJudgeDetails, QmJudgeDetailsVo> {
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmJudgeMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
package org.dromara.qa.qm.mapper;
import org.dromara.qa.qm.domain.QmJudge;
import org.dromara.qa.qm.domain.vo.QmJudgeVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * åˆ¤å®šä¾æ®Mapper接口
 *
 * @author zhuguifei
 * @date 2026-03-18
 */
public interface QmJudgeMapper extends BaseMapperPlus<QmJudge, QmJudgeVo> {
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmJudgeDetailsService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
package org.dromara.qa.qm.service;
import org.dromara.qa.qm.domain.vo.QmJudgeDetailsVo;
import org.dromara.qa.qm.domain.bo.QmJudgeDetailsBo;
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 æœ±æ¡‚飞
 * @date 2026-03-20
 */
public interface IQmJudgeDetailsService {
    /**
     * æŸ¥è¯¢åˆ¤å®šæ¨¡æ¿æ˜Žç»†
     *
     * @param id ä¸»é”®
     * @return åˆ¤å®šæ¨¡æ¿æ˜Žç»†
     */
    QmJudgeDetailsVo queryById(String id);
    /**
     * åˆ†é¡µæŸ¥è¯¢åˆ¤å®šæ¨¡æ¿æ˜Žç»†åˆ—表
     *
     * @param bo        æŸ¥è¯¢æ¡ä»¶
     * @param pageQuery åˆ†é¡µå‚æ•°
     * @return åˆ¤å®šæ¨¡æ¿æ˜Žç»†åˆ†é¡µåˆ—表
     */
    TableDataInfo<QmJudgeDetailsVo> queryPageList(QmJudgeDetailsBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢ç¬¦åˆæ¡ä»¶çš„判定模板明细列表
     *
     * @param bo æŸ¥è¯¢æ¡ä»¶
     * @return åˆ¤å®šæ¨¡æ¿æ˜Žç»†åˆ—表
     */
    List<QmJudgeDetailsVo> queryList(QmJudgeDetailsBo bo);
    /**
     * æ–°å¢žåˆ¤å®šæ¨¡æ¿æ˜Žç»†
     *
     * @param bo åˆ¤å®šæ¨¡æ¿æ˜Žç»†
     * @return æ˜¯å¦æ–°å¢žæˆåŠŸ
     */
    Boolean insertByBo(QmJudgeDetailsBo bo);
    /**
     * ä¿®æ”¹åˆ¤å®šæ¨¡æ¿æ˜Žç»†
     *
     * @param bo åˆ¤å®šæ¨¡æ¿æ˜Žç»†
     * @return æ˜¯å¦ä¿®æ”¹æˆåŠŸ
     */
    Boolean updateByBo(QmJudgeDetailsBo 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/qa/qm/service/IQmJudgeService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
package org.dromara.qa.qm.service;
import org.dromara.qa.qm.domain.vo.QmJudgeVo;
import org.dromara.qa.qm.domain.bo.QmJudgeBo;
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-03-18
 */
public interface IQmJudgeService {
    /**
     * æŸ¥è¯¢åˆ¤å®šä¾æ®
     *
     * @param id ä¸»é”®
     * @return åˆ¤å®šä¾æ®
     */
    QmJudgeVo queryById(String id);
    /**
     * åˆ†é¡µæŸ¥è¯¢åˆ¤å®šä¾æ®åˆ—表
     *
     * @param bo        æŸ¥è¯¢æ¡ä»¶
     * @param pageQuery åˆ†é¡µå‚æ•°
     * @return åˆ¤å®šä¾æ®åˆ†é¡µåˆ—表
     */
    TableDataInfo<QmJudgeVo> queryPageList(QmJudgeBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢ç¬¦åˆæ¡ä»¶çš„判定依据列表
     *
     * @param bo æŸ¥è¯¢æ¡ä»¶
     * @return åˆ¤å®šä¾æ®åˆ—表
     */
    List<QmJudgeVo> queryList(QmJudgeBo bo);
    /**
     * æ–°å¢žåˆ¤å®šä¾æ®
     *
     * @param bo åˆ¤å®šä¾æ®
     * @return æ˜¯å¦æ–°å¢žæˆåŠŸ
     */
    Boolean insertByBo(QmJudgeBo bo);
    /**
     * ä¿®æ”¹åˆ¤å®šä¾æ®
     *
     * @param bo åˆ¤å®šä¾æ®
     * @return æ˜¯å¦ä¿®æ”¹æˆåŠŸ
     */
    Boolean updateByBo(QmJudgeBo 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/qa/qm/service/impl/QmJudgeDetailsServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,135 @@
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.QmJudgeDetailsBo;
import org.dromara.qa.qm.domain.vo.QmJudgeDetailsVo;
import org.dromara.qa.qm.domain.QmJudgeDetails;
import org.dromara.qa.qm.mapper.QmJudgeDetailsMapper;
import org.dromara.qa.qm.service.IQmJudgeDetailsService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
 * åˆ¤å®šæ¨¡æ¿æ˜Žç»†Service业务层处理
 *
 * @author æœ±æ¡‚飞
 * @date 2026-03-20
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class QmJudgeDetailsServiceImpl implements IQmJudgeDetailsService {
    private final QmJudgeDetailsMapper baseMapper;
    /**
     * æŸ¥è¯¢åˆ¤å®šæ¨¡æ¿æ˜Žç»†
     *
     * @param id ä¸»é”®
     * @return åˆ¤å®šæ¨¡æ¿æ˜Žç»†
     */
    @Override
    public QmJudgeDetailsVo queryById(String id){
        return baseMapper.selectVoById(id);
    }
    /**
     * åˆ†é¡µæŸ¥è¯¢åˆ¤å®šæ¨¡æ¿æ˜Žç»†åˆ—表
     *
     * @param bo        æŸ¥è¯¢æ¡ä»¶
     * @param pageQuery åˆ†é¡µå‚æ•°
     * @return åˆ¤å®šæ¨¡æ¿æ˜Žç»†åˆ†é¡µåˆ—表
     */
    @Override
    public TableDataInfo<QmJudgeDetailsVo> queryPageList(QmJudgeDetailsBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<QmJudgeDetails> lqw = buildQueryWrapper(bo);
        Page<QmJudgeDetailsVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * æŸ¥è¯¢ç¬¦åˆæ¡ä»¶çš„判定模板明细列表
     *
     * @param bo æŸ¥è¯¢æ¡ä»¶
     * @return åˆ¤å®šæ¨¡æ¿æ˜Žç»†åˆ—表
     */
    @Override
    public List<QmJudgeDetailsVo> queryList(QmJudgeDetailsBo bo) {
        LambdaQueryWrapper<QmJudgeDetails> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    private LambdaQueryWrapper<QmJudgeDetails> buildQueryWrapper(QmJudgeDetailsBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<QmJudgeDetails> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getJudgeId()), QmJudgeDetails::getJudgeId, bo.getJudgeId());
        lqw.eq(StringUtils.isNotBlank(bo.getItemCod()), QmJudgeDetails::getItemCod, bo.getItemCod());
        lqw.like(StringUtils.isNotBlank(bo.getItemName()), QmJudgeDetails::getItemName, bo.getItemName());
        lqw.eq(StringUtils.isNotBlank(bo.getCls()), QmJudgeDetails::getCls, bo.getCls());
        lqw.eq(bo.getIsmix() != null, QmJudgeDetails::getIsmix, bo.getIsmix());
        return lqw;
    }
    /**
     * æ–°å¢žåˆ¤å®šæ¨¡æ¿æ˜Žç»†
     *
     * @param bo åˆ¤å®šæ¨¡æ¿æ˜Žç»†
     * @return æ˜¯å¦æ–°å¢žæˆåŠŸ
     */
    @Override
    public Boolean insertByBo(QmJudgeDetailsBo bo) {
        QmJudgeDetails add = MapstructUtils.convert(bo, QmJudgeDetails.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }
    /**
     * ä¿®æ”¹åˆ¤å®šæ¨¡æ¿æ˜Žç»†
     *
     * @param bo åˆ¤å®šæ¨¡æ¿æ˜Žç»†
     * @return æ˜¯å¦ä¿®æ”¹æˆåŠŸ
     */
    @Override
    public Boolean updateByBo(QmJudgeDetailsBo bo) {
        QmJudgeDetails update = MapstructUtils.convert(bo, QmJudgeDetails.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(QmJudgeDetails 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/qa/qm/service/impl/QmJudgeServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,174 @@
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.dromara.qa.qm.domain.QmStd;
import org.springframework.stereotype.Service;
import org.dromara.qa.qm.domain.bo.QmJudgeBo;
import org.dromara.qa.qm.domain.vo.QmJudgeVo;
import org.dromara.qa.qm.domain.QmJudge;
import org.dromara.qa.qm.mapper.QmJudgeMapper;
import org.dromara.qa.qm.service.IQmJudgeService;
import org.dromara.qa.qm.service.IQmStdService;
import org.dromara.qa.qm.mapper.QmStdMapper;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.HashMap;
/**
 * åˆ¤å®šä¾æ®Service业务层处理
 *
 * @author zhuguifei
 * @date 2026-03-18
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class QmJudgeServiceImpl implements IQmJudgeService {
    private final QmJudgeMapper baseMapper;
    private final QmStdMapper qmStdMapper;
    /**
     * æŸ¥è¯¢åˆ¤å®šä¾æ®
     *
     * @param id ä¸»é”®
     * @return åˆ¤å®šä¾æ®
     */
    @Override
    public QmJudgeVo queryById(String id){
        return baseMapper.selectVoById(id);
    }
    /**
     * åˆ†é¡µæŸ¥è¯¢åˆ¤å®šä¾æ®åˆ—表
     *
     * @param bo        æŸ¥è¯¢æ¡ä»¶
     * @param pageQuery åˆ†é¡µå‚æ•°
     * @return åˆ¤å®šä¾æ®åˆ†é¡µåˆ—表
     */
    @Override
    public TableDataInfo<QmJudgeVo> queryPageList(QmJudgeBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<QmJudge> lqw = buildQueryWrapper(bo);
        Page<QmJudgeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        queryQmStd(result);
        return TableDataInfo.build(result);
    }
    private void queryQmStd(Page<QmJudgeVo> result) {
        if (result == null || result.getRecords() == null || result.getRecords().isEmpty()) {
            return;
        }
        List<QmJudgeVo> records = result.getRecords();
        // 1. Collect all unique stdCode values
        Set<String> stdCodes = records.stream()
            .map(QmJudgeVo::getStdCod)
            .filter(StringUtils::isNotBlank)
            .collect(Collectors.toSet());
        if (stdCodes.isEmpty()) {
            return;
        }
        // 2. Query QmStd entities based on the collected stdCode values
        LambdaQueryWrapper<QmStd> stdLqw = Wrappers.lambdaQuery();
        stdLqw.in(QmStd::getId, stdCodes);
        List<QmStd> qmStds = qmStdMapper.selectList(stdLqw);
        // 3. Create a map from stdCode to stdName for easy lookup
        Map<String, String> stdCodeToNameMap = qmStds.stream()
            .collect(Collectors.toMap(QmStd::getId, QmStd::getStdName, (oldValue, newValue) -> oldValue));
        // 4. Populate stdName for each QmJudgeVo
        records.forEach(judgeVo ->
            judgeVo.setStdName(stdCodeToNameMap.getOrDefault(judgeVo.getStdCod(), null))
        );
    }
    /**
     * æŸ¥è¯¢ç¬¦åˆæ¡ä»¶çš„判定依据列表
     *
     * @param bo æŸ¥è¯¢æ¡ä»¶
     * @return åˆ¤å®šä¾æ®åˆ—表
     */
    @Override
    public List<QmJudgeVo> queryList(QmJudgeBo bo) {
        LambdaQueryWrapper<QmJudge> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    private LambdaQueryWrapper<QmJudge> buildQueryWrapper(QmJudgeBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<QmJudge> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getMatCode()), QmJudge::getMatCode, bo.getMatCode());
        lqw.like(StringUtils.isNotBlank(bo.getMatName()), QmJudge::getMatName, bo.getMatName());
        lqw.like(StringUtils.isNotBlank(bo.getJudgeName()), QmJudge::getJudgeName, bo.getJudgeName());
        lqw.eq(bo.getStatus()!=null,QmJudge::getStatus, bo.getStatus());
        lqw.eq(bo.getCategory()!=null,QmJudge::getCategory, bo.getCategory());
        return lqw;
    }
    /**
     * æ–°å¢žåˆ¤å®šä¾æ®
     *
     * @param bo åˆ¤å®šä¾æ®
     * @return æ˜¯å¦æ–°å¢žæˆåŠŸ
     */
    @Override
    public Boolean insertByBo(QmJudgeBo bo) {
        QmJudge add = MapstructUtils.convert(bo, QmJudge.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }
    /**
     * ä¿®æ”¹åˆ¤å®šä¾æ®
     *
     * @param bo åˆ¤å®šä¾æ®
     * @return æ˜¯å¦ä¿®æ”¹æˆåŠŸ
     */
    @Override
    public Boolean updateByBo(QmJudgeBo bo) {
        QmJudge update = MapstructUtils.convert(bo, QmJudge.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(QmJudge 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/resources/mapper/qa/md/MdInstrumentMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.qa.md.mapper.MdInstrumentMapper">
</mapper>
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmJudgeDetailsMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.qa.qm.mapper.QmJudgeDetailsMapper">
</mapper>
ruoyi-plus-soybean/.gitignore
@@ -33,3 +33,5 @@
yarn.lock
.VSCodeCounter
/pms/
ruoyi-plus-soybean/src/router/elegant/imports.ts
@@ -32,12 +32,15 @@
  demo_demo: () => import("@/views/demo/demo/index.vue"),
  demo_tree: () => import("@/views/demo/tree/index.vue"),
  home: () => import("@/views/home/index.vue"),
  md_instrument: () => import("@/views/md/instrument/index.vue"),
  md_shift: () => import("@/views/md/shift/index.vue"),
  monitor_cache: () => import("@/views/monitor/cache/index.vue"),
  monitor_logininfor: () => import("@/views/monitor/logininfor/index.vue"),
  monitor_online: () => import("@/views/monitor/online/index.vue"),
  monitor_operlog: () => import("@/views/monitor/operlog/index.vue"),
  qm_batch: () => import("@/views/qm/batch/index.vue"),
  "qm_judge-details": () => import("@/views/qm/judge-details/index.vue"),
  qm_judge: () => import("@/views/qm/judge/index.vue"),
  qm_std: () => import("@/views/qm/std/index.vue"),
  report_demo: () => import("@/views/report/demo/index.vue"),
  "report_silk-storage-output": () => import("@/views/report/silk-storage-output/index.vue"),
ruoyi-plus-soybean/src/router/elegant/routes.ts
@@ -190,6 +190,15 @@
    },
    children: [
      {
        name: 'md_instrument',
        path: '/md/instrument',
        component: 'view.md_instrument',
        meta: {
          title: 'md_instrument',
          i18nKey: 'route.md_instrument'
        }
      },
      {
        name: 'md_shift',
        path: '/md/shift',
        component: 'view.md_shift',
@@ -266,6 +275,24 @@
        }
      },
      {
        name: 'qm_judge',
        path: '/qm/judge',
        component: 'view.qm_judge',
        meta: {
          title: 'qm_judge',
          i18nKey: 'route.qm_judge'
        }
      },
      {
        name: 'qm_judge-details',
        path: '/qm/judge-details',
        component: 'view.qm_judge-details',
        meta: {
          title: 'qm_judge-details',
          i18nKey: 'route.qm_judge-details'
        }
      },
      {
        name: 'qm_std',
        path: '/qm/std',
        component: 'view.qm_std',
ruoyi-plus-soybean/src/router/elegant/transform.ts
@@ -185,6 +185,7 @@
  "iframe-page": "/iframe-page/:url",
  "login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?",
  "md": "/md",
  "md_instrument": "/md/instrument",
  "md_shift": "/md/shift",
  "monitor": "/monitor",
  "monitor_cache": "/monitor/cache",
@@ -193,6 +194,8 @@
  "monitor_operlog": "/monitor/operlog",
  "qm": "/qm",
  "qm_batch": "/qm/batch",
  "qm_judge": "/qm/judge",
  "qm_judge-details": "/qm/judge-details",
  "qm_std": "/qm/std",
  "report": "/report",
  "report_demo": "/report/demo",
ruoyi-plus-soybean/src/service/api/md/instrument.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
import { request } from '@/service/request';
/** èŽ·å–æµ‹é‡ä»ªå™¨åˆ—è¡¨ */
export function fetchGetInstrumentList (params?: Api.Md.InstrumentSearchParams) {
    return request<Api.Md.InstrumentList>({
        url: '/md/instrument/list',
        method: 'get',
        params
    });
}
/** æ–°å¢žæµ‹é‡ä»ªå™¨ */
export function fetchCreateInstrument (data: Api.Md.InstrumentOperateParams) {
    return request<boolean>({
        url: '/md/instrument',
        method: 'post',
        data
    });
}
/** ä¿®æ”¹æµ‹é‡ä»ªå™¨ */
export function fetchUpdateInstrument (data: Api.Md.InstrumentOperateParams) {
    return request<boolean>({
        url: '/md/instrument',
        method: 'put',
        data
    });
}
/** æ‰¹é‡åˆ é™¤æµ‹é‡ä»ªå™¨ */
export function fetchBatchDeleteInstrument (ids: CommonType.IdType[]) {
    return request<boolean>({
        url: `/md/instrument/${ids.join(',')}`,
        method: 'delete'
    });
}
ruoyi-plus-soybean/src/service/api/qm/judge-details.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
import { request } from '@/service/request';
/** èŽ·å–åˆ¤å®šæ¨¡æ¿æ˜Žç»†åˆ—è¡¨ */
export function fetchGetJudgeDetailsList (params?: Api.Qm.JudgeDetailsSearchParams) {
    return request<Api.Qm.JudgeDetailsList>({
        url: '/qm/judgeDetails/list',
        method: 'get',
        params
    });
}
/** æ–°å¢žåˆ¤å®šæ¨¡æ¿æ˜Žç»† */
export function fetchCreateJudgeDetails (data: Api.Qm.JudgeDetailsOperateParams) {
    return request<boolean>({
        url: '/qm/judgeDetails',
        method: 'post',
        data
    });
}
/** ä¿®æ”¹åˆ¤å®šæ¨¡æ¿æ˜Žç»† */
export function fetchUpdateJudgeDetails (data: Api.Qm.JudgeDetailsOperateParams) {
    return request<boolean>({
        url: '/qm/judgeDetails',
        method: 'put',
        data
    });
}
/** æ‰¹é‡åˆ é™¤åˆ¤å®šæ¨¡æ¿æ˜Žç»† */
export function fetchBatchDeleteJudgeDetails (ids: CommonType.IdType[]) {
    return request<boolean>({
        url: `/qm/judgeDetails/${ids.join(',')}`,
        method: 'delete'
    });
}
ruoyi-plus-soybean/src/service/api/qm/judge.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
import { request } from '@/service/request';
/** èŽ·å–åˆ¤å®šä¾æ®åˆ—è¡¨ */
export function fetchGetJudgeList (params?: Api.Qm.JudgeSearchParams) {
    return request<Api.Qm.JudgeList>({
        url: '/qm/judge/list',
        method: 'get',
        params
    });
}
/** æ–°å¢žåˆ¤å®šä¾æ® */
export function fetchCreateJudge (data: Api.Qm.JudgeOperateParams) {
    return request<boolean>({
        url: '/qm/judge',
        method: 'post',
        data
    });
}
/** ä¿®æ”¹åˆ¤å®šä¾æ® */
export function fetchUpdateJudge (data: Api.Qm.JudgeOperateParams) {
    return request<boolean>({
        url: '/qm/judge',
        method: 'put',
        data
    });
}
/** æ‰¹é‡åˆ é™¤åˆ¤å®šä¾æ® */
export function fetchBatchDeleteJudge (ids: CommonType.IdType[]) {
    return request<boolean>({
        url: `/qm/judge/${ids.join(',')}`,
        method: 'delete'
    });
}
ruoyi-plus-soybean/src/typings/api/md.instrument.api.d.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
/**
 * Namespace Api
 *
 * All backend api type
 */
declare namespace Api {
    /**
     * namespace Md
     *
     * backend api module: "Md"
     */
    namespace Md {
        /** instrument */
        type Instrument = Common.CommonRecord<{
            /** ç¼–码 */
                id: CommonType.IdType;
            /** ä»ªå™¨ä»£ç  */
                instrumentCode: string;
            /** ä»ªå™¨åç§° */
                instrumentName: string;
            /** æŽ¥å£æ ‡å‡† */
                ifStd: string;
            /** æŽ¥å£æ ‡å‡†ä»£ç  */
                isc: number;
            /** æ‰€å±žè½¦é—´ */
                workShop: string;
            /** å¯ç”¨ */
                enable: number;
            /** åˆ é™¤ */
                del: number;
            /** å¤‡æ³¨ */
                instrumentDes: string;
        }>;
        /** instrument search params */
        type InstrumentSearchParams = CommonType.RecordNullable<
            Pick<
                Api.Md.Instrument,
                        | 'instrumentCode'
                        | 'instrumentName'
                        | 'enable'
            > &
            Api.Common.CommonSearchParams
        >;
        /** instrument operate params */
        type InstrumentOperateParams = CommonType.RecordNullable<
            Pick<
                Api.Md.Instrument,
                        | 'id'
                        | 'instrumentCode'
                        | 'instrumentName'
                        | 'ifStd'
                        | 'isc'
                        | 'workShop'
                        | 'enable'
                        | 'del'
                        | 'instrumentDes'
            >
        >;
        /** instrument list */
        type InstrumentList = Api.Common.PaginatingQueryRecord<Instrument>;
    }
}
ruoyi-plus-soybean/src/typings/api/qm.judge-details.api.d.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,85 @@
/**
 * Namespace Api
 *
 * All backend api type
 */
declare namespace Api {
    /**
     * namespace Qm
     *
     * backend api module: "Qm"
     */
    namespace Qm {
        /** judge details */
        type JudgeDetails = Common.CommonRecord<{
            /** ç¼–码 */
                id: CommonType.IdType;
            /** åˆ¤å®šä¸»æ ‡è¯† */
                judgeId: CommonType.IdType;
            /** åˆ¤å®šé¡¹ITEM */
                itemCod: string;
            /** åˆ¤å®šé¡¹NAME */
                itemName: string;
            /** æ ‡å‡†å€¼ */
                value3: number;
            /** åˆ¤å®šå€¼1 */
                value1: number;
            /** åˆ¤å®šå€¼2 */
                value2: number;
            /** ç¼ºé™·ä½ç½® */
                location: string;
            /** åˆ¤å®šçº§åˆ« (A,B,C,D) */
                cls: string;
            /** åˆ†å€¼æ ‡å‡† (扣分标准,得分标准),比如不合格一次扣多少分 */
                stdscore: number;
            /** æ ‡è®°æ­¤é¡¹æ˜¯å¦ä¸ºåˆæˆé¡¹ç›®ï¼Œæ¯”如外观,实际上关联了很多子项目 */
                ismix: number;
            /** è‹¥æ­¤å­—段有UUID值,表明它可能为其他项目的子项,比如“空头”,它为烟支外观项目的子项 */
                rid: CommonType.IdType;
            /** èŒƒå›´-备用 */
                category: number;
            /** å¤‡æ³¨ */
                decisionDes: string;
            /** ä¿®æ”¹äºº */
                updateUser: string;
        }>;
        /** judge details search params */
        type JudgeDetailsSearchParams = CommonType.RecordNullable<
            Pick<
                Api.Qm.JudgeDetails,
                        | 'judgeId'
                        | 'itemCod'
                        | 'itemName'
                        | 'cls'
                        | 'ismix'
            > &
            Api.Common.CommonSearchParams
        >;
        /** judge details operate params */
        type JudgeDetailsOperateParams = CommonType.RecordNullable<
            Pick<
                Api.Qm.JudgeDetails,
                        | 'id'
                        | 'judgeId'
                        | 'itemCod'
                        | 'itemName'
                        | 'value3'
                        | 'value1'
                        | 'value2'
                        | 'location'
                        | 'cls'
                        | 'stdscore'
                        | 'ismix'
                        | 'rid'
                        | 'category'
                        | 'decisionDes'
                        | 'updateUser'
            >
        >;
        /** judge details list */
        type JudgeDetailsList = Api.Common.PaginatingQueryRecord<JudgeDetails>;
    }
}
ruoyi-plus-soybean/src/typings/api/qm.judge.api.d.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
/**
 * Namespace Api
 *
 * All backend api type
 */
declare namespace Api {
    /**
     * namespace Qm
     *
     * backend api module: "Qm"
     */
    namespace Qm {
        /** judge */
        type Judge = Common.CommonRecord<{
            /** ç¼–码 */
                id: CommonType.IdType;
            /** ç‰©æ–™ç‰Œå·ä»£ç  */
                matCode: string;
            /** ç‰©æ–™ç‰Œå· */
                matName: string;
            /** ç‰ˆæœ¬å· */
                version: number;
            /** çŠ¶æ€ */
                status: number;
            /** åˆ¤å®šè§„程COD */
                stdCod: string;
            /** åˆ›å»ºæ—¶é—´ */
                cdate: string;
            /** ç”Ÿæ•ˆäºº/操作人员 */
                oper: string;
            /** å¤‡æ³¨ */
                des: string;
            /** ç‰©æ–™ç±»åž‹ */
                category: number;
            /** è¾…料类型编码 */
                typeCode: string;
            /** è¾…料类型名称 */
                typeName: string;
            /** åˆ¤å®šåç§° */
                judgeName: string;
        }>;
        /** judge search params */
        type JudgeSearchParams = CommonType.RecordNullable<
            Pick<
                Api.Qm.Judge,
                        | 'matCode'
                        | 'matName'
                        | 'judgeName'
                        | 'category'
                        | 'status'
            > &
            Api.Common.CommonSearchParams
        >;
        /** judge operate params */
        type JudgeOperateParams = CommonType.RecordNullable<
            Pick<
                Api.Qm.Judge,
                        | 'matCode'
                        | 'matName'
                        | 'status'
                        | 'stdCod'
                        | 'cdate'
                        | 'oper'
                        | 'des'
                        | 'category'
                        | 'typeCode'
                        | 'typeName'
                        | 'judgeName'
            >
        >;
        /** judge list */
        type JudgeList = Api.Common.PaginatingQueryRecord<Judge>;
    }
}
ruoyi-plus-soybean/src/typings/elegant-router.d.ts
@@ -39,6 +39,7 @@
    "iframe-page": "/iframe-page/:url";
    "login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
    "md": "/md";
    "md_instrument": "/md/instrument";
    "md_shift": "/md/shift";
    "monitor": "/monitor";
    "monitor_cache": "/monitor/cache";
@@ -47,6 +48,8 @@
    "monitor_operlog": "/monitor/operlog";
    "qm": "/qm";
    "qm_batch": "/qm/batch";
    "qm_judge": "/qm/judge";
    "qm_judge-details": "/qm/judge-details";
    "qm_std": "/qm/std";
    "report": "/report";
    "report_demo": "/report/demo";
@@ -156,12 +159,15 @@
    | "demo_demo"
    | "demo_tree"
    | "home"
    | "md_instrument"
    | "md_shift"
    | "monitor_cache"
    | "monitor_logininfor"
    | "monitor_online"
    | "monitor_operlog"
    | "qm_batch"
    | "qm_judge-details"
    | "qm_judge"
    | "qm_std"
    | "report_demo"
    | "report_silk-storage-output"
ruoyi-plus-soybean/src/views/md/instrument/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,247 @@
<script setup lang="tsx">
import { ref } from 'vue';
import { NDivider, NTooltip } from 'naive-ui';
import { fetchBatchDeleteInstrument, fetchGetInstrumentList } from '@/service/api/md/instrument';
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 { useDict } from '@/hooks/business/dict';
import { $t } from '@/locales';
import ButtonIcon from '@/components/custom/button-icon.vue';
import InstrumentOperateDrawer from './modules/instrument-operate-drawer.vue';
import InstrumentSearch from './modules/instrument-search.vue';
defineOptions({
  name: 'InstrumentList'
});
useDict('sys_yes_no');
const appStore = useAppStore();
const { download } = useDownload();
const { hasAuth } = useAuth();
const searchParams = ref<Api.Md.InstrumentSearchParams>({
  pageNum: 1,
  pageSize: 10,
  instrumentCode: null,
  instrumentName: null,
  enable: null,
  params: {}
});
const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
  useNaivePaginatedTable({
  api: () => fetchGetInstrumentList(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: 'instrumentCode',
      title: '仪器代码',
      align: 'center',
      width: 120
    },
    {
      key: 'instrumentName',
      title: '仪器名称',
      align: 'center',
      width: 200
    },
    {
      key: 'ifStd',
      title: '接口标准',
      align: 'center',
      width: 120
    },
    {
      key: 'isc',
      title: '接口标准代码',
      align: 'center',
      width: 100
    },
    {
      key: 'workShop',
      title: '所属车间',
      align: 'center',
      width: 120
    },
    {
      key: 'enable',
      title: '启用',
      align: 'center',
      width: 120,
      render(row) {
        return <DictTag value={row.enable} dictCode="sys_yes_no" />;
      }
    },
    {
      key: 'del',
      title: '删除',
      align: 'center',
      width: 120
    },
    {
      key: 'instrumentDes',
      title: '备注',
      align: 'center',
      width: 300,
      render: row => (
        <NTooltip trigger="hover">
          {{
            trigger: () => (
              <div
                style={{
                  whiteSpace: 'nowrap',
                  overflow: 'hidden',
                  textOverflow: 'ellipsis'
                }}
              >
                {row.instrumentDes}
              </div>
            ),
            default: () => row.instrumentDes
          }}
        </NTooltip>
      )
    },
    {
      key: 'operate',
      title: $t('common.operate'),
      align: 'center',
      width: 130,
      render: row => {
        const divider = () => {
          if (!hasAuth('md:instrument:edit') || !hasAuth('md:instrument:remove')) {
            return null;
          }
          return <NDivider vertical />;
        };
        const editBtn = () => {
          if (!hasAuth('md:instrument: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:instrument: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 fetchBatchDeleteInstrument(checkedRowKeys.value);
  if (error) return;
  onBatchDeleted();
}
async function handleDelete(id: CommonType.IdType) {
  // request
  const { error } = await fetchBatchDeleteInstrument([id]);
  if (error) return;
  onDeleted();
}
function edit(id: CommonType.IdType) {
  handleEdit(id);
}
function handleExport() {
  download('/md/instrument/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">
    <InstrumentSearch 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:instrument:add')"
          :show-delete="hasAuth('md:instrument:remove')"
          :show-export="hasAuth('md:instrument: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"
      />
      <InstrumentOperateDrawer
        v-model:visible="drawerVisible"
        :operate-type="operateType"
        :row-data="editingData"
        @submitted="getDataByPage"
      />
    </NCard>
  </div>
</template>
<style scoped></style>
ruoyi-plus-soybean/src/views/md/instrument/modules/instrument-operate-drawer.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,157 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { NSelect } from 'naive-ui';
import { jsonClone } from '@sa/utils';
import { fetchCreateInstrument, fetchUpdateInstrument } from '@/service/api/md/instrument';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales';
defineOptions({
  name: 'InstrumentOperateDrawer'
});
interface Props {
  /** the type of operation */
  operateType: NaiveUI.TableOperateType;
  /** the edit row data */
  rowData?: Api.Md.Instrument | 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];
});
const enableOptions = [
  { label: '启用', value: 1 },
  { label: '停用', value: 0 }
];
const delOptions = [
  { label: '正常', value: 0 },
  { label: '删除', value: 1 }
];
type Model = Api.Md.InstrumentOperateParams;
const model = ref<Model>(createDefaultModel());
function createDefaultModel(): Model {
  return {
      id: '',
      instrumentCode: '',
      instrumentName: '',
      ifStd: '',
      isc: null,
      workShop: '',
      enable: 1,
      del: 0,
      instrumentDes: ''
  };
}
type RuleKey = Extract<keyof Model, 'id'>;
const rules: Record<RuleKey, App.Global.FormRule> = {
  id: createRequiredRule('ud不能为空')
};
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, instrumentCode, instrumentName, ifStd, isc, workShop, enable, del, instrumentDes } = model.value;
  // request
  if (props.operateType === 'add') {
    const { error } = await fetchCreateInstrument({ id, instrumentCode, instrumentName, ifStd, isc, workShop, enable, del, instrumentDes });
    if (error) return;
  }
  if (props.operateType === 'edit') {
    const { error } = await fetchUpdateInstrument({ id, instrumentCode, instrumentName, ifStd, isc, workShop, enable, del, instrumentDes });
    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="instrumentCode">
          <NInput v-model:value="model.instrumentCode" placeholder="请输入仪器代码" />
        </NFormItem>
        <NFormItem label="仪器名称" path="instrumentName">
          <NInput v-model:value="model.instrumentName" placeholder="请输入仪器名称" />
        </NFormItem>
        <NFormItem label="接口标准" path="ifStd">
          <NInput v-model:value="model.ifStd" placeholder="请输入接口标准" />
        </NFormItem>
        <NFormItem label="接口标准代码" path="isc">
          <NInput v-model:value="model.isc" placeholder="请输入接口标准代码" />
        </NFormItem>
        <NFormItem label="所属车间" path="workShop">
          <NInput v-model:value="model.workShop" placeholder="请输入所属车间" />
        </NFormItem>
        <NFormItem label="启用" path="enable">
          <NSelect v-model:value="model.enable as number" :options="enableOptions" placeholder="请选择启用" clearable />
        </NFormItem>
        <NFormItem label="删除" path="del">
          <NSelect v-model:value="model.del as number" :options="delOptions" placeholder="请选择删除" clearable />
        </NFormItem>
        <NFormItem label="备注" path="instrumentDes">
          <NInput v-model:value="model.instrumentDes" placeholder="请输入备注" />
        </NFormItem>
      </NForm>
      <template #footer>
        <NSpace :size="16">
          <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
          <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
        </NSpace>
      </template>
    </NDrawerContent>
  </NDrawer>
</template>
<style scoped></style>
ruoyi-plus-soybean/src/views/md/instrument/modules/instrument-search.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
<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: 'InstrumentSearch'
});
interface Emits {
  (e: 'search'): void;
}
const emit = defineEmits<Emits>();
const { formRef, validate, restoreValidation } = useNaiveForm();
const model = defineModel<Api.Md.InstrumentSearchParams>('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-instrument-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="instrumentCode" class="pr-24px">
              <NInput v-model:value="model.instrumentCode" placeholder="请输入仪器代码" />
            </NFormItemGi>
            <NFormItemGi span="24 s:12 m:6" label="仪器名称" label-width="auto" path="instrumentName" class="pr-24px">
              <NInput v-model:value="model.instrumentName" placeholder="请输入仪器名称" />
            </NFormItemGi>
            <NFormItemGi span="24 s:12 m:6" label="启用" label-width="auto" path="enable" class="pr-24px">
              <DictSelect
                v-model:value="model.enable"
                placeholder="请选择启用"
                dict-code="sys_yes_no"
                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/checkitem/modules/checkitem-operate-drawer.vue
@@ -6,6 +6,7 @@
  fetchGetRid,
  fetchUpdateCheckitem
} from '@/service/api/qm/checkitem';
import { fetchGetInstrumentList } from '@/service/api/md/instrument';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales';
@@ -76,6 +77,7 @@
const model = ref<Model>(createDefaultModel());
const ridOptions = ref<{ label: string; value: string | number }[]>([]);
const instrumentOptions = ref<{ label: string; value: string | number }[]>([]);
async function fetchRidOptions(searchText?: string) {
  const params: any = {};
@@ -96,6 +98,26 @@
function handleRidSelectSearch(query: string) {
  fetchRidOptions(query);
}
async function fetchInstrumentOptions(searchText?: string) {
  const params: any = {};
  if (searchText) {
    params.instrumentName = searchText;
  }
  const { data } = await fetchGetInstrumentList(params);
  if (data && data.rows) {
    instrumentOptions.value = data.rows.map(item => ({
      label: item.instrumentName,
      value: item.instrumentCode
    }));
  } else {
    instrumentOptions.value = [];
  }
}
function handleInstrumentSelectSearch(query: string) {
  fetchInstrumentOptions(query);
}
@@ -139,6 +161,8 @@
  // Fetch options for rid
  await fetchRidOptions();
  // Fetch options for instrument
  await fetchInstrumentOptions();
  if (props.operateType === 'add' && props.stdCode) {
    model.value.stdCode = props.stdCode;
@@ -202,7 +226,17 @@
        <NFormItem label="检验项描述" path="itemDes">
          <NInput v-model:value="model.itemDes" placeholder="请输入检验项描述" />
        </NFormItem>
        <NFormItem label="检测仪器" path="instrumentCode">
          <NSelect
            v-model:value="model.instrumentCode"
            :options="instrumentOptions"
            placeholder="请选择检测仪器"
            clearable
            filterable
            @search="handleInstrumentSelectSearch"
            @focus="() => fetchInstrumentOptions()"
          />
        </NFormItem>
        <NFormItem label="仪器描述" path="instrumentDes">
          <NInput v-model:value="model.instrumentDes" placeholder="请输入仪器描述" />
        </NFormItem>
ruoyi-plus-soybean/src/views/qm/judge-details/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,262 @@
<script setup lang="tsx">
import { ref } from 'vue';
import { NDivider } from 'naive-ui';
import { fetchBatchDeleteJudgeDetails, fetchGetJudgeDetailsList } from '@/service/api/qm/judge-details';
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 JudgeDetailsOperateDrawer from './modules/judge-details-operate-drawer.vue';
import JudgeDetailsSearch from './modules/judge-details-search.vue';
defineOptions({
  name: 'JudgeDetailsList'
});
const appStore = useAppStore();
const { download } = useDownload();
const { hasAuth } = useAuth();
const searchParams = ref<Api.Qm.JudgeDetailsSearchParams>({
  pageNum: 1,
  pageSize: 10,
  judgeId: null,
  itemCod: null,
  itemName: null,
  cls: null,
  ismix: null,
  params: {}
});
const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
  useNaivePaginatedTable({
  api: () => fetchGetJudgeDetailsList(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: 'judgeId',
      title: '判定主标识',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'itemCod',
      title: '判定项ITEM',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'itemName',
      title: '判定项NAME',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'value3',
      title: '标准值',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'value1',
      title: '判定值1',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'value2',
      title: '判定值2',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'location',
      title: '缺陷位置',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'cls',
      title: '判定级别 (A,B,C,D)',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'stdscore',
      title: '分值标准 (扣分标准,得分标准),比如不合格一次扣多少分',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'ismix',
      title: '标记此项是否为合成项目,比如外观,实际上关联了很多子项目',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'rid',
      title: '若此字段有UUID值,表明它可能为其他项目的子项,比如“空头”,它为烟支外观项目的子项',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'category',
      title: '范围-备用',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'decisionDes',
      title: '备注',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'updateUser',
      title: '修改人',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'operate',
      title: $t('common.operate'),
      align: 'center',
      width: 130,
      render: row => {
        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={() => edit(row.id)}
            />
          );
        };
        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>
        );
      }
    }
  ]
});
const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
  useTableOperate(data, 'id', getData);
async function handleBatchDelete() {
  // request
  const { error } = await fetchBatchDeleteJudgeDetails(checkedRowKeys.value);
  if (error) return;
  onBatchDeleted();
}
async function handleDelete(id: CommonType.IdType) {
  // request
  const { error } = await fetchBatchDeleteJudgeDetails([id]);
  if (error) return;
  onDeleted();
}
function edit(id: CommonType.IdType) {
  handleEdit(id);
}
function handleExport() {
  download('/qm/judgeDetails/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">
    <JudgeDetailsSearch v-model:model="searchParams" @search="getDataByPage" />
    <NCard title="判定模板明细列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
      <template #header-extra>
        <TableHeaderOperation
          v-model:columns="columnChecks"
          :disabled-delete="checkedRowKeys.length === 0"
          :loading="loading"
          :show-add="hasAuth('qm:judgeDetails:add')"
          :show-delete="hasAuth('qm:judgeDetails:remove')"
          :show-export="hasAuth('qm:judgeDetails: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"
      />
      <JudgeDetailsOperateDrawer
        v-model:visible="drawerVisible"
        :operate-type="operateType"
        :row-data="editingData"
        @submitted="getDataByPage"
      />
    </NCard>
  </div>
</template>
<style scoped></style>
ruoyi-plus-soybean/src/views/qm/judge-details/modules/judge-details-operate-drawer.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,175 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { jsonClone } from '@sa/utils';
import { fetchCreateJudgeDetails, fetchUpdateJudgeDetails } from '@/service/api/qm/judge-details';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales';
defineOptions({
  name: 'JudgeDetailsOperateDrawer'
});
interface Props {
  /** the type of operation */
  operateType: NaiveUI.TableOperateType;
  /** the edit row data */
  rowData?: Api.Qm.JudgeDetails | null;
}
const props = defineProps<Props>();
interface Emits {
  (e: 'submitted'): void;
}
const emit = defineEmits<Emits>();
const visible = defineModel<boolean>('visible', {
  default: false
});
const { formRef, validate, restoreValidation } = useNaiveForm();
const { createRequiredRule } = useFormRules();
const title = computed(() => {
  const titles: Record<NaiveUI.TableOperateType, string> = {
    add: '新增判定模板明细',
    edit: '编辑判定模板明细'
  };
  return titles[props.operateType];
});
type Model = Api.Qm.JudgeDetailsOperateParams;
const model = ref<Model>(createDefaultModel());
function createDefaultModel(): Model {
  return {
      id: '',
      judgeId: '',
      itemCod: '',
      itemName: '',
      value3: null,
      value1: null,
      value2: null,
      location: '',
      cls: '',
      stdscore: null,
      ismix: null,
      rid: '',
      category: null,
      decisionDes: '',
      updateUser: '',
  };
}
type RuleKey = Extract<
  keyof Model,
  | 'id'
>;
const rules: Record<RuleKey, App.Global.FormRule> = {
};
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, judgeId, itemCod, itemName, value3, value1, value2, location, cls, stdscore, ismix, rid, category, decisionDes, updateUser } = model.value;
  // request
  if (props.operateType === 'add') {
    const { error } = await fetchCreateJudgeDetails({ id, judgeId, itemCod, itemName, value3, value1, value2, location, cls, stdscore, ismix, rid, category, decisionDes, updateUser });
    if (error) return;
  }
  if (props.operateType === 'edit') {
    const { error } = await fetchUpdateJudgeDetails({ id, judgeId, itemCod, itemName, value3, value1, value2, location, cls, stdscore, ismix, rid, category, decisionDes, updateUser });
    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="id">
          <NInput v-model:value="model.id" placeholder="请输入编码" />
        </NFormItem>
        <NFormItem label="判定主标识" path="judgeId">
          <NInput v-model:value="model.judgeId" placeholder="请输入判定主标识" />
        </NFormItem>
        <NFormItem label="判定项ITEM" path="itemCod">
          <NInput v-model:value="model.itemCod" placeholder="请输入判定项ITEM" />
        </NFormItem>
        <NFormItem label="判定项NAME" path="itemName">
          <NInput v-model:value="model.itemName" placeholder="请输入判定项NAME" />
        </NFormItem>
        <NFormItem label="标准值" path="value3">
          <NInput v-model:value="model.value3" placeholder="请输入标准值" />
        </NFormItem>
        <NFormItem label="判定值1" path="value1">
          <NInput v-model:value="model.value1" placeholder="请输入判定值1" />
        </NFormItem>
        <NFormItem label="判定值2" path="value2">
          <NInput v-model:value="model.value2" placeholder="请输入判定值2" />
        </NFormItem>
        <NFormItem label="缺陷位置" path="location">
          <NInput v-model:value="model.location" placeholder="请输入缺陷位置" />
        </NFormItem>
        <NFormItem label="判定级别 (A,B,C,D)" path="cls">
          <NInput v-model:value="model.cls" placeholder="请输入判定级别 (A,B,C,D)" />
        </NFormItem>
        <NFormItem label="分值标准 (扣分标准,得分标准),比如不合格一次扣多少分" path="stdscore">
          <NInput v-model:value="model.stdscore" placeholder="请输入分值标准 (扣分标准,得分标准),比如不合格一次扣多少分" />
        </NFormItem>
        <NFormItem label="标记此项是否为合成项目,比如外观,实际上关联了很多子项目" path="ismix">
          <NInput v-model:value="model.ismix" placeholder="请输入标记此项是否为合成项目,比如外观,实际上关联了很多子项目" />
        </NFormItem>
        <NFormItem label="若此字段有UUID值,表明它可能为其他项目的子项,比如“空头”,它为烟支外观项目的子项" path="rid">
          <NInput v-model:value="model.rid" placeholder="请输入若此字段有UUID值,表明它可能为其他项目的子项,比如“空头”,它为烟支外观项目的子项" />
        </NFormItem>
        <NFormItem label="范围-备用" path="category">
          <NInput v-model:value="model.category" placeholder="请输入范围-备用" />
        </NFormItem>
        <NFormItem label="备注" path="decisionDes">
          <NInput v-model:value="model.decisionDes" placeholder="请输入备注" />
        </NFormItem>
        <NFormItem label="修改人" path="updateUser">
          <NInput v-model:value="model.updateUser" placeholder="请输入修改人" />
        </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/qm/judge-details/modules/judge-details-search.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,83 @@
<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: 'JudgeDetailsSearch'
});
interface Emits {
  (e: 'search'): void;
}
const emit = defineEmits<Emits>();
const { formRef, validate, restoreValidation } = useNaiveForm();
const model = defineModel<Api.Qm.JudgeDetailsSearchParams>('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-judge-details-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="judgeId" class="pr-24px">
              <NInput v-model:value="model.judgeId" placeholder="请输入判定主标识" />
            </NFormItemGi>
            <NFormItemGi span="24 s:12 m:6" label="判定项ITEM" label-width="auto" path="itemCod" class="pr-24px">
              <NInput v-model:value="model.itemCod" placeholder="请输入判定项ITEM" />
            </NFormItemGi>
            <NFormItemGi span="24 s:12 m:6" label="判定项NAME" label-width="auto" path="itemName" class="pr-24px">
              <NInput v-model:value="model.itemName" placeholder="请输入判定项NAME" />
            </NFormItemGi>
            <NFormItemGi span="24 s:12 m:6" label="判定级别 (A,B,C,D)" label-width="auto" path="cls" class="pr-24px">
              <NInput v-model:value="model.cls" placeholder="请输入判定级别 (A,B,C,D)" />
            </NFormItemGi>
            <NFormItemGi span="24 s:12 m:6" label="标记此项是否为合成项目,比如外观,实际上关联了很多子项目" label-width="auto" path="ismix" class="pr-24px">
              <NInput v-model:value="model.ismix" placeholder="请输入标记此项是否为合成项目,比如外观,实际上关联了很多子项目" />
            </NFormItemGi>
            <NFormItemGi :show-feedback="false" span="24" class="pr-24px">
              <NSpace class="w-full" justify="end">
                <NButton @click="reset">
                  <template #icon>
                    <icon-ic-round-refresh class="text-icon" />
                  </template>
                  {{ $t('common.reset') }}
                </NButton>
                <NButton type="primary" ghost @click="search">
                  <template #icon>
                    <icon-ic-round-search class="text-icon" />
                  </template>
                  {{ $t('common.search') }}
                </NButton>
              </NSpace>
            </NFormItemGi>
          </NGrid>
        </NForm>
      </NCollapseItem>
    </NCollapse>
  </NCard>
</template>
<style scoped></style>
ruoyi-plus-soybean/src/views/qm/judge/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,323 @@
<script setup lang="tsx">
import { ref } from 'vue';
import { NDivider, NTooltip } from 'naive-ui';
import { fetchBatchDeleteJudge, fetchGetJudgeList } from '@/service/api/qm/judge';
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 JudgeOperateDrawer from './modules/judge-operate-drawer.vue';
import JudgeSearch from './modules/judge-search.vue';
defineOptions({
  name: 'JudgeList'
});
const appStore = useAppStore();
const { download } = useDownload();
const { hasAuth } = useAuth();
const searchParams = ref<Api.Qm.JudgeSearchParams>({
  pageNum: 1,
  pageSize: 10,
  matCode: null,
  matName: null,
  judgeName: null,
  category: 0, // é»˜è®¤é€‰æ‹©æˆå“
  status: -1, // é»˜è®¤é€‰æ‹©å…¨éƒ¨
  params: {}
});
const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
  useNaivePaginatedTable({
  api: () => {
    const params = { ...searchParams.value };
    if (params.status === -1) {
      delete params.status;
    }
    return fetchGetJudgeList(params);
  },
  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: 'judgeName',
      title: '判定名称',
      align: 'center',
      width: 200,
      render: row => (
        <NTooltip trigger="hover">
          {{
            trigger: () => (
              <div
                style={{
                  whiteSpace: 'nowrap',
                  overflow: 'hidden',
                  textOverflow: 'ellipsis'
                }}
              >
                {row.judgeName}
              </div>
            ),
            default: () => row.judgeName
          }}
        </NTooltip>
      )
    },
    {
      key: 'category',
      title: '物料类型',
      align: 'center',
      width: 100,
      render: row => {
        if (row.category === 0) {
          return '成品';
        }
        if (row.category === 1) {
          return '辅料';
        }
        return String(row.category);
      }
    },
    {
      key: 'typeName',
      title: '辅料类型',
      align: 'center',
      width: 100,
      render: row => (
        <NTooltip trigger="hover">
          {{
            trigger: () => (
              <div
                style={{
                  whiteSpace: 'nowrap',
                  overflow: 'hidden',
                  textOverflow: 'ellipsis'
                }}
              >
                {row.typeName}
              </div>
            ),
            default: () => row.typeName
          }}
        </NTooltip>
      )
    },
    {
      key: 'matName',
      title: '物料牌号',
      align: 'center',
      width: 180,
      render: row => (
        <NTooltip trigger="hover">
          {{
            trigger: () => (
              <div
                style={{
                  whiteSpace: 'nowrap',
                  overflow: 'hidden',
                  textOverflow: 'ellipsis'
                }}
              >
                {row.matName}
              </div>
            ),
            default: () => row.matName
          }}
        </NTooltip>
      )
    },
    {
      key: 'matCode',
      title: '物料牌号代码',
      align: 'center',
      width: 150
    },
    {
      key: 'version',
      title: '版本号',
      align: 'center',
      width: 100
    },
    {
      key: 'status',
      title: '状态',
      align: 'center',
      width: 100,
      render: row => {
        if (row.status === 1) {
          return '启用';
        }
        if (row.status === 0) {
          return '归档';
        }
        return String(row.status);
      }
    },
    {
      key: 'stdName',
      title: '判定规程',
      align: 'center',
      width: 200
    },
    {
      key: 'cdate',
      title: '创建时间',
      align: 'center',
      width: 180
    },
    {
      key: 'oper',
      title: '操作人',
      align: 'center',
      width: 100
    },
    {
      key: 'des',
      title: '备注',
      align: 'center',
      width: 200
    },
    {
      key: 'operate',
      title: $t('common.operate'),
      align: 'center',
      fixed: 'right',
      width: 130,
      render: row => {
        const divider = () => {
          if (!hasAuth('qm:judge:edit') || !hasAuth('qm:judge:remove')) {
            return null;
          }
          return <NDivider vertical />;
        };
        const editBtn = () => {
          if (!hasAuth('qm:judge: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:judge: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 fetchBatchDeleteJudge(checkedRowKeys.value);
  if (error) return;
  onBatchDeleted();
}
async function handleDelete(id: CommonType.IdType) {
  // request
  const { error } = await fetchBatchDeleteJudge([id]);
  if (error) return;
  onDeleted();
}
function edit(id: CommonType.IdType) {
  handleEdit(id);
}
function handleExport() {
  download('/qm/judge/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">
    <JudgeSearch v-model:model="searchParams" @search="getDataByPage" />
    <NCard title="判定依据列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
      <template #header-extra>
        <TableHeaderOperation
          v-model:columns="columnChecks"
          :disabled-delete="checkedRowKeys.length === 0"
          :loading="loading"
          :show-add="hasAuth('qm:judge:add')"
          :show-delete="hasAuth('qm:judge:remove')"
          :show-export="hasAuth('qm:judge:export')"
          @add="handleAdd"
          @delete="handleBatchDelete"
          @export="handleExport"
          @refresh="getData"
        />
      </template>
      <NDataTable
        v-model:checked-row-keys="checkedRowKeys"
        :columns="columns"
        :data="data"
        size="small"
        :flex-height="!appStore.isMobile"
        :scroll-x="scrollX"
        :loading="loading"
        remote
        :row-key="row => row.id"
        :pagination="mobilePagination"
        class="sm:h-full"
      />
      <JudgeOperateDrawer
        v-model:visible="drawerVisible"
        :operate-type="operateType"
        :row-data="editingData"
        @submitted="getDataByPage"
      />
    </NCard>
  </div>
</template>
<style scoped></style>
ruoyi-plus-soybean/src/views/qm/judge/modules/judge-operate-drawer.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,212 @@
<script setup lang="ts">
import { computed, ref, watch, onMounted } from 'vue';
import { NSelect, SelectOption } from 'naive-ui';
import { jsonClone } from '@sa/utils';
import { fetchCreateJudge, fetchUpdateJudge } from '@/service/api/qm/judge';
import { fetchGetStdList } from '@/service/api/qm/std';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales';
defineOptions({
  name: 'JudgeOperateDrawer'
});
interface Props {
  /** the type of operation */
  operateType: NaiveUI.TableOperateType;
  /** the edit row data */
  rowData?: Api.Qm.Judge | 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];
});
const statusOptions: SelectOption[] = [
  { label: '启用', value: 1 },
  { label: '归档', value: 0 }
];
const categoryOptions: SelectOption[] = [
  { label: '成品', value: 0 },
  { label: '辅料', value: 1 }
];
const stdOptions = ref<SelectOption[]>([]);
type Model = Api.Qm.JudgeOperateParams;
const model = ref<Model>(createDefaultModel());
function createDefaultModel(): Model {
  return {
      matCode: '',
      matName: '',
      status: null,
      stdCod: '',
      cdate: null,
      oper: '',
      des: '',
      category: null,
      typeCode: '',
      typeName: '',
      judgeName: ''
  };
}
type RuleKey = Extract<
  keyof Model,
  | 'id'
>;
const rules: Record<RuleKey, App.Global.FormRule> = {
};
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 fetchStdOptions() {
    const response = await fetchGetStdList({ category: model.value.category });
  const stdListData = response.data?.rows || [];
  if (stdListData.length > 0) {
    stdOptions.value = stdListData.map((item: Api.Qm.Std) => ({
        label: item.stdName + item.stdCode,
        value: String(item.id)
      }));
  }
}
async function handleSubmit() {
  await validate();
  const { matCode, matName, status, stdCod, cdate, oper, des, category, typeCode, typeName, judgeName } = model.value;
  // request
  if (props.operateType === 'add') {
    const { error } = await fetchCreateJudge({ matCode, matName, status, stdCod, cdate, oper, des, category, typeCode, typeName, judgeName });
    if (error) return;
  }
  if (props.operateType === 'edit') {
    const { error } = await fetchUpdateJudge({ matCode, matName, status, stdCod, cdate, oper, des, category, typeCode, typeName, judgeName });
    if (error) return;
  }
  window.$message?.success($t('common.updateSuccess'));
  closeDrawer();
  emit('submitted');
}
watch(visible, () => {
  if (visible.value) {
    handleUpdateModelWhenEdit();
    restoreValidation();
    // Fetch stdOptions when the drawer becomes visible
    fetchStdOptions();
  }
});
watch(() => model.value.category, () => {
  fetchStdOptions();
});
</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="judgeName">
          <NInput v-model:value="model.judgeName" placeholder="请输入判定名称" />
        </NFormItem>
        <NFormItem label="物料牌号代码" path="matCode">
          <NInput v-model:value="model.matCode" placeholder="请输入物料牌号代码" />
        </NFormItem>
        <NFormItem label="物料牌号" path="matName">
          <NInput v-model:value="model.matName" placeholder="请输入物料牌号" />
        </NFormItem>
        <NFormItem label="物料类型" path="category">
          <NSelect
            v-model:value="model.category"
            :options="categoryOptions"
            placeholder="请选择物料类型"
          />
        </NFormItem>
        <NFormItem label="状态" path="status">
          <NSelect
            v-model:value="model.status"
            :options="statusOptions"
            placeholder="请选择状态"
          />
        </NFormItem>
        <NFormItem label="判定规程" path="stdCod">
          <NSelect
            v-model:value="model.stdCod"
            :options="stdOptions"
            placeholder="请选择判定规程"
          />
        </NFormItem>
        <NFormItem label="创建时间" path="cdate">
          <NDatePicker
            v-model:formatted-value="model.cdate"
            type="datetime"
            value-format="yyyy-MM-dd HH:mm:ss"
            clearable
          />
        </NFormItem>
        <NFormItem label="生效人/操作人员" path="oper">
          <NInput v-model:value="model.oper" placeholder="请输入生效人/操作人员" />
        </NFormItem>
        <NFormItem label="备注" path="des">
          <NInput v-model:value="model.des" placeholder="请输入备注" />
        </NFormItem>
        <NFormItem label="辅料类型编码" path="typeCode">
          <NInput v-model:value="model.typeCode" placeholder="请输入辅料类型编码" />
        </NFormItem>
        <NFormItem label="辅料类型名称" path="typeName">
          <NInput v-model:value="model.typeName" placeholder="请输入辅料类型名称" />
        </NFormItem>
      </NForm>
      <template #footer>
        <NSpace :size="16">
          <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
          <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
        </NSpace>
      </template>
    </NDrawerContent>
  </NDrawer>
</template>
<style scoped></style>
ruoyi-plus-soybean/src/views/qm/judge/modules/judge-search.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,98 @@
<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: 'JudgeSearch'
});
interface Emits {
  (e: 'search'): void;
}
const emit = defineEmits<Emits>();
const { formRef, validate, restoreValidation } = useNaiveForm();
const model = defineModel<Api.Qm.JudgeSearchParams>('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-judge-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="category" class="pr-24px">
              <NSelect
                v-model:value="model.category"
                :options="[
                  { label: '成品', value: 0 },
                  { label: '辅料', value: 1 }
                ]"
                placeholder="请选择物料类型"
              />
            </NFormItemGi>
            <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="matName" class="pr-24px">
              <NInput v-model:value="model.matName" placeholder="请输入物料牌号" />
            </NFormItemGi>
            <NFormItemGi span="24 s:12 m:6" label="判定名称" label-width="auto" path="judgeName" class="pr-24px">
              <NInput v-model:value="model.judgeName" placeholder="请输入判定名称" />
            </NFormItemGi>
            <NFormItemGi span="24 s:12 m:6" label="是否启用" label-width="auto" path="status" class="pr-24px">
              <NSelect
                v-model:value="model.status"
                :options="[
                  { label: '全部', value: -1 },
                  { label: '启用', value: 1 },
                  { label: '归档', value: 0 }
                ]"
              />
            </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>