广丰卷烟厂数采质量分析系统
zhuguifei
2026-03-13 06f6eb3b6159323a26e55cc15ef3000786931e24
feat(新增基础数据判断规程、以及判定规程明细):
已修改6个文件
已添加14个文件
1594 ■■■■■ 文件已修改
.gitignore 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmCheckitemController.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmCheckitem.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmCheckitemBo.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmCheckitemVo.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmCheckitemMapper.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmCheckitemService.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmCheckitemServiceImpl.java 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmCheckitemMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/router/elegant/imports.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/router/elegant/routes.ts 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/router/elegant/transform.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/service/api/qm/checkitem.ts 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/typings/api/qm.checkitem.api.d.ts 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/typings/elegant-router.d.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/checkitem/index.vue 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/checkitem/modules/checkitem-operate-drawer.vue 178 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/checkitem/modules/checkitem-search.vue 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/std/index.vue 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/std/modules/std-sub-table.vue 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -2,4 +2,6 @@
**/logs
**/target
**/.vscode
**/.flattened-pom.xml
**/.flattened-pom.xml
RuoYi-Vue-Plus/.msp
RuoYi-Vue-Plus/gzdams
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmCheckitemController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,114 @@
package org.dromara.qa.qm.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.qa.qm.domain.vo.QmCheckitemVo;
import org.dromara.qa.qm.domain.bo.QmCheckitemBo;
import org.dromara.qa.qm.service.IQmCheckitemService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
 * è§„程检验项目
 *
 * @author zhuguifei
 * @date 2026-03-12
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/qm/checkitem")
public class QmCheckitemController extends BaseController {
    private final IQmCheckitemService qmCheckitemService;
    /**
     * æŸ¥è¯¢è§„程检验项目列表
     */
    @SaCheckPermission("qm:checkitem:list")
    @GetMapping("/list")
    public TableDataInfo<QmCheckitemVo> list(QmCheckitemBo bo, PageQuery pageQuery) {
        return qmCheckitemService.queryPageList(bo, pageQuery);
    }
    @SaCheckPermission("qm:checkitem:list")
    @GetMapping("/tree")
    public TableDataInfo<QmCheckitemVo> tree(@RequestParam @NotBlank(message = "stdCode不能为空") String stdCode,
                                             @RequestParam(required = false) Integer page,
                                             @RequestParam(required = false) Integer rows) {
        List<QmCheckitemVo> list = qmCheckitemService.queryTreeListByStdCode(stdCode);
        return TableDataInfo.build(list);
    }
    /**
     * å¯¼å‡ºè§„程检验项目列表
     */
    @SaCheckPermission("qm:checkitem:export")
    @Log(title = "规程检验项目", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(QmCheckitemBo bo, HttpServletResponse response) {
        List<QmCheckitemVo> list = qmCheckitemService.queryList(bo);
        ExcelUtil.exportExcel(list, "规程检验项目", QmCheckitemVo.class, response);
    }
    /**
     * èŽ·å–è§„ç¨‹æ£€éªŒé¡¹ç›®è¯¦ç»†ä¿¡æ¯
     *
     * @param id ä¸»é”®
     */
    @SaCheckPermission("qm:checkitem:query")
    @GetMapping("/{id}")
    public R<QmCheckitemVo> getInfo(@NotNull(message = "主键不能为空")
                                     @PathVariable String id) {
        return R.ok(qmCheckitemService.queryById(id));
    }
    /**
     * æ–°å¢žè§„程检验项目
     */
    @SaCheckPermission("qm:checkitem:add")
    @Log(title = "规程检验项目", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping()
    public R<Void> add(@Validated(AddGroup.class) @RequestBody QmCheckitemBo bo) {
        return toAjax(qmCheckitemService.insertByBo(bo));
    }
    /**
     * ä¿®æ”¹è§„程检验项目
     */
    @SaCheckPermission("qm:checkitem:edit")
    @Log(title = "规程检验项目", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping()
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody QmCheckitemBo bo) {
        return toAjax(qmCheckitemService.updateByBo(bo));
    }
    /**
     * åˆ é™¤è§„程检验项目
     *
     * @param ids ä¸»é”®ä¸²
     */
    @SaCheckPermission("qm:checkitem:remove")
    @Log(title = "规程检验项目", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
                          @PathVariable String[] ids) {
        return toAjax(qmCheckitemService.deleteWithValidByIds(List.of(ids), true));
    }
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmCheckitem.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
package org.dromara.qa.qm.domain;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
 * è§„程检验项目对象 qm_checkitem
 *
 * @author zhuguifei
 * @date 2026-03-12
 */
@Data
@TableName("qm_checkitem")
public class QmCheckitem {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ç¼–码
     */
    @TableId(value = "id")
    private String id;
    /**
     * æ£€éªŒé¡¹ç›®ä»£ç 
     */
    private String itemCode;
    /**
     * æ£€éªŒé¡¹ç›®åç§°
     */
    private String itemName;
    /**
     * å•位
     */
    private String unit;
    /**
     * å¯ç”¨
     */
    private Long enable;
    /**
     * åˆ é™¤
     */
    private Long del;
    /**
     * æ£€éªŒé¡¹æè¿°
     */
    private String itemDes;
    /**
     * è§„程代码
     */
    private String stdCode;
    /**
     * ä»ªå™¨æè¿°
     */
    private String instrumentDes;
    /**
     * ç¼ºé™·ä½ç½®-外观用
     */
    private String location;
    /**
     * åˆ†A,B,C,D四个级别
     */
    private String checkLevel;
    /**
     * æ˜¯å¦åˆæˆé¡¹
     */
    private Long ismix;
    /**
     * å…³è”项ID
     */
    private String rid;
    /**
     * ç±»åˆ« 0:成品 1辅料
     */
    private Long category;
    /**
     * ä»ªå™¨ç¼–码
     */
    private String instrumentCode;
    /**
     * åˆ†å€¼
     */
    private Long score;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmCheckitemBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
package org.dromara.qa.qm.domain.bo;
import org.dromara.qa.qm.domain.QmCheckitem;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
 * è§„程检验项目业务对象 qm_checkitem
 *
 * @author zhuguifei
 * @date 2026-03-12
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = QmCheckitem.class, reverseConvertGenerate = false)
public class QmCheckitemBo extends BaseEntity {
    /**
     * ç¼–码
     */
    @NotBlank(message = "编码不能为空", groups = { EditGroup.class })
    private String id;
    /**
     * æ£€éªŒé¡¹ç›®ä»£ç 
     */
    private String itemCode;
    /**
     * æ£€éªŒé¡¹ç›®åç§°
     */
    private String itemName;
    /**
     * å•位
     */
    private String unit;
    /**
     * å¯ç”¨
     */
    private Long enable;
    /**
     * åˆ é™¤
     */
    private Long del;
    /**
     * æ£€éªŒé¡¹æè¿°
     */
    private String itemDes;
    /**
     * è§„程代码
     */
    private String stdCode;
    /**
     * ä»ªå™¨æè¿°
     */
    private String instrumentDes;
    /**
     * ç¼ºé™·ä½ç½®-外观用
     */
    private String location;
    /**
     * åˆ†A,B,C,D四个级别
     */
    private String checkLevel;
    /**
     * æ˜¯å¦åˆæˆé¡¹
     */
    private Long ismix;
    /**
     * å…³è”项ID
     */
    private String rid;
    /**
     * ç±»åˆ« 0:成品 1辅料
     */
    private Long category;
    /**
     * ä»ªå™¨ç¼–码
     */
    private String instrumentCode;
    /**
     * åˆ†å€¼
     */
    private Long score;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmCheckitemVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,130 @@
package org.dromara.qa.qm.domain.vo;
import org.dromara.qa.qm.domain.QmCheckitem;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
 * è§„程检验项目视图对象 qm_checkitem
 *
 * @author zhuguifei
 * @date 2026-03-12
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = QmCheckitem.class)
public class QmCheckitemVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ç¼–码
     */
    @ExcelProperty(value = "编码")
    private String id;
    /**
     * æ£€éªŒé¡¹ç›®ä»£ç 
     */
    @ExcelProperty(value = "检验项目代码")
    private String itemCode;
    /**
     * æ£€éªŒé¡¹ç›®åç§°
     */
    @ExcelProperty(value = "检验项目名称")
    private String itemName;
    /**
     * å•位
     */
    @ExcelProperty(value = "单位")
    private String unit;
    /**
     * å¯ç”¨
     */
    @ExcelProperty(value = "启用")
    private Long enable;
    /**
     * åˆ é™¤
     */
    @ExcelProperty(value = "删除")
    private Long del;
    /**
     * æ£€éªŒé¡¹æè¿°
     */
    @ExcelProperty(value = "检验项描述")
    private String itemDes;
    /**
     * è§„程代码
     */
    @ExcelProperty(value = "规程代码")
    private String stdCode;
    /**
     * ä»ªå™¨æè¿°
     */
    @ExcelProperty(value = "仪器描述")
    private String instrumentDes;
    /**
     * ç¼ºé™·ä½ç½®-外观用
     */
    @ExcelProperty(value = "缺陷位置-外观用")
    private String location;
    /**
     * åˆ†A,B,C,D四个级别
     */
    @ExcelProperty(value = "分A,B,C,D四个级别")
    private String checkLevel;
    /**
     * æ˜¯å¦åˆæˆé¡¹
     */
    @ExcelProperty(value = "是否合成项")
    private Long ismix;
    /**
     * å…³è”项ID
     */
    @ExcelProperty(value = "关联项ID")
    private String rid;
    /**
     * ç±»åˆ« 0:成品 1辅料
     */
    @ExcelProperty(value = "类别 0:成品 1辅料")
    private Long category;
    /**
     * ä»ªå™¨ç¼–码
     */
    @ExcelProperty(value = "仪器编码")
    private String instrumentCode;
    /**
     * åˆ†å€¼
     */
    @ExcelProperty(value = "分值")
    private Long score;
    private List<QmCheckitemVo> children;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmCheckitemMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
package org.dromara.qa.qm.mapper;
import org.dromara.qa.qm.domain.QmCheckitem;
import org.dromara.qa.qm.domain.vo.QmCheckitemVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * è§„程检验项目Mapper接口
 *
 * @author zhuguifei
 * @date 2026-03-12
 */
public interface QmCheckitemMapper extends BaseMapperPlus<QmCheckitem, QmCheckitemVo> {
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmCheckitemService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,70 @@
package org.dromara.qa.qm.service;
import org.dromara.qa.qm.domain.vo.QmCheckitemVo;
import org.dromara.qa.qm.domain.bo.QmCheckitemBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
 * è§„程检验项目Service接口
 *
 * @author zhuguifei
 * @date 2026-03-12
 */
public interface IQmCheckitemService {
    /**
     * æŸ¥è¯¢è§„程检验项目
     *
     * @param id ä¸»é”®
     * @return è§„程检验项目
     */
    QmCheckitemVo queryById(String id);
    /**
     * åˆ†é¡µæŸ¥è¯¢è§„程检验项目列表
     *
     * @param bo        æŸ¥è¯¢æ¡ä»¶
     * @param pageQuery åˆ†é¡µå‚æ•°
     * @return è§„程检验项目分页列表
     */
    TableDataInfo<QmCheckitemVo> queryPageList(QmCheckitemBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢ç¬¦åˆæ¡ä»¶çš„规程检验项目列表
     *
     * @param bo æŸ¥è¯¢æ¡ä»¶
     * @return è§„程检验项目列表
     */
    List<QmCheckitemVo> queryList(QmCheckitemBo bo);
    List<QmCheckitemVo> queryTreeListByStdCode(String stdCode);
    /**
     * æ–°å¢žè§„程检验项目
     *
     * @param bo è§„程检验项目
     * @return æ˜¯å¦æ–°å¢žæˆåŠŸ
     */
    Boolean insertByBo(QmCheckitemBo bo);
    /**
     * ä¿®æ”¹è§„程检验项目
     *
     * @param bo è§„程检验项目
     * @return æ˜¯å¦ä¿®æ”¹æˆåŠŸ
     */
    Boolean updateByBo(QmCheckitemBo bo);
    /**
     * æ ¡éªŒå¹¶æ‰¹é‡åˆ é™¤è§„程检验项目信息
     *
     * @param ids     å¾…删除的主键集合
     * @param isValid æ˜¯å¦è¿›è¡Œæœ‰æ•ˆæ€§æ ¡éªŒ
     * @return æ˜¯å¦åˆ é™¤æˆåŠŸ
     */
    Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid);
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmCheckitemServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,164 @@
package org.dromara.qa.qm.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.dromara.qa.qm.domain.bo.QmCheckitemBo;
import org.dromara.qa.qm.domain.vo.QmCheckitemVo;
import org.dromara.qa.qm.domain.QmCheckitem;
import org.dromara.qa.qm.mapper.QmCheckitemMapper;
import org.dromara.qa.qm.service.IQmCheckitemService;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
 * è§„程检验项目Service业务层处理
 *
 * @author zhuguifei
 * @date 2026-03-12
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class QmCheckitemServiceImpl implements IQmCheckitemService {
    private final QmCheckitemMapper baseMapper;
    /**
     * æŸ¥è¯¢è§„程检验项目
     *
     * @param id ä¸»é”®
     * @return è§„程检验项目
     */
    @Override
    public QmCheckitemVo queryById(String id){
        return baseMapper.selectVoById(id);
    }
    /**
     * åˆ†é¡µæŸ¥è¯¢è§„程检验项目列表
     *
     * @param bo        æŸ¥è¯¢æ¡ä»¶
     * @param pageQuery åˆ†é¡µå‚æ•°
     * @return è§„程检验项目分页列表
     */
    @Override
    public TableDataInfo<QmCheckitemVo> queryPageList(QmCheckitemBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<QmCheckitem> lqw = buildQueryWrapper(bo);
        Page<QmCheckitemVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * æŸ¥è¯¢ç¬¦åˆæ¡ä»¶çš„规程检验项目列表
     *
     * @param bo æŸ¥è¯¢æ¡ä»¶
     * @return è§„程检验项目列表
     */
    @Override
    public List<QmCheckitemVo> queryList(QmCheckitemBo bo) {
        LambdaQueryWrapper<QmCheckitem> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    @Override
    public List<QmCheckitemVo> queryTreeListByStdCode(String stdCode) {
        List<QmCheckitemVo> roots = selectTreeNodes(stdCode, null);
        for (QmCheckitemVo root : roots) {
            List<QmCheckitemVo> children = selectTreeNodes(stdCode, root.getId());
            for (QmCheckitemVo child : children) {
                List<QmCheckitemVo> grandchildren = selectTreeNodes(stdCode, child.getId());
                child.setChildren(grandchildren);
            }
            root.setChildren(children);
        }
        return roots;
    }
    private List<QmCheckitemVo> selectTreeNodes(String stdCode, String rid) {
        if (StringUtils.isBlank(stdCode)) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<QmCheckitem> lqw = Wrappers.lambdaQuery();
        lqw.eq(QmCheckitem::getStdCode, stdCode);
        lqw.ne(QmCheckitem::getDel, 1L);
        if (rid == null) {
            lqw.isNull(QmCheckitem::getRid);
        } else {
            lqw.eq(QmCheckitem::getRid, rid);
        }
        lqw.orderByAsc(QmCheckitem::getId);
        return baseMapper.selectVoList(lqw);
    }
    private LambdaQueryWrapper<QmCheckitem> buildQueryWrapper(QmCheckitemBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<QmCheckitem> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(QmCheckitem::getId);
        lqw.like(StringUtils.isNotBlank(bo.getItemCode()), QmCheckitem::getItemCode, bo.getItemCode());
        lqw.like(StringUtils.isNotBlank(bo.getItemName()), QmCheckitem::getItemName, bo.getItemName());
        return lqw;
    }
    /**
     * æ–°å¢žè§„程检验项目
     *
     * @param bo è§„程检验项目
     * @return æ˜¯å¦æ–°å¢žæˆåŠŸ
     */
    @Override
    public Boolean insertByBo(QmCheckitemBo bo) {
        QmCheckitem add = MapstructUtils.convert(bo, QmCheckitem.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }
    /**
     * ä¿®æ”¹è§„程检验项目
     *
     * @param bo è§„程检验项目
     * @return æ˜¯å¦ä¿®æ”¹æˆåŠŸ
     */
    @Override
    public Boolean updateByBo(QmCheckitemBo bo) {
        QmCheckitem update = MapstructUtils.convert(bo, QmCheckitem.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(QmCheckitem entity){
        //TODO åšä¸€äº›æ•°æ®æ ¡éªŒ,如唯一约束
    }
    /**
     * æ ¡éªŒå¹¶æ‰¹é‡åˆ é™¤è§„程检验项目信息
     *
     * @param ids     å¾…删除的主键集合
     * @param isValid æ˜¯å¦è¿›è¡Œæœ‰æ•ˆæ€§æ ¡éªŒ
     * @return æ˜¯å¦åˆ é™¤æˆåŠŸ
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
        if(isValid){
            //TODO åšä¸€äº›ä¸šåŠ¡ä¸Šçš„æ ¡éªŒ,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmCheckitemMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.qa.qm.mapper.QmCheckitemMapper">
</mapper>
ruoyi-plus-soybean/src/router/elegant/imports.ts
@@ -38,6 +38,7 @@
  monitor_online: () => import("@/views/monitor/online/index.vue"),
  monitor_operlog: () => import("@/views/monitor/operlog/index.vue"),
  qm_batch: () => import("@/views/qm/batch/index.vue"),
  qm_checkitem: () => import("@/views/qm/checkitem/index.vue"),
  qm_std: () => import("@/views/qm/std/index.vue"),
  system_client: () => import("@/views/system/client/index.vue"),
  system_config: () => import("@/views/system/config/index.vue"),
ruoyi-plus-soybean/src/router/elegant/routes.ts
@@ -266,6 +266,15 @@
        }
      },
      {
        name: 'qm_checkitem',
        path: '/qm/checkitem',
        component: 'view.qm_checkitem',
        meta: {
          title: 'qm_checkitem',
          i18nKey: 'route.qm_checkitem'
        }
      },
      {
        name: 'qm_std',
        path: '/qm/std',
        component: 'view.qm_std',
ruoyi-plus-soybean/src/router/elegant/transform.ts
@@ -193,6 +193,7 @@
  "monitor_operlog": "/monitor/operlog",
  "qm": "/qm",
  "qm_batch": "/qm/batch",
  "qm_checkitem": "/qm/checkitem",
  "qm_std": "/qm/std",
  "social-callback": "/social-callback",
  "system": "/system",
ruoyi-plus-soybean/src/service/api/qm/checkitem.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
import { request } from '@/service/request';
/** èŽ·å–è§„ç¨‹æ£€éªŒé¡¹ç›®åˆ—è¡¨ */
export function fetchGetCheckitemList (params?: Api.Qm.CheckitemSearchParams) {
    return request<Api.Qm.CheckitemList>({
        url: '/qm/checkitem/list',
        method: 'get',
        params
    });
}
/** èŽ·å–è§„ç¨‹æ£€éªŒé¡¹ç›®åˆ—è¡¨ */
export function fetchGetCheckitemTree (params?: Api.Qm.CheckitemSearchParams) {
  return request<Api.Qm.CheckitemList>({
    url: '/qm/checkitem/tree',
    method: 'get',
    params
  });
}
/** æ–°å¢žè§„程检验项目 */
export function fetchCreateCheckitem (data: Api.Qm.CheckitemOperateParams) {
    return request<boolean>({
        url: '/qm/checkitem',
        method: 'post',
        data
    });
}
/** ä¿®æ”¹è§„程检验项目 */
export function fetchUpdateCheckitem (data: Api.Qm.CheckitemOperateParams) {
    return request<boolean>({
        url: '/qm/checkitem',
        method: 'put',
        data
    });
}
/** æ‰¹é‡åˆ é™¤è§„程检验项目 */
export function fetchBatchDeleteCheckitem (ids: CommonType.IdType[]) {
    return request<boolean>({
        url: `/qm/checkitem/${ids.join(',')}`,
        method: 'delete'
    });
}
ruoyi-plus-soybean/src/typings/api/qm.checkitem.api.d.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,88 @@
/**
 * Namespace Api
 *
 * All backend api type
 */
declare namespace Api {
    /**
     * namespace Qm
     *
     * backend api module: "Qm"
     */
    namespace Qm {
        /** checkitem */
        type Checkitem = Common.CommonRecord<{
            /** ç¼–码 */
                id: CommonType.IdType;
            /** æ£€éªŒé¡¹ç›®ä»£ç  */
                itemCode: string;
            /** æ£€éªŒé¡¹ç›®åç§° */
                itemName: string;
            /** å•位 */
                unit: string;
            /** å¯ç”¨ */
                enable: number;
            /** åˆ é™¤ */
                del: number;
            /** æ£€éªŒé¡¹æè¿° */
                itemDes: string;
            /** è§„程代码 */
                stdCode: string;
            /** ä»ªå™¨æè¿° */
                instrumentDes: string;
            /** ç¼ºé™·ä½ç½®-外观用 */
                location: string;
            /** åˆ†A,B,C,D四个级别 */
                checkLevel: string;
            /** æ˜¯å¦åˆæˆé¡¹ */
                ismix: number;
            /** å…³è”项ID */
                rid: CommonType.IdType;
            /** ç±»åˆ« 0:成品 1辅料 */
                category: number;
            /** ä»ªå™¨ç¼–码 */
                instrumentCode: string;
            /** åˆ†å€¼ */
                score: number;
            /** å­èŠ‚ç‚¹ */
                children?: Api.Qm.Checkitem[];
        }>;
        /** checkitem search params */
        type CheckitemSearchParams = CommonType.RecordNullable<
            Pick<
                Api.Qm.Checkitem,
                        | 'itemCode'
                        | 'itemName'
                        | 'stdCode'
            > &
            Api.Common.CommonSearchParams
        >;
        /** checkitem operate params */
        type CheckitemOperateParams = CommonType.RecordNullable<
            Pick<
                Api.Qm.Checkitem,
                        | 'id'
                        | 'itemCode'
                        | 'itemName'
                        | 'unit'
                        | 'enable'
                        | 'del'
                        | 'itemDes'
                        | 'stdCode'
                        | 'instrumentDes'
                        | 'location'
                        | 'checkLevel'
                        | 'ismix'
                        | 'rid'
                        | 'category'
                        | 'instrumentCode'
                        | 'score'
            >
        >;
        /** checkitem list */
        type CheckitemList = Api.Common.PaginatingQueryRecord<Checkitem>;
    }
}
ruoyi-plus-soybean/src/typings/elegant-router.d.ts
@@ -47,6 +47,7 @@
    "monitor_operlog": "/monitor/operlog";
    "qm": "/qm";
    "qm_batch": "/qm/batch";
    "qm_checkitem": "/qm/checkitem";
    "qm_std": "/qm/std";
    "social-callback": "/social-callback";
    "system": "/system";
@@ -157,6 +158,7 @@
    | "monitor_online"
    | "monitor_operlog"
    | "qm_batch"
    | "qm_checkitem"
    | "qm_std"
    | "system_client"
    | "system_config"
ruoyi-plus-soybean/src/views/qm/checkitem/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,223 @@
<script setup lang="tsx">
import { ref } from 'vue';
import { NDivider } from 'naive-ui';
import { fetchBatchDeleteCheckitem, fetchGetCheckitemList } from '@/service/api/qm/checkitem';
import { useAppStore } from '@/store/modules/app';
import { useAuth } from '@/hooks/business/auth';
import { useDownload } from '@/hooks/business/download';
import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
import { $t } from '@/locales';
import ButtonIcon from '@/components/custom/button-icon.vue';
import CheckitemOperateDrawer from './modules/checkitem-operate-drawer.vue';
import CheckitemSearch from './modules/checkitem-search.vue';
defineOptions({
  name: 'CheckitemList'
});
const appStore = useAppStore();
const { download } = useDownload();
const { hasAuth } = useAuth();
const searchParams = ref<Api.Qm.CheckitemSearchParams>({
  pageNum: 1,
  pageSize: 10,
  itemCode: null,
  itemName: null,
  params: {}
});
const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
  useNaivePaginatedTable({
  api: () => fetchGetCheckitemList(searchParams.value),
  transform: response => defaultTransform(response),
  onPaginationParamsChange: params => {
    searchParams.value.pageNum = params.page;
    searchParams.value.pageSize = params.pageSize;
  },
  columns: () => [
    {
      type: 'selection',
      align: 'center',
      width: 48
    },
    {
      key: 'index',
      title: $t('common.index'),
      align: 'center',
      width: 64,
      render: (_, index) => index + 1
    },
    {
      key: 'itemCode',
      title: '项目代码',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'itemName',
      title: '项目名称',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'location',
      title: '位置',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'instrumentDes',
      title: '仪器描述',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'itemDes',
      title: '项目描述',
      align: 'center',
      width: 200
    },
    {
      key: 'ismix',
      title: '是否合成项',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'score',
      title: '分值',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'enable',
      title: '启用',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'operate',
      title: $t('common.operate'),
      align: 'center',
      width: 130,
      render: row => {
        const divider = () => {
          if (!hasAuth('qm:checkitem:edit') || !hasAuth('qm:checkitem:remove')) {
            return null;
          }
          return <NDivider vertical />;
        };
        const editBtn = () => {
          if (!hasAuth('qm:checkitem:edit')) {
            return null;
          }
          return (
            <ButtonIcon
              text
              type="primary"
              icon="material-symbols:drive-file-rename-outline-outline"
              tooltipContent={$t('common.edit')}
              onClick={() => edit(row.id)}
            />
          );
        };
        const deleteBtn = () => {
          if (!hasAuth('qm:checkitem:remove')) {
            return null;
          }
          return (
            <ButtonIcon
              text
              type="error"
              icon="material-symbols:delete-outline"
              tooltipContent={$t('common.delete')}
              popconfirmContent={$t('common.confirmDelete')}
              onPositiveClick={() => handleDelete(row.id)}
            />
          );
        };
        return (
          <div class="flex-center gap-8px">
            {editBtn()}
            {divider()}
            {deleteBtn()}
          </div>
        );
      }
    }
  ]
});
const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
  useTableOperate(data, 'id', getData);
async function handleBatchDelete() {
  // request
  const { error } = await fetchBatchDeleteCheckitem(checkedRowKeys.value);
  if (error) return;
  onBatchDeleted();
}
async function handleDelete(id: CommonType.IdType) {
  // request
  const { error } = await fetchBatchDeleteCheckitem([id]);
  if (error) return;
  onDeleted();
}
function edit(id: CommonType.IdType) {
  handleEdit(id);
}
function handleExport() {
  download('/qm/checkitem/export', searchParams.value, `规程检验项目_${new Date().getTime()}.xlsx`);
}
</script>
<template>
  <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
    <CheckitemSearch v-model:model="searchParams" @search="getDataByPage" />
    <NCard title="规程检验项目列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
      <template #header-extra>
        <TableHeaderOperation
          v-model:columns="columnChecks"
          :disabled-delete="checkedRowKeys.length === 0"
          :loading="loading"
          :show-add="hasAuth('qm:checkitem:add')"
          :show-delete="hasAuth('qm:checkitem:remove')"
          :show-export="hasAuth('qm:checkitem:export')"
          @add="handleAdd"
          @delete="handleBatchDelete"
          @export="handleExport"
          @refresh="getData"
        />
      </template>
      <NDataTable
        v-model:checked-row-keys="checkedRowKeys"
        :columns="columns"
        :data="data"
        size="small"
        :flex-height="!appStore.isMobile"
        :scroll-x="scrollX"
        :loading="loading"
        remote
        :row-key="row => row.id"
        :pagination="mobilePagination"
        class="sm:h-full"
      />
      <CheckitemOperateDrawer
        v-model:visible="drawerVisible"
        :operate-type="operateType"
        :row-data="editingData"
        @submitted="getDataByPage"
      />
    </NCard>
  </div>
</template>
<style scoped></style>
ruoyi-plus-soybean/src/views/qm/checkitem/modules/checkitem-operate-drawer.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,178 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { jsonClone } from '@sa/utils';
import { fetchCreateCheckitem, fetchUpdateCheckitem } from '@/service/api/qm/checkitem';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales';
defineOptions({
  name: 'CheckitemOperateDrawer'
});
interface Props {
  /** the type of operation */
  operateType: NaiveUI.TableOperateType;
  /** the edit row data */
  rowData?: Api.Qm.Checkitem | null;
}
const props = defineProps<Props>();
interface Emits {
  (e: 'submitted'): void;
}
const emit = defineEmits<Emits>();
const visible = defineModel<boolean>('visible', {
  default: false
});
const { formRef, validate, restoreValidation } = useNaiveForm();
const { createRequiredRule } = useFormRules();
const title = computed(() => {
  const titles: Record<NaiveUI.TableOperateType, string> = {
    add: '新增规程检验项目',
    edit: '编辑规程检验项目'
  };
  return titles[props.operateType];
});
type Model = Api.Qm.CheckitemOperateParams;
const model = ref<Model>(createDefaultModel());
function createDefaultModel(): Model {
  return {
      id: '',
      itemCode: '',
      itemName: '',
      unit: '',
      enable: null,
      del: null,
      itemDes: '',
      stdCode: '',
      instrumentDes: '',
      location: '',
      checkLevel: '',
      ismix: null,
      rid: '',
      category: null,
      instrumentCode: '',
      score: null
  };
}
type RuleKey = Extract<
  keyof Model,
  | 'id'
>;
const rules: Record<RuleKey, App.Global.FormRule> = {
  id: createRequiredRule('编码不能为空'),
};
function handleUpdateModelWhenEdit() {
  model.value = createDefaultModel();
  if (props.operateType === 'edit' && props.rowData) {
    Object.assign(model.value, jsonClone(props.rowData));
  }
}
function closeDrawer() {
  visible.value = false;
}
async function handleSubmit() {
  await validate();
  const { id, itemCode, itemName, unit, enable, del, itemDes, stdCode, instrumentDes, location, checkLevel, ismix, rid, category, instrumentCode, score } = model.value;
  // request
  if (props.operateType === 'add') {
    const { error } = await fetchCreateCheckitem({ itemCode, itemName, unit, enable, del, itemDes, stdCode, instrumentDes, location, checkLevel, ismix, rid, category, instrumentCode, score });
    if (error) return;
  }
  if (props.operateType === 'edit') {
    const { error } = await fetchUpdateCheckitem({ id, itemCode, itemName, unit, enable, del, itemDes, stdCode, instrumentDes, location, checkLevel, ismix, rid, category, instrumentCode, score });
    if (error) return;
  }
  window.$message?.success($t('common.updateSuccess'));
  closeDrawer();
  emit('submitted');
}
watch(visible, () => {
  if (visible.value) {
    handleUpdateModelWhenEdit();
    restoreValidation();
    getTreeList();
  }
});
</script>
<template>
  <NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
    <NDrawerContent :title="title" :native-scrollbar="false" closable>
      <NForm ref="formRef" :model="model" :rules="rules">
        <NFormItem label="检验项目代码" path="itemCode">
          <NInput v-model:value="model.itemCode" placeholder="请输入检验项目代码" />
        </NFormItem>
        <NFormItem label="检验项目名称" path="itemName">
          <NInput v-model:value="model.itemName" placeholder="请输入检验项目名称" />
        </NFormItem>
        <NFormItem label="单位" path="unit">
          <NInput v-model:value="model.unit" placeholder="请输入单位" />
        </NFormItem>
        <NFormItem label="启用" path="enable">
          <NInput v-model:value="model.enable" placeholder="请输入启用" />
        </NFormItem>
        <NFormItem label="删除" path="del">
          <NInput v-model:value="model.del" placeholder="请输入删除" />
        </NFormItem>
        <NFormItem label="检验项描述" path="itemDes">
          <NInput v-model:value="model.itemDes" placeholder="请输入检验项描述" />
        </NFormItem>
        <NFormItem label="规程代码" path="stdCode">
          <NInput v-model:value="model.stdCode" placeholder="请输入规程代码" />
        </NFormItem>
        <NFormItem label="仪器描述" path="instrumentDes">
          <NInput v-model:value="model.instrumentDes" placeholder="请输入仪器描述" />
        </NFormItem>
        <NFormItem label="缺陷位置-外观用" path="location">
          <NInput v-model:value="model.location" placeholder="请输入缺陷位置-外观用" />
        </NFormItem>
        <NFormItem label="分A,B,C,D四个级别" path="checkLevel">
          <NInput v-model:value="model.checkLevel" placeholder="请输入分A,B,C,D四个级别" />
        </NFormItem>
        <NFormItem label="是否合成项" path="ismix">
          <NInput v-model:value="model.ismix" placeholder="请输入是否合成项" />
        </NFormItem>
        <NFormItem label="关联项ID" path="rid">
          <NInput v-model:value="model.rid" placeholder="请输入关联项ID" />
        </NFormItem>
        <NFormItem label="类别 0:成品 1辅料" path="category">
          <NInput v-model:value="model.category" placeholder="请输入类别 0:成品 1辅料" />
        </NFormItem>
        <NFormItem label="仪器编码" path="instrumentCode">
          <NInput v-model:value="model.instrumentCode" placeholder="请输入仪器编码" />
        </NFormItem>
        <NFormItem label="分值" path="score">
          <NInput v-model:value="model.score" placeholder="请输入分值" />
        </NFormItem>
      </NForm>
      <template #footer>
        <NSpace :size="16">
          <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
          <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
        </NSpace>
      </template>
    </NDrawerContent>
  </NDrawer>
</template>
<style scoped></style>
ruoyi-plus-soybean/src/views/qm/checkitem/modules/checkitem-search.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
<script setup lang="ts">
import { toRaw } from 'vue';
import { jsonClone } from '@sa/utils';
import { useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales';
defineOptions({
  name: 'CheckitemSearch'
});
interface Emits {
  (e: 'search'): void;
}
const emit = defineEmits<Emits>();
const { formRef, validate, restoreValidation } = useNaiveForm();
const model = defineModel<Api.Qm.CheckitemSearchParams>('model', { required: true });
const defaultModel = jsonClone(toRaw(model.value));
function resetModel() {
  Object.assign(model.value, defaultModel);
}
async function reset() {
  await restoreValidation();
  resetModel();
  emit('search');
}
async function search() {
  await validate();
  emit('search');
}
</script>
<template>
  <NCard :bordered="false" size="small" class="card-wrapper">
    <NCollapse>
      <NCollapseItem :title="$t('common.search')" name="qm-checkitem-search">
        <NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
          <NGrid responsive="screen" item-responsive>
            <NFormItemGi span="24 s:12 m:6" label="检验项目代码" label-width="auto" path="itemCode" class="pr-24px">
              <NInput v-model:value="model.itemCode" placeholder="请输入检验项目代码" />
            </NFormItemGi>
            <NFormItemGi span="24 s:12 m:6" label="检验项目名称" label-width="auto" path="itemName" class="pr-24px">
              <NInput v-model:value="model.itemName" placeholder="请输入检验项目名称" />
            </NFormItemGi>
            <NFormItemGi :show-feedback="false" span="24" class="pr-24px">
              <NSpace class="w-full" justify="end">
                <NButton @click="reset">
                  <template #icon>
                    <icon-ic-round-refresh class="text-icon" />
                  </template>
                  {{ $t('common.reset') }}
                </NButton>
                <NButton type="primary" ghost @click="search">
                  <template #icon>
                    <icon-ic-round-search class="text-icon" />
                  </template>
                  {{ $t('common.search') }}
                </NButton>
              </NSpace>
            </NFormItemGi>
          </NGrid>
        </NForm>
      </NCollapseItem>
    </NCollapse>
  </NCard>
</template>
<style scoped></style>
ruoyi-plus-soybean/src/views/qm/std/index.vue
@@ -11,6 +11,7 @@
import ButtonIcon from '@/components/custom/button-icon.vue';
import StdOperateDrawer from './modules/std-operate-drawer.vue';
import StdSearch from './modules/std-search.vue';
import StdSubTable from './modules/std-sub-table.vue';
defineOptions({
  name: 'StdList'
@@ -20,6 +21,8 @@
const appStore = useAppStore();
const { download } = useDownload();
const { hasAuth } = useAuth();
const selectedStdId = ref<CommonType.IdType | null>(null);
const searchParams = ref<Api.Qm.StdSearchParams>({
  pageNum: 1,
@@ -76,7 +79,9 @@
      minWidth: 120,
      render: row => {
        const v = String(row?.category ?? '');
        return v === '0' ? '成品' : v === '1' ? '辅料' : v;
        if (v === '0') return '成品';
        if (v === '1') return '辅料';
        return v;
      }
    },
    {
@@ -99,7 +104,9 @@
      minWidth: 120,
      render: row => {
        const v = String(row?.enable ?? '');
        return v === '0' ? '停用' : v === '1' ? '启用' : v;
        if (v === '0') return '停用';
        if (v === '1') return '启用';
        return v;
      }
    },
    {
@@ -183,47 +190,75 @@
function handleExport() {
  download('/qm/std/export', searchParams.value, `判定规程_${new Date().getTime()}.xlsx`);
}
function handleRowClick(row: any) {
  return {
    onClick: (e: MouseEvent) => {
      const target = e.target as HTMLElement | null;
      if (target?.closest('.n-checkbox') || target?.closest('.n-button') || target?.closest('a')) return;
      selectedStdId.value = row.id;
    },
    style: 'cursor: pointer;'
  };
}
</script>
<template>
  <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
    <StdSearch v-model:model="searchParams" @search="getDataByPage" />
    <NCard title="判定规程列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
      <template #header-extra>
        <TableHeaderOperation
          v-model:columns="columnChecks"
          :disabled-delete="checkedRowKeys.length === 0"
          :loading="loading"
          :show-add="hasAuth('qm:std:add')"
          :show-delete="hasAuth('qm:std:remove')"
          :show-export="hasAuth('qm:std:export')"
          @add="handleAdd"
          @delete="handleBatchDelete"
          @export="handleExport"
          @refresh="getData"
        />
      </template>
      <NDataTable
        v-model:checked-row-keys="checkedRowKeys"
        :columns="columns"
        :data="data"
    <div class="flex-col-stretch gap-16px sm:flex-1-hidden">
      <NCard
        title="判定规程列表"
        :bordered="false"
        size="small"
        :flex-height="!appStore.isMobile"
        :scroll-x="scrollX"
        :loading="loading"
        remote
        :row-key="row => row.id"
        :pagination="mobilePagination"
        class="sm:h-full"
      />
      <StdOperateDrawer
        v-model:visible="drawerVisible"
        :operate-type="operateType"
        :row-data="editingData"
        @submitted="getDataByPage"
      />
    </NCard>
        class="card-wrapper flex-col-stretch sm:flex-1-hidden"
        :content-style="{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }"
      >
        <template #header-extra>
          <TableHeaderOperation
            v-model:columns="columnChecks"
            :disabled-delete="checkedRowKeys.length === 0"
            :loading="loading"
            :show-add="hasAuth('qm:std:add')"
            :show-delete="hasAuth('qm:std:remove')"
            :show-export="hasAuth('qm:std:export')"
            @add="handleAdd"
            @delete="handleBatchDelete"
            @export="handleExport"
            @refresh="getData"
          />
        </template>
        <NDataTable
          v-model:checked-row-keys="checkedRowKeys"
          :columns="columns"
          :data="data"
          size="small"
          :flex-height="!appStore.isMobile"
          :scroll-x="scrollX"
          :loading="loading"
          remote
          :row-key="row => row.id"
          :pagination="mobilePagination"
          :row-props="handleRowClick"
          class="flex-1-hidden"
        />
        <StdOperateDrawer
          v-model:visible="drawerVisible"
          :operate-type="operateType"
          :row-data="editingData"
          @submitted="getDataByPage"
        />
      </NCard>
      <StdSubTable :std-id="selectedStdId" class="sm:flex-1-hidden" />
    </div>
  </div>
</template>
<style scoped></style>
<style scoped>
:deep(.n-data-table-th),
:deep(.n-data-table-td) {
  padding: 4px 6px;
  overflow: hidden;
}
</style>
ruoyi-plus-soybean/src/views/qm/std/modules/std-sub-table.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,151 @@
<script setup lang="tsx">
import { computed, ref, watch } from 'vue';
import { useLoading } from '@sa/hooks';
import { $t } from '@/locales';
import { fetchGetCheckitemTree } from '@/service/api/qm/checkitem';
import type { DataTableColumns, DataTableRowKey } from 'naive-ui';
defineOptions({
  name: 'StdSubTable'
});
interface Props {
  stdId?: CommonType.IdType | null;
}
const props = withDefaults(defineProps<Props>(), {
  stdId: null
});
interface StdSubRow extends Api.Qm.Checkitem {
  children?: StdSubRow[];
}
const { loading, startLoading, endLoading } = useLoading();
const rows = ref<StdSubRow[]>([]);
async function getSubList() {
  if (!props.stdId) {
    rows.value = [];
    return;
  }
  startLoading();
  try {
    const { data, error } = await fetchGetCheckitemTree({
      pageNum: 1,
      pageSize: 9999,
      stdCode: String(props.stdId)
    });
    if (error) {
      rows.value = [];
      return;
    }
    rows.value = data.rows;
  } finally {
    endLoading();
  }
}
watch(
  () => props.stdId,
  async () => {
    await getSubList();
  },
  { immediate: true }
);
const columns = computed<DataTableColumns<StdSubRow>>(() => [
  {
    key: 'index',
    title: $t('common.index'),
    align: 'center',
    width: 56,
    render: (_: any, index: number) => index + 1
  },
  {
    key: 'itemName',
    title: '项目名称',
    align: 'left',
    width: 400,
    tree: true
  } as any,
  {
    key: 'itemCode',
    title: '项目代码',
    align: 'center',
    width: 180
  },
  {
    key: 'unit',
    title: '单位',
    align: 'center',
    width: 80
  },
  {
    key: 'enable',
    title: '启用',
    align: 'center',
    width: 72,
    render: row => (String(row.enable) === '1' ? '启用' : '停用')
  },
  {
    key: 'score',
    title: '分值',
    align: 'center',
    width: 80
  },
  {
    key: 'itemDes',
    title: '描述',
    align: 'center',
    minWidth: 160
  }
]);
function rowKey(row: StdSubRow): DataTableRowKey {
  return String(row.id);
}
</script>
<template>
  <NCard
    title="规程明细"
    :bordered="false"
    size="small"
    class="flex-col-stretch card-wrapper"
    :content-style="{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }"
  >
    <template #header-extra>
      <span class="text-13px text-gray-500">{{ props.stdId ? `STD CODE:${props.stdId}` : '' }}</span>
    </template>
    <NSpin :show="loading" class="h-full" content-class="h-full">
      <div v-if="!props.stdId" class="h-full flex-center text-gray-400">请点击上方表格行查看明细</div>
      <NDataTable
        v-else
        :columns="columns as any"
        :data="rows"
        size="small"
        flex-height
        children-key="children"
        :row-key="rowKey"
        default-expand-all
        striped
        style="height: 200px"
      />
    </NSpin>
  </NCard>
</template>
<style scoped>
:deep(.n-card__content) {
  padding: 8px 12px;
}
:deep(.n-data-table-th),
:deep(.n-data-table-td) {
  padding: 4px 6px;
}
</style>