广丰卷烟厂数采质量分析系统
zhuguifei
2026-03-12 5740eb93928f3cb8e17c3fa5f082f42072ebbc31
feat: 新增基础数据维护-判定规程维护界面和后端接口
已添加14个文件
1553 ■■■■■ 文件已修改
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmStdController.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmStd.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmStdBo.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmStdVo.java 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmStdMapper.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmStdService.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/impl/QmStdServiceImpl.java 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qa/qm/QmStdMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/service/api/qm/std.ts 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/typings/api/qm.std.api.d.ts 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/analy/store-silk/modules/store-silk-sankey.vue 282 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/std/index.vue 229 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/std/modules/std-operate-drawer.vue 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-plus-soybean/src/views/qm/std/modules/std-search.vue 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/controller/QmStdController.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.dromara.qa.qm.domain.bo.QmStdBo;
import org.dromara.qa.qm.domain.vo.QmStdVo;
import org.dromara.qa.qm.service.IQmStdService;
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.common.mybatis.core.page.TableDataInfo;
/**
 * åˆ¤å®šè§„程
 *
 * @author zhuguifei
 * @date 2026-03-11
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/qm/std")
public class QmStdController extends BaseController {
    private final IQmStdService qmStdService;
    /**
     * æŸ¥è¯¢åˆ¤å®šè§„程列表
     */
    @SaCheckPermission("qm:std:list")
    @GetMapping("/list")
    public TableDataInfo<QmStdVo> list(QmStdBo bo, PageQuery pageQuery) {
        return qmStdService.queryPageList(bo, pageQuery);
    }
    /**
     * å¯¼å‡ºåˆ¤å®šè§„程列表
     */
    @SaCheckPermission("qm:std:export")
    @Log(title = "判定规程", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(QmStdBo bo, HttpServletResponse response) {
        List<QmStdVo> list = qmStdService.queryList(bo);
        ExcelUtil.exportExcel(list, "判定规程", QmStdVo.class, response);
    }
    /**
     * èŽ·å–åˆ¤å®šè§„ç¨‹è¯¦ç»†ä¿¡æ¯
     *
     * @param id ä¸»é”®
     */
    @SaCheckPermission("qm:std:query")
    @GetMapping("/{id}")
    public R<QmStdVo> getInfo(@NotNull(message = "主键不能为空")
                                     @PathVariable String id) {
        return R.ok(qmStdService.queryById(id));
    }
    /**
     * æ–°å¢žåˆ¤å®šè§„程
     */
    @SaCheckPermission("qm:std:add")
    @Log(title = "判定规程", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping()
    public R<Void> add(@Validated(AddGroup.class) @RequestBody QmStdBo bo) {
        return toAjax(qmStdService.insertByBo(bo));
    }
    /**
     * ä¿®æ”¹åˆ¤å®šè§„程
     */
    @SaCheckPermission("qm:std:edit")
    @Log(title = "判定规程", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping()
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody QmStdBo bo) {
        return toAjax(qmStdService.updateByBo(bo));
    }
    /**
     * åˆ é™¤åˆ¤å®šè§„程
     *
     * @param ids ä¸»é”®ä¸²
     */
    @SaCheckPermission("qm:std:remove")
    @Log(title = "判定规程", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
                          @PathVariable String[] ids) {
        return toAjax(qmStdService.deleteWithValidByIds(List.of(ids), true));
    }
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/QmStd.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,97 @@
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_std
 *
 * @author zhuguifei
 * @date 2026-03-11
 */
@Data
@TableName("qm_std")
public class QmStd {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ç¼–码
     */
    @TableId(value = "id")
    private String id;
    /**
     * è§„程代码
     */
    private String stdCode;
    /**
     * è§„程名称
     */
    private String stdName;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    private Date cdate;
    /**
     * ç‰ˆæœ¬å·
     */
    private Long ver;
    /**
     * å¯ç”¨æ ‡è¯†
     */
    private Long enable;
    /**
     * æ£€éªŒé¡¹ç›®code
     */
    private String itemCod;
    /**
     * æ£€éªŒé¡¹ç›®åç§°
     */
    private String itemNam;
    /**
     * åˆ¤å®šç±»åž‹  0-手动判定,1-上下限判定,2-平均值判定,3-SD值判定,4-CV值判定,5-超标数判定
     */
    private Long typ;
    /**
     * å¤‡æ³¨
     */
    private String stdDes;
    /**
     * æ£€éªŒçº§åˆ«
     */
    private Long checkLevel;
    /**
     * ç±»åž‹  ï¼š 0-成品  1-辅料
     */
    private Long category;
    /**
     * $column.columnComment
     */
    private String matfltype;
    /**
     * $column.columnComment
     */
    private String matflname;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/bo/QmStdBo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,97 @@
package org.dromara.qa.qm.domain.bo;
import org.dromara.qa.qm.domain.QmStd;
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_std
 *
 * @author zhuguifei
 * @date 2026-03-11
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = QmStd.class, reverseConvertGenerate = false)
public class QmStdBo extends BaseEntity {
    /**
     * ç¼–码
     */
    @NotBlank(message = "编码不能为空", groups = { EditGroup.class })
    private String id;
    /**
     * è§„程代码
     */
    private String stdCode;
    /**
     * è§„程名称
     */
    private String stdName;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    private Date cdate;
    /**
     * ç‰ˆæœ¬å·
     */
    private Long ver;
    /**
     * å¯ç”¨æ ‡è¯†
     */
    private Long enable;
    /**
     * æ£€éªŒé¡¹ç›®code
     */
    private String itemCod;
    /**
     * æ£€éªŒé¡¹ç›®åç§°
     */
    private String itemNam;
    /**
     * åˆ¤å®šç±»åž‹  0-手动判定,1-上下限判定,2-平均值判定,3-SD值判定,4-CV值判定,5-超标数判定
     */
    private Long typ;
    /**
     * å¤‡æ³¨
     */
    private String stdDes;
    /**
     * æ£€éªŒçº§åˆ«
     */
    private Long checkLevel;
    /**
     * ç±»åž‹  ï¼š 0-成品  1-辅料
     */
    private Long category;
    /**
     * $column.columnComment
     */
    private String matfltype;
    /**
     * $column.columnComment
     */
    private String matflname;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/domain/vo/QmStdVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,120 @@
package org.dromara.qa.qm.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.qa.qm.domain.QmStd;
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_std
 *
 * @author zhuguifei
 * @date 2026-03-11
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = QmStd.class)
public class QmStdVo implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * ç¼–码
     */
    @ExcelProperty(value = "编码")
    private String id;
    /**
     * è§„程代码
     */
    @ExcelProperty(value = "规程代码")
    private String stdCode;
    /**
     * è§„程名称
     */
    @ExcelProperty(value = "规程名称")
    private String stdName;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    @ExcelProperty(value = "创建时间")
    private Date cdate;
    /**
     * ç‰ˆæœ¬å·
     */
    @ExcelProperty(value = "版本号")
    private Long ver;
    /**
     * å¯ç”¨æ ‡è¯†
     */
    @ExcelProperty(value = "启用标识")
    private Long enable;
    /**
     * æ£€éªŒé¡¹ç›®code
     */
    @ExcelProperty(value = "检验项目code")
    private String itemCod;
    /**
     * æ£€éªŒé¡¹ç›®åç§°
     */
    @ExcelProperty(value = "检验项目名称")
    private String itemNam;
    /**
     * åˆ¤å®šç±»åž‹  0-手动判定,1-上下限判定,2-平均值判定,3-SD值判定,4-CV值判定,5-超标数判定
     */
    @ExcelProperty(value = "判定类型  0-手动判定,1-上下限判定,2-平均值判定,3-SD值判定,4-CV值判定,5-超标数判定")
    private Long typ;
    /**
     * å¤‡æ³¨
     */
    @ExcelProperty(value = "备注")
    private String stdDes;
    /**
     * æ£€éªŒçº§åˆ«
     */
    @ExcelProperty(value = "检验级别")
    private Long checkLevel;
    /**
     * ç±»åž‹  ï¼š 0-成品  1-辅料
     */
    @ExcelProperty(value = "类型  ï¼š 0-成品  1-辅料")
    private Long category;
    /**
     * $column.columnComment
     */
    @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
    @ExcelDictFormat(readConverterExp = "$column.readConverterExp()")
    private String matfltype;
    /**
     * $column.columnComment
     */
    @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
    @ExcelDictFormat(readConverterExp = "$column.readConverterExp()")
    private String matflname;
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/mapper/QmStdMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
package org.dromara.qa.qm.mapper;
import org.dromara.qa.qm.domain.QmStd;
import org.dromara.qa.qm.domain.vo.QmStdVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
 * åˆ¤å®šè§„程Mapper接口
 *
 * @author zhuguifei
 * @date 2026-03-11
 */
public interface QmStdMapper extends BaseMapperPlus<QmStd, QmStdVo> {
}
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qa/qm/service/IQmStdService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,68 @@
package org.dromara.qa.qm.service;
import org.dromara.qa.qm.domain.vo.QmStdVo;
import org.dromara.qa.qm.domain.bo.QmStdBo;
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-11
 */
public interface IQmStdService {
    /**
     * æŸ¥è¯¢åˆ¤å®šè§„程
     *
     * @param id ä¸»é”®
     * @return åˆ¤å®šè§„程
     */
    QmStdVo queryById(String id);
    /**
     * åˆ†é¡µæŸ¥è¯¢åˆ¤å®šè§„程列表
     *
     * @param bo        æŸ¥è¯¢æ¡ä»¶
     * @param pageQuery åˆ†é¡µå‚æ•°
     * @return åˆ¤å®šè§„程分页列表
     */
    TableDataInfo<QmStdVo> queryPageList(QmStdBo bo, PageQuery pageQuery);
    /**
     * æŸ¥è¯¢ç¬¦åˆæ¡ä»¶çš„判定规程列表
     *
     * @param bo æŸ¥è¯¢æ¡ä»¶
     * @return åˆ¤å®šè§„程列表
     */
    List<QmStdVo> queryList(QmStdBo bo);
    /**
     * æ–°å¢žåˆ¤å®šè§„程
     *
     * @param bo åˆ¤å®šè§„程
     * @return æ˜¯å¦æ–°å¢žæˆåŠŸ
     */
    Boolean insertByBo(QmStdBo bo);
    /**
     * ä¿®æ”¹åˆ¤å®šè§„程
     *
     * @param bo åˆ¤å®šè§„程
     * @return æ˜¯å¦ä¿®æ”¹æˆåŠŸ
     */
    Boolean updateByBo(QmStdBo 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/QmStdServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,139 @@
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.QmStdBo;
import org.dromara.qa.qm.domain.vo.QmStdVo;
import org.dromara.qa.qm.domain.QmStd;
import org.dromara.qa.qm.mapper.QmStdMapper;
import org.dromara.qa.qm.service.IQmStdService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
 * åˆ¤å®šè§„程Service业务层处理
 *
 * @author zhuguifei
 * @date 2026-03-11
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class QmStdServiceImpl implements IQmStdService {
    private final QmStdMapper baseMapper;
    /**
     * æŸ¥è¯¢åˆ¤å®šè§„程
     *
     * @param id ä¸»é”®
     * @return åˆ¤å®šè§„程
     */
    @Override
    public QmStdVo queryById(String id){
        return baseMapper.selectVoById(id);
    }
    /**
     * åˆ†é¡µæŸ¥è¯¢åˆ¤å®šè§„程列表
     *
     * @param bo        æŸ¥è¯¢æ¡ä»¶
     * @param pageQuery åˆ†é¡µå‚æ•°
     * @return åˆ¤å®šè§„程分页列表
     */
    @Override
    public TableDataInfo<QmStdVo> queryPageList(QmStdBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<QmStd> lqw = buildQueryWrapper(bo);
        Page<QmStdVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }
    /**
     * æŸ¥è¯¢ç¬¦åˆæ¡ä»¶çš„判定规程列表
     *
     * @param bo æŸ¥è¯¢æ¡ä»¶
     * @return åˆ¤å®šè§„程列表
     */
    @Override
    public List<QmStdVo> queryList(QmStdBo bo) {
        LambdaQueryWrapper<QmStd> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }
    private LambdaQueryWrapper<QmStd> buildQueryWrapper(QmStdBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<QmStd> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(QmStd::getId);
        lqw.like(StringUtils.isNotBlank(bo.getStdCode()), QmStd::getStdCode, bo.getStdCode());
        lqw.like(StringUtils.isNotBlank(bo.getStdName()), QmStd::getStdName, bo.getStdName());
        lqw.eq(bo.getTyp() != null, QmStd::getTyp, bo.getTyp());
        lqw.eq(StringUtils.isNotBlank(bo.getStdDes()), QmStd::getStdDes, bo.getStdDes());
        lqw.eq(bo.getCheckLevel() != null, QmStd::getCheckLevel, bo.getCheckLevel());
        lqw.eq(bo.getCategory() != null, QmStd::getCategory, bo.getCategory());
        lqw.eq(StringUtils.isNotBlank(bo.getMatfltype()), QmStd::getMatfltype, bo.getMatfltype());
        lqw.like(StringUtils.isNotBlank(bo.getMatflname()), QmStd::getMatflname, bo.getMatflname());
        return lqw;
    }
    /**
     * æ–°å¢žåˆ¤å®šè§„程
     *
     * @param bo åˆ¤å®šè§„程
     * @return æ˜¯å¦æ–°å¢žæˆåŠŸ
     */
    @Override
    public Boolean insertByBo(QmStdBo bo) {
        QmStd add = MapstructUtils.convert(bo, QmStd.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }
    /**
     * ä¿®æ”¹åˆ¤å®šè§„程
     *
     * @param bo åˆ¤å®šè§„程
     * @return æ˜¯å¦ä¿®æ”¹æˆåŠŸ
     */
    @Override
    public Boolean updateByBo(QmStdBo bo) {
        QmStd update = MapstructUtils.convert(bo, QmStd.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }
    /**
     * ä¿å­˜å‰çš„æ•°æ®æ ¡éªŒ
     */
    private void validEntityBeforeSave(QmStd 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/QmStdMapper.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.QmStdMapper">
</mapper>
ruoyi-plus-soybean/src/service/api/qm/std.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
import { request } from '@/service/request';
/** èŽ·å–åˆ¤å®šè§„ç¨‹åˆ—è¡¨ */
export function fetchGetStdList (params?: Api.Qm.StdSearchParams) {
    return request<Api.Qm.StdList>({
        url: '/qm/std/list',
        method: 'get',
        params
    });
}
/** æ–°å¢žåˆ¤å®šè§„程 */
export function fetchCreateStd (data: Api.Qm.StdOperateParams) {
    return request<boolean>({
        url: '/qm/std',
        method: 'post',
        data
    });
}
/** ä¿®æ”¹åˆ¤å®šè§„程 */
export function fetchUpdateStd (data: Api.Qm.StdOperateParams) {
    return request<boolean>({
        url: '/qm/std',
        method: 'put',
        data
    });
}
/** æ‰¹é‡åˆ é™¤åˆ¤å®šè§„程 */
export function fetchBatchDeleteStd (ids: CommonType.IdType[]) {
    return request<boolean>({
        url: `/qm/std/${ids.join(',')}`,
        method: 'delete'
    });
}
ruoyi-plus-soybean/src/typings/api/qm.std.api.d.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,85 @@
/**
 * Namespace Api
 *
 * All backend api type
 */
declare namespace Api {
    /**
     * namespace Qm
     *
     * backend api module: "Qm"
     */
    namespace Qm {
        /** std */
        type Std = Common.CommonRecord<{
            /** ç¼–码 */
                id: CommonType.IdType;
            /** è§„程代码 */
                stdCode: string;
            /** è§„程名称 */
                stdName: string;
            /** åˆ›å»ºæ—¶é—´ */
                cdate: string;
            /** ç‰ˆæœ¬å· */
                ver: number;
            /** å¯ç”¨æ ‡è¯† */
                enable: number;
            /** æ£€éªŒé¡¹ç›®code */
                itemCod: string;
            /** æ£€éªŒé¡¹ç›®åç§° */
                itemNam: string;
            /** åˆ¤å®šç±»åž‹  0-手动判定,1-上下限判定,2-平均值判定,3-SD值判定,4-CV值判定,5-超标数判定 */
                typ: number;
            /** å¤‡æ³¨ */
                stdDes: string;
            /** æ£€éªŒçº§åˆ« */
                checkLevel: number;
            /** ç±»åž‹  ï¼š 0-成品  1-辅料 */
                category: number;
            /** $column.columnComment */
                matfltype: string;
            /** $column.columnComment */
                matflname: string;
        }>;
        /** std search params */
        type StdSearchParams = CommonType.RecordNullable<
            Pick<
                Api.Qm.Std,
                        | 'stdCode'
                        | 'stdName'
                        | 'typ'
                        | 'stdDes'
                        | 'checkLevel'
                        | 'category'
                        | 'matfltype'
                        | 'matflname'
            > &
            Api.Common.CommonSearchParams
        >;
        /** std operate params */
        type StdOperateParams = CommonType.RecordNullable<
            Pick<
                Api.Qm.Std,
                        | 'id'
                        | 'stdCode'
                        | 'stdName'
                        | 'cdate'
                        | 'ver'
                        | 'enable'
                        | 'itemCod'
                        | 'itemNam'
                        | 'typ'
                        | 'stdDes'
                        | 'checkLevel'
                        | 'category'
                        | 'matfltype'
                        | 'matflname'
            >
        >;
        /** std list */
        type StdList = Api.Common.PaginatingQueryRecord<Std>;
    }
}
ruoyi-plus-soybean/src/views/analy/store-silk/modules/store-silk-sankey.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,282 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { useEcharts } from '@/hooks/common/echarts';
defineOptions({
  name: 'StoreSilkSankey'
});
interface StoreSilkDetailVo {
  fsNum?: string;
  siloNum?: string;
  equNo?: string;
  output?: number | null;
}
interface Props {
  rollerRecordList?: StoreSilkDetailVo[];
  packerRecordList?: StoreSilkDetailVo[];
  rows?: any[];
}
const props = withDefaults(defineProps<Props>(), {
  rollerRecordList: () => [],
  packerRecordList: () => [],
  rows: () => []
});
type SankeyType = 'roller' | 'packer';
const sankeyType = ref<SankeyType>('roller');
function normalizeNumber(val: unknown) {
  const v = Number(val);
  if (!Number.isFinite(v)) return null;
  return v;
}
function calcRollerBox(val: unknown) {
  if (val === null || val === undefined) return null;
  const v = Number(val) / 50;
  if (!Number.isFinite(v)) return null;
  return v;
}
function calcPackerBox(val: unknown) {
  if (val === null || val === undefined) return null;
  const v = Number(val) / 10 / 250;
  if (!Number.isFinite(v)) return null;
  return v;
}
function formatTime(val: unknown) {
  if (!val) return '';
  const s = String(val);
  return s.length > 19 ? s.slice(0, 19) : s;
}
function buildChartData(list: StoreSilkDetailVo[], type: SankeyType) {
  const nodeSet = new Set<string>();
  const linkMap = new Map<string, { source: string; target: string; value: number }>();
  const nodeInValue = new Map<string, number>();
  const nodeOutValue = new Map<string, number>();
  const nodeExtra = new Map<string, any>();
  const rows = Array.isArray(props.rows) ? props.rows : [];
  function addLink(source: string, target: string, value: number) {
    if (value <= 0) return;
    nodeSet.add(source);
    nodeSet.add(target);
    nodeInValue.set(target, (nodeInValue.get(target) ?? 0) + value);
    nodeOutValue.set(source, (nodeOutValue.get(source) ?? 0) + value);
    const key = `${source}__->__${target}`;
    const existed = linkMap.get(key);
    if (existed) {
      existed.value += value;
      return;
    }
    linkMap.set(key, { source, target, value });
  }
  for (const item of list) {
    const val = normalizeNumber(item.output);
    if (val === null) continue;
    if (val <= 0) continue;
    const fsBase = `喂丝机 ${item.fsNum || '-'}`;
    const siloBase = `储丝柜 ${item.siloNum || '-'}`;
    const equ = item.equNo ? `${item.equNo}#${type === 'roller' ? '卷接机' : '包装机'}` : type === 'roller' ? '卷接机' : '包装机';
    const target = equ;
    const fs = fsBase;
    const silo = siloBase;
    addLink(fs, silo, val);
    addLink(silo, target, val);
    const parentRow = rows.find((r: any) => {
      const dList = type === 'roller' ? r?.rollerDetailList : r?.packerDetailList;
      if (!Array.isArray(dList)) return false;
      return dList.some((d: any) => d?.fsNum === item.fsNum && d?.siloNum === item.siloNum && d?.equNo === item.equNo);
    });
    if (parentRow) {
      const materialname = String(parentRow.materialname ?? '');
      const batchcode = String(parentRow.batchcode ?? parentRow.batchCode ?? '');
      const jobinput = Number(parentRow.jobinput);
      const distimebegin = formatTime(parentRow.distimebegin);
      const distimeend = formatTime(parentRow.distimeend);
      nodeExtra.set(fs, {
        kind: 'fs',
        displayName: fsBase,
        meta: { materialname, batchcode, jobinput }
      });
      nodeExtra.set(silo, {
        kind: 'silo',
        displayName: siloBase,
        meta: { distimebegin, distimeend }
      });
    }
  }
  const nodes = Array.from(nodeSet).map(name => {
    const inV = nodeInValue.get(name) ?? 0;
    const outV = nodeOutValue.get(name) ?? 0;
    const value = inV > 0 ? inV : outV;
    return { name, value, ...(nodeExtra.get(name) ?? {}) };
  });
  const links = Array.from(linkMap.values());
  return { nodes, links };
}
const activeList = computed(() => {
  return sankeyType.value === 'roller' ? props.rollerRecordList : props.packerRecordList;
});
watch(
  () => [props.rollerRecordList, props.packerRecordList],
  () => {
    const rollerLen = Array.isArray(props.rollerRecordList) ? props.rollerRecordList.length : 0;
    const packerLen = Array.isArray(props.packerRecordList) ? props.packerRecordList.length : 0;
    if (sankeyType.value === 'roller' && rollerLen === 0 && packerLen > 0) {
      sankeyType.value = 'packer';
      return;
    }
    if (sankeyType.value === 'packer' && packerLen === 0 && rollerLen > 0) {
      sankeyType.value = 'roller';
    }
  },
  { deep: true, immediate: true }
);
const hasData = computed(() => {
  return Boolean(activeList.value && activeList.value.length > 0);
});
const { domRef, updateOptions } = useEcharts(() => {
  const { nodes, links } = buildChartData(activeList.value, sankeyType.value);
  return {
    tooltip: {
      trigger: 'item'
    },
    series: [
      {
        type: 'sankey',
        data: nodes,
        links,
        nodeAlign: 'justify',
        layoutIterations: 32,
        emphasis: {
          focus: 'adjacency'
        },
        lineStyle: {
          color: 'source',
          curveness: 0.5,
          opacity: 0.35
        },
        label: {
          position: 'right',
          formatter: (params: any) => {
            const name = String(params?.data?.name ?? '');
            const value = params?.data?.value;
            const kind = params?.data?.kind;
            const displayName = String(params?.data?.displayName ?? name);
            const meta = params?.data?.meta;
            if (kind === 'fs') {
              const materialLine = meta?.materialname ? `牌号:${meta.materialname}` : '';
              const batchLine = meta?.batchcode ? `批次:${meta.batchcode}` : '';
              const jobLine =
                Number.isFinite(Number(meta?.jobinput)) ? `投料重量:${Number(meta.jobinput).toFixed(2)}kg` : '';
              const lines: string[] = [displayName];
              lines.push('');
              if (materialLine) lines.push(materialLine);
              if (batchLine) lines.push(batchLine);
              if (jobLine) {
                lines.push('');
                lines.push(jobLine);
              }
              return lines.join('\n');
            }
            if (kind === 'silo') {
              const beginLine = meta?.distimebegin ? `开始:${meta.distimebegin}` : '';
              const endLine = meta?.distimeend ? `结束:${meta.distimeend}` : '';
              const valLine =
                typeof value === 'number' && Number.isFinite(value) ? `产量:${value.toFixed(2)}ç®±` : '';
              const lines: string[] = [displayName];
              lines.push('');
              if (beginLine) lines.push(beginLine);
              if (endLine) lines.push(endLine);
              if (valLine) {
                lines.push('');
                lines.push(valLine);
              }
              return lines.join('\n');
            }
            const showValue =
              name.startsWith('储丝柜 ') ||
              name.endsWith('#卷接机') ||
              name.endsWith('#包装机') ||
              name === '卷接机' ||
              name === '包装机';
            if (showValue && typeof value === 'number' && Number.isFinite(value)) {
              return `${displayName}\n${value.toFixed(2)}ç®±`;
            }
            return displayName;
        }
      }
      },
    ]
  };
});
watch(
  () => [props.rollerRecordList, props.packerRecordList, sankeyType.value],
  () => {
    updateOptions(opts => {
      const { nodes, links } = buildChartData(activeList.value, sankeyType.value);
      opts.series[0].data = nodes as any;
      (opts.series[0] as any).links = links;
      return opts;
    });
  },
  { deep: true, immediate: true }
);
</script>
<template>
  <div class="h-full flex-col-stretch">
    <div class="pb-8px">
      <NSpace :size="8">
        <NButton
          size="small"
          ghost
          :type="sankeyType === 'roller' ? 'primary' : 'default'"
          @click="sankeyType = 'roller'"
        >
          å·æŽ¥
        </NButton>
        <NButton
          size="small"
          ghost
          :type="sankeyType === 'packer' ? 'primary' : 'default'"
          @click="sankeyType = 'packer'"
        >
          åŒ…装
        </NButton>
      </NSpace>
    </div>
    <div v-if="!hasData" class="flex-center flex-1 text-gray-400">
      æš‚æ— {{ sankeyType === 'roller' ? '卷接' : '包装' }}桑基图数据
    </div>
    <div v-else ref="domRef" class="flex-1 min-h-360px overflow-hidden"></div>
  </div>
</template>
<style scoped></style>
ruoyi-plus-soybean/src/views/qm/std/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,229 @@
<script setup lang="tsx">
import { ref } from 'vue';
import { NDivider } from 'naive-ui';
import dayjs from 'dayjs';
import { fetchBatchDeleteStd, fetchGetStdList } from '@/service/api/qm/std';
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 StdOperateDrawer from './modules/std-operate-drawer.vue';
import StdSearch from './modules/std-search.vue';
defineOptions({
  name: 'StdList'
});
const appStore = useAppStore();
const { download } = useDownload();
const { hasAuth } = useAuth();
const searchParams = ref<Api.Qm.StdSearchParams>({
  pageNum: 1,
  pageSize: 10,
  stdCode: null,
  stdName: null,
  typ: null,
  stdDes: null,
  checkLevel: null,
  category: 0,
  matfltype: null,
  matflname: null,
  params: {}
});
const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
  useNaivePaginatedTable({
  api: () => fetchGetStdList(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: 'stdCode',
      title: '规程代码',
      align: 'center',
      width: 200
    },
    {
      key: 'stdName',
      title: '规程名称',
      align: 'center',
      width: 300
    },
    {
      key: 'category',
      title: '物料类型',
      align: 'center',
      minWidth: 120,
      render: row => {
        const v = String(row?.category ?? '');
        return v === '0' ? '成品' : v === '1' ? '辅料' : v;
      }
    },
    {
      key: 'cdate',
      title: '创建时间',
      align: 'center',
      minWidth: 120,
      render: row => (row.cdate ? dayjs(row.cdate).format('YYYY-MM-DD') : '')
    },
    {
      key: 'ver',
      title: '版本号',
      align: 'center',
      minWidth: 120
    },
    {
      key: 'enable',
      title: '启用标识',
      align: 'center',
      minWidth: 120,
      render: row => {
        const v = String(row?.enable ?? '');
        return v === '0' ? '停用' : v === '1' ? '启用' : v;
      }
    },
    {
      key: 'operate',
      title: $t('common.operate'),
      align: 'center',
      fixed: 'right',
      width: 130,
      render: row => {
        const divider = () => {
          if (!hasAuth('qm:std:edit') || !hasAuth('qm:std:remove')) {
            return null;
          }
          return <NDivider vertical />;
        };
        const editBtn = () => {
          if (!hasAuth('qm:std: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:std: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 fetchBatchDeleteStd(checkedRowKeys.value);
  if (error) return;
  onBatchDeleted();
}
async function handleDelete(id: CommonType.IdType) {
  // request
  const { error } = await fetchBatchDeleteStd([id]);
  if (error) return;
  onDeleted();
}
function edit(id: CommonType.IdType) {
  handleEdit(id);
}
function handleExport() {
  download('/qm/std/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">
    <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"
        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>
  </div>
</template>
<style scoped></style>
ruoyi-plus-soybean/src/views/qm/std/modules/std-operate-drawer.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,179 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { jsonClone } from '@sa/utils';
import { fetchCreateStd, fetchUpdateStd } from '@/service/api/qm/std';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales';
defineOptions({
  name: 'StdOperateDrawer'
});
interface Props {
  /** the type of operation */
  operateType: NaiveUI.TableOperateType;
  /** the edit row data */
  rowData?: Api.Qm.Std | 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.StdOperateParams;
const model = ref<Model>(createDefaultModel());
function createDefaultModel(): Model {
  return {
      id: '',
      stdCode: '',
      stdName: '',
      cdate: null,
      ver: null,
      enable: null,
      itemCod: '',
      itemNam: '',
      typ: null,
      stdDes: '',
      checkLevel: null,
      category: null,
      matfltype: '',
      matflname: ''
  };
}
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, stdCode, stdName, cdate, ver, enable, itemCod, itemNam, typ, stdDes, checkLevel, category, matfltype, matflname } = model.value;
  // request
  if (props.operateType === 'add') {
    const { error } = await fetchCreateStd({ stdCode, stdName, cdate, ver, enable, itemCod, itemNam, typ, stdDes, checkLevel, category, matfltype, matflname });
    if (error) return;
  }
  if (props.operateType === 'edit') {
    const { error } = await fetchUpdateStd({ id, stdCode, stdName, cdate, ver, enable, itemCod, itemNam, typ, stdDes, checkLevel, category, matfltype, matflname });
    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="stdCode">
          <NInput v-model:value="model.stdCode" placeholder="请输入规程代码" />
        </NFormItem>
        <NFormItem label="规程名称" path="stdName">
          <NInput v-model:value="model.stdName" 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="ver">
          <NInput v-model:value="model.ver" placeholder="请输入版本号" />
        </NFormItem>
        <NFormItem label="启用标识" path="enable">
          <NInput v-model:value="model.enable" placeholder="请输入启用标识" />
        </NFormItem>
        <NFormItem label="检验项目code" path="itemCod">
          <NInput v-model:value="model.itemCod" placeholder="请输入检验项目code" />
        </NFormItem>
        <NFormItem label="检验项目名称" path="itemNam">
          <NInput v-model:value="model.itemNam" placeholder="请输入检验项目名称" />
        </NFormItem>
        <NFormItem label="判定类型  0-手动判定,1-上下限判定,2-平均值判定,3-SD值判定,4-CV值判定,5-超标数判定" path="typ">
          <NInput v-model:value="model.typ" placeholder="请输入判定类型  0-手动判定,1-上下限判定,2-平均值判定,3-SD值判定,4-CV值判定,5-超标数判定" />
        </NFormItem>
        <NFormItem label="备注" path="stdDes">
          <NInput v-model:value="model.stdDes" placeholder="请输入备注" />
        </NFormItem>
        <NFormItem label="检验级别" path="checkLevel">
          <NInput v-model:value="model.checkLevel" placeholder="请输入检验级别" />
        </NFormItem>
        <NFormItem label="类型  ï¼š 0-成品  1-辅料" path="category">
          <NInput v-model:value="model.category" placeholder="请输入类型  ï¼š 0-成品  1-辅料" />
        </NFormItem>
        <NFormItem label="$column.columnComment" path="matfltype">
          <NSelect
            v-model:value="model.matfltype"
            placeholder="请选择$column.columnComment"
            :options="[{ value: '0', label: '请选择字典生成' }]"
            clearable
          />
        </NFormItem>
        <NFormItem label="$column.columnComment" path="matflname">
          <NInput v-model:value="model.matflname" placeholder="请输入$column.columnComment" />
        </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/std/modules/std-search.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,96 @@
<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: 'StdSearch'
});
interface Emits {
  (e: 'search'): void;
}
const emit = defineEmits<Emits>();
const { formRef, validate, restoreValidation } = useNaiveForm();
const model = defineModel<Api.Qm.StdSearchParams>('model', { required: true });
const defaultModel = jsonClone(toRaw(model.value));
// åˆ¤å®šç±»åž‹é€‰é¡¹ï¼š0-手动判定 1-上下限判定 2-平均值判定 3-SD值判定 4-CV值判定 5-超标数判定
const typOptions = [
  { label: '手动判定', value: 0 },
  { label: '上下限判定', value: 1 },
  { label: '平均值判定', value: 2 },
  { label: 'SD值判定', value: 3 },
  { label: 'CV值判定', value: 4 },
  { label: '超标数判定', value: 5 }
];
// ç‰©æ–™ç±»åž‹é€‰é¡¹ï¼š0-成品 1-辅料
const categoryOptions = [
  { label: '成品', value: 0 },
  { label: '辅料', value: 1 }
];
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-std-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="stdCode" class="pr-24px">
              <NInput v-model:value="model.stdCode" placeholder="请输入规程代码" />
            </NFormItemGi>
            <NFormItemGi span="24 s:12 m:6" label="规程名称" label-width="auto" path="stdName" class="pr-24px">
              <NInput v-model:value="model.stdName" placeholder="请输入规程名称" />
            </NFormItemGi>
            <NFormItemGi span="24 s:12 m:6" label="判定类型" label-width="auto" path="typ" class="pr-24px">
              <NSelect v-model:value="model.typ" :options="typOptions" placeholder="请选择判定类型" clearable />
            </NFormItemGi>
            <NFormItemGi span="24 s:12 m:6" label="物料类型" label-width="auto" path="category" class="pr-24px">
              <NSelect v-model:value="model.category" :options="categoryOptions" placeholder="请选择物料类型" 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>