Compare commits

...

10 Commits

@ -70,10 +70,13 @@
<netty.version>4.1.113.Final</netty.version> <netty.version>4.1.113.Final</netty.version>
<mqtt.version>1.2.5</mqtt.version> <mqtt.version>1.2.5</mqtt.version>
<opc.version>0.6.9</opc.version> <opc.version>0.6.9</opc.version>
<qrcode.version>3.5.3</qrcode.version>
<!-- 三方云服务相关 --> <!-- 三方云服务相关 -->
<commons-io.version>2.17.0</commons-io.version> <commons-io.version>2.17.0</commons-io.version>
<commons-compress.version>1.27.1</commons-compress.version> <commons-compress.version>1.27.1</commons-compress.version>
<aws-java-sdk-s3.version>1.12.777</aws-java-sdk-s3.version> <aws-java-sdk-s3.version>1.12.777</aws-java-sdk-s3.version>
<s3.version>2.41.33</s3.version>
<justauth.version>1.0.8</justauth.version> <justauth.version>1.0.8</justauth.version>
<jimureport.version>1.7.8</jimureport.version> <jimureport.version>1.7.8</jimureport.version>
<weixin-java.version>4.6.0</weixin-java.version> <weixin-java.version>4.6.0</weixin-java.version>
@ -589,6 +592,17 @@
<version>${aws-java-sdk-s3.version}</version> <version>${aws-java-sdk-s3.version}</version>
</dependency> </dependency>
<!-- <dependency>-->
<!-- <groupId>software.amazon.awssdk</groupId>-->
<!-- <artifactId>s3</artifactId>-->
<!-- <version>${s3.version}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>software.amazon.awssdk</groupId>-->
<!-- <artifactId>sts</artifactId>-->
<!-- <version>${s3.version}</version>-->
<!-- </dependency>-->
<dependency> <dependency>
<groupId>com.xingyuv</groupId> <groupId>com.xingyuv</groupId>
<artifactId>spring-boot-starter-justauth</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) --> <artifactId>spring-boot-starter-justauth</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) -->
@ -648,6 +662,16 @@
<artifactId>logback-classic</artifactId> <artifactId>logback-classic</artifactId>
<version>${logback.version}</version> <version>${logback.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>${qrcode.version}</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>${qrcode.version}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

@ -35,7 +35,7 @@ public interface GlobalErrorCodeConstants {
// ========== 自定义错误段 ========== // ========== 自定义错误段 ==========
ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求 ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作"); ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作");
ErrorCode DEVICE_CONTACT_MODEL_NOT_EXISTS = new ErrorCode(902, "查询不到该设备"); ErrorCode DEVICE_CONTACT_MODEL_NOT_EXISTS = new ErrorCode(902, "查询不到该点位");
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误"); ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");

@ -0,0 +1,16 @@
package cn.iocoder.yudao.module.common.api.mold.enums;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
/**
* ERP
* <p>
* erp 使 1-030-000-000
*/
public interface ErrorCodeConstants {
// ========== 二维码记录表1-030-100-000 ==========
ErrorCode RECORD_NOT_EXISTS = new ErrorCode(1_003_000_000, "通用二维码记录不存在。");
ErrorCode FAILED_TO_REGENERATE = new ErrorCode(1_003_000_001, "重新生成二维码/条形码错误。");
}

@ -16,6 +16,12 @@
<description>common 模块业务实现</description> <description>common 模块业务实现</description>
<dependencies> <dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
<!-- 模块自身 --> <!-- 模块自身 -->
<dependency> <dependency>
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
@ -56,6 +62,14 @@
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-excel</artifactId> <artifactId>yudao-spring-boot-starter-excel</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -16,7 +16,7 @@ public class MoldSaveReqVO {
private Long id; private Long id;
@Schema(description = "模具编码", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "模具编码", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "模具编码不能为空") // @NotEmpty(message = "模具编码不能为空")
private String code; private String code;
@Schema(description = "模具名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") @Schema(description = "模具名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")

@ -0,0 +1,122 @@
package cn.iocoder.yudao.module.common.controller.admin.qrcoderecord;
import cn.iocoder.yudao.module.common.controller.admin.qrcoderecord.vo.QrcodeRecordPageReqVO;
import cn.iocoder.yudao.module.common.controller.admin.qrcoderecord.vo.QrcodeRecordRespVO;
import cn.iocoder.yudao.module.common.controller.admin.qrcoderecord.vo.QrcodeRecordSaveReqVO;
import cn.iocoder.yudao.module.common.dal.dataobject.qrcoderecord.QrcodeRecordDO;
import cn.iocoder.yudao.module.common.service.qrcordrecord.QrcodeRecordService;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
@Tag(name = "管理后台 - 通用二维码记录")
@RestController
@RequestMapping("/qrcode/record")
@Validated
public class QrcodeRecordController {
@Resource
private QrcodeRecordService qrcodeRecordService;
@PostMapping("/create")
@Operation(summary = "创建通用二维码记录")
@PreAuthorize("@ss.hasPermission('qrcode:record:create')")
public CommonResult<Long> createRecord(@Valid @RequestBody QrcodeRecordSaveReqVO createReqVO) {
return success(qrcodeRecordService.createRecord(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新通用二维码记录")
@PreAuthorize("@ss.hasPermission('qrcode:record:update')")
public CommonResult<Boolean> updateRecord(@Valid @RequestBody QrcodeRecordSaveReqVO updateReqVO) {
qrcodeRecordService.updateRecord(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除通用二维码记录")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('qrcode:record:delete')")
public CommonResult<Boolean> deleteRecord(@RequestParam("id") Long id) {
qrcodeRecordService.deleteRecord(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得通用二维码记录")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('qrcode:record:query')")
public CommonResult<QrcodeRecordRespVO> getRecord(@RequestParam("id") Long id) {
QrcodeRecordDO record = qrcodeRecordService.getRecord(id);
return success(BeanUtils.toBean(record, QrcodeRecordRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得通用二维码记录分页")
@PreAuthorize("@ss.hasPermission('qrcode:record:query')")
public CommonResult<PageResult<QrcodeRecordRespVO>> getRecordPage(@Valid QrcodeRecordPageReqVO pageReqVO) {
PageResult<QrcodeRecordDO> pageResult = qrcodeRecordService.getRecordPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, QrcodeRecordRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出通用二维码记录 Excel")
@PreAuthorize("@ss.hasPermission('qrcode:record:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportRecordExcel(@Valid QrcodeRecordPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<QrcodeRecordDO> list = qrcodeRecordService.getRecordPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "通用二维码记录.xls", "数据", QrcodeRecordRespVO.class,
BeanUtils.toBean(list, QrcodeRecordRespVO.class));
}
//TODO 扫二维码拉起app端,仍需app拉起连接地址。
// @GetMapping(value = "/scan", produces = "text/html;charset=UTF-8")
// @Operation(summary = "扫二维码拉起app端 ")
// @PermitAll
// public void scan(@RequestParam("type") String type,
// @RequestParam("id") Long id,
// @RequestParam(required=false) String code,
// HttpServletResponse response) throws IOException {
// String html = qrcodeRecordService.buildScanTransitHtml(type, id,code);
// response.setContentType("text/html;charset=UTF-8");
// response.getWriter().write(html);
// }
@GetMapping("/scan/resolve-id")
@Operation(summary = "扫二维码返回对应id ")
@PermitAll
public CommonResult<Map<String, Object>> resolveId(@RequestParam String type,
@RequestParam Long id,
@RequestParam String code) {
return success(qrcodeRecordService.resolveScanBizId(type, id, code));
}
}

@ -0,0 +1,59 @@
package cn.iocoder.yudao.module.common.controller.admin.qrcoderecord.vo;
import lombok.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 通用二维码记录分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class QrcodeRecordPageReqVO extends PageParam {
@Schema(description = "业务类型MOLD/PRODUCT/EQUIPMENT/PART/SPARE/WORK_ORDER", example = "2")
private String bizType;
@Schema(description = "业务ID", example = "31277")
private Long bizId;
@Schema(description = "业务编码")
private String bizCode;
@Schema(description = "二维码场景DETAIL/LABEL/TRACE")
private String qrScene;
@Schema(description = "二维码内容(扫码入口地址)")
private String qrContent;
@Schema(description = "二维码文件名", example = "芋艿")
private String fileName;
@Schema(description = "MinIO bucket名称", example = "王五")
private String bucketName;
@Schema(description = "MinIO对象路径", example = "赵六")
private String objectName;
@Schema(description = "二维码图片访问地址", example = "https://www.iocoder.cn")
private String qrcodeFileUrl;
@Schema(description = "文件MIME类型", example = "1")
private String mimeType;
@Schema(description = "文件大小(字节)")
private Long fileSize;
@Schema(description = "状态1-有效 0-失效", example = "1")
private Integer status;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "QR(二维码)/BARCODE(条形码)", example = "")
private String codeType;
}

@ -0,0 +1,73 @@
package cn.iocoder.yudao.module.common.controller.admin.qrcoderecord.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 通用二维码记录 Response VO")
@Data
@ExcelIgnoreUnannotated
public class QrcodeRecordRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "28938")
@ExcelProperty("主键ID")
private Long id;
@Schema(description = "业务类型MOLD/PRODUCT/EQUIPMENT/PART/SPARE/WORK_ORDER", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty("业务类型MOLD/PRODUCT/EQUIPMENT/PART/SPARE/WORK_ORDER")
private String bizType;
@Schema(description = "业务ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "31277")
@ExcelProperty("业务ID")
private Long bizId;
@Schema(description = "业务编码")
@ExcelProperty("业务编码")
private String bizCode;
@Schema(description = "二维码场景DETAIL/LABEL/TRACE", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("二维码场景DETAIL/LABEL/TRACE")
private String qrScene;
@Schema(description = "二维码内容(扫码入口地址)", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("二维码内容(扫码入口地址)")
private String qrContent;
@Schema(description = "二维码文件名", example = "芋艿")
@ExcelProperty("二维码文件名")
private String fileName;
@Schema(description = "MinIO bucket名称", example = "王五")
@ExcelProperty("MinIO bucket名称")
private String bucketName;
@Schema(description = "MinIO对象路径", example = "赵六")
@ExcelProperty("MinIO对象路径")
private String objectName;
@Schema(description = "二维码图片访问地址", example = "https://www.iocoder.cn")
@ExcelProperty("二维码图片访问地址")
private String qrcodeFileUrl;
@Schema(description = "文件MIME类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty("文件MIME类型")
private String mimeType;
@Schema(description = "文件大小(字节)")
@ExcelProperty("文件大小(字节)")
private Long fileSize;
@Schema(description = "状态1-有效 0-失效", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty("状态1-有效 0-失效")
private Integer status;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "QR(二维码)/BARCODE(条形码)", example = "")
private String codeType;
}

@ -0,0 +1,61 @@
package cn.iocoder.yudao.module.common.controller.admin.qrcoderecord.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 通用二维码记录新增/修改 Request VO")
@Data
public class QrcodeRecordSaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "28938")
private Long id;
@Schema(description = "业务类型MOLD/PRODUCT/EQUIPMENT/PART/SPARE/WORK_ORDER", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotEmpty(message = "业务类型MOLD/PRODUCT/EQUIPMENT/PART/SPARE/WORK_ORDER不能为空")
private String bizType;
@Schema(description = "业务ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "31277")
@NotNull(message = "业务ID不能为空")
private Long bizId;
@Schema(description = "业务编码")
private String bizCode;
@Schema(description = "二维码场景DETAIL/LABEL/TRACE", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "二维码场景DETAIL/LABEL/TRACE不能为空")
private String qrScene;
@Schema(description = "二维码内容(扫码入口地址)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "二维码内容(扫码入口地址)不能为空")
private String qrContent;
@Schema(description = "二维码文件名", example = "芋艿")
private String fileName;
@Schema(description = "MinIO bucket名称", example = "王五")
private String bucketName;
@Schema(description = "MinIO对象路径", example = "赵六")
private String objectName;
@Schema(description = "二维码图片访问地址", example = "https://www.iocoder.cn")
private String qrcodeFileUrl;
@Schema(description = "文件MIME类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotEmpty(message = "文件MIME类型不能为空")
private String mimeType;
@Schema(description = "文件大小(字节)")
private Long fileSize;
@Schema(description = "状态1-有效 0-失效", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态1-有效 0-失效不能为空")
private Integer status;
@Schema(description = "QR(二维码)/BARCODE(条形码)", example = "")
private String codeType;
}

@ -113,4 +113,10 @@ public class MoldDO extends BaseDO {
@TableField(exist = false) @TableField(exist = false)
private String moldType; private String moldType;
/**
*
*/
@TableField(exist = false)
private String qrcodeUrl;
} }

@ -0,0 +1,81 @@
package cn.iocoder.yudao.module.common.dal.dataobject.qrcoderecord;
import lombok.*;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* DO
*
* @author
*/
@TableName("qrcode_record")
@KeySequence("qrcode_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class QrcodeRecordDO extends BaseDO {
/**
* ID
*/
@TableId
private Long id;
/**
* MOLD/PRODUCT/EQUIPMENT/PART/SPARE/WORK_ORDER
*/
private String bizType;
/**
* ID
*/
private Long bizId;
/**
*
*/
private String bizCode;
/**
* DETAIL/LABEL/TRACE
*/
private String qrScene;
/**
*
*/
private String qrContent;
/**
*
*/
private String fileName;
/**
* MinIO bucket
*/
private String bucketName;
/**
* MinIO
*/
private String objectName;
/**
* 访
*/
private String qrcodeFileUrl;
/**
* MIME
*/
private String mimeType;
/**
*
*/
private Long fileSize;
/**
* 1- 0-
*/
private Integer status;
/**
* QR()/BARCODE()
*/
private String codeType;
}

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.common.dal.mysql.qrcoderecord;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.common.controller.admin.qrcoderecord.vo.QrcodeRecordPageReqVO;
import cn.iocoder.yudao.module.common.dal.dataobject.qrcoderecord.QrcodeRecordDO;
import org.apache.ibatis.annotations.Mapper;
/**
* Mapper
*
* @author
*/
@Mapper
public interface QrcodeRecordMapper extends BaseMapperX<QrcodeRecordDO> {
default PageResult<QrcodeRecordDO> selectPage(QrcodeRecordPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<QrcodeRecordDO>()
.eqIfPresent(QrcodeRecordDO::getBizType, reqVO.getBizType())
.eqIfPresent(QrcodeRecordDO::getBizId, reqVO.getBizId())
.eqIfPresent(QrcodeRecordDO::getBizCode, reqVO.getBizCode())
.eqIfPresent(QrcodeRecordDO::getQrScene, reqVO.getQrScene())
.eqIfPresent(QrcodeRecordDO::getQrContent, reqVO.getQrContent())
.likeIfPresent(QrcodeRecordDO::getFileName, reqVO.getFileName())
.likeIfPresent(QrcodeRecordDO::getBucketName, reqVO.getBucketName())
.likeIfPresent(QrcodeRecordDO::getObjectName, reqVO.getObjectName())
.eqIfPresent(QrcodeRecordDO::getQrcodeFileUrl, reqVO.getQrcodeFileUrl())
.eqIfPresent(QrcodeRecordDO::getMimeType, reqVO.getMimeType())
.eqIfPresent(QrcodeRecordDO::getFileSize, reqVO.getFileSize())
.eqIfPresent(QrcodeRecordDO::getStatus, reqVO.getStatus())
.betweenIfPresent(QrcodeRecordDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(QrcodeRecordDO::getId));
}
}

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum CodeTypeEnum {
QR("QR", "二维码"),
BARCODE("BARCODE", "条形码");
private final String code;
private final String desc;
public String getCode() {
return code;
}
public String getDesc() {
return desc;
}
public static CodeTypeEnum fromBarcodeType(Integer barcodeType) {
if (barcodeType == null) {
return null;
}
return Integer.valueOf(1).equals(barcodeType) ? BARCODE : QR;
}
}

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.common.enums;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum QrcodeBizTypeEnum {
PRODUCT("PRODUCTMATERIAL", "产品物料"),
EQUIPMENT("EQUIPMENT", "设备"),
KEY_PART("KEY_PART", "关键件"),
MOLD("MOLD", "模具"),
SPARE("SPARE", "备件");
private final String code;
private final String name;
public static QrcodeBizTypeEnum of(String code) {
for (QrcodeBizTypeEnum item : values()) {
if (item.code.equalsIgnoreCase(code)) {
return item;
}
}
return null;
}
}

@ -0,0 +1,9 @@
package cn.iocoder.yudao.module.common.handler;
public interface QrcodeBizHandler {
String getBizType();
boolean exists(Long id);
String buildDeepLink(Long id);
String buildH5Path(Long id);
}

@ -0,0 +1,83 @@
package cn.iocoder.yudao.module.common.service.qrcordrecord;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.common.controller.admin.qrcoderecord.vo.QrcodeRecordPageReqVO;
import cn.iocoder.yudao.module.common.controller.admin.qrcoderecord.vo.QrcodeRecordSaveReqVO;
import cn.iocoder.yudao.module.common.dal.dataobject.qrcoderecord.QrcodeRecordDO;
import cn.iocoder.yudao.module.common.enums.CodeTypeEnum;
import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum;
import org.springframework.transaction.annotation.Transactional;
import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.util.Map;
/**
* Service
*
* @author
*/
public interface QrcodeRecordService {
/**
*
*
* @param createReqVO
* @return
*/
Long createRecord(@Valid QrcodeRecordSaveReqVO createReqVO);
/**
*
*
* @param updateReqVO
*/
void updateRecord(@Valid QrcodeRecordSaveReqVO updateReqVO);
/**
*
*
* @param id
*/
void deleteRecord(Long id);
/**
*
*
* @param id
* @return
*/
QrcodeRecordDO getRecord(Long id);
/**
*
*
* @param pageReqVO
* @return
*/
PageResult<QrcodeRecordDO> getRecordPage(QrcodeRecordPageReqVO pageReqVO);
void generateOrRefresh(QrcodeBizTypeEnum bizType, Long bizId, String bizCode, String scene) throws UnsupportedEncodingException;
void generateOrRefreshBarcode(QrcodeBizTypeEnum bizType, Long bizId, String bizCode, String scene) throws UnsupportedEncodingException;
String buildScanTransitHtml(String type, Long id,String code);
String selectQrcodeUrlByIdAndCode(String code, Long id, String code1);
Map<String, Object> resolveScanBizId(String type, Long id, String code);
void deleteByBiz(QrcodeBizTypeEnum bizType, Long bizId);
void regenerateByCodeType(QrcodeBizTypeEnum bizType, Long bizId, String bizCode, String scene, String codeType)
throws UnsupportedEncodingException;
void generateOrRefresh(
QrcodeBizTypeEnum bizType,
Long bizId,
String bizCode,
String scene,
CodeTypeEnum codeType
) throws UnsupportedEncodingException;
}

@ -0,0 +1,605 @@
package cn.iocoder.yudao.module.common.service.qrcordrecord;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.common.controller.admin.qrcoderecord.vo.QrcodeRecordPageReqVO;
import cn.iocoder.yudao.module.common.controller.admin.qrcoderecord.vo.QrcodeRecordSaveReqVO;
import cn.iocoder.yudao.module.common.dal.dataobject.qrcoderecord.QrcodeRecordDO;
import cn.iocoder.yudao.module.common.dal.mysql.qrcoderecord.QrcodeRecordMapper;
import cn.iocoder.yudao.module.common.enums.CodeTypeEnum;
import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum;
import cn.iocoder.yudao.module.common.handler.QrcodeBizHandler;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.common.api.mold.enums.ErrorCodeConstants.RECORD_NOT_EXISTS;
/**
* Service
*
* @author
*/
@Service
@Validated
@Slf4j
public class QrcodeRecordServiceImpl implements QrcodeRecordService {
@Resource
private FileApi fileApi;
@Value("${yudao.qrcode.scan-base-url}")
private String scanBaseUrl;
@Value("${yudao.qrcode.width:300}")
private Integer width;
@Value("${yudao.qrcode.height:300}")
private Integer height;
@Value("${yudao.qrcode.default-bucket:common-qrcode}")
private String defaultBucket;
@Value("${yudao.qrcode.fail-url}")
private String failUrl;
@Value("${yudao.qrcode.scan-base-url}")
private String serverBaseUrl;
@Value("#{${yudao.qrcode.buckets:{}}}")
private Map<String, String> bucketMap = new HashMap<>();
@Resource
private QrcodeRecordMapper qrcodeRecordMapper;
private final Map<String, QrcodeBizHandler> handlerMap;
public QrcodeRecordServiceImpl(List<QrcodeBizHandler> handlers) {
this.handlerMap = handlers.stream()
.collect(Collectors.toMap(h -> h.getBizType().toUpperCase(), h -> h));
}
@Override
public Long createRecord(QrcodeRecordSaveReqVO createReqVO) {
// 插入
QrcodeRecordDO record = BeanUtils.toBean(createReqVO, QrcodeRecordDO.class);
qrcodeRecordMapper.insert(record);
// 返回
return record.getId();
}
@Override
public void updateRecord(QrcodeRecordSaveReqVO updateReqVO) {
// 校验存在
validateRecordExists(updateReqVO.getId());
// 更新
QrcodeRecordDO updateObj = BeanUtils.toBean(updateReqVO, QrcodeRecordDO.class);
qrcodeRecordMapper.updateById(updateObj);
}
@Override
public void deleteRecord(Long id) {
// 校验存在
validateRecordExists(id);
// 删除
qrcodeRecordMapper.deleteById(id);
}
private void validateRecordExists(Long id) {
if (qrcodeRecordMapper.selectById(id) == null) {
throw exception(RECORD_NOT_EXISTS);
}
}
@Override
public QrcodeRecordDO getRecord(Long id) {
return qrcodeRecordMapper.selectById(id);
}
@Override
public PageResult<QrcodeRecordDO> getRecordPage(QrcodeRecordPageReqVO pageReqVO) {
return qrcodeRecordMapper.selectPage(pageReqVO);
}
@Override
public void generateOrRefresh(QrcodeBizTypeEnum bizType, Long bizId, String bizCode, String scene) throws UnsupportedEncodingException {
if (bizType == null || bizId == null) {
throw new IllegalArgumentException("bizType 或 bizId 不能为空");
}
String qrScene = StrUtil.blankToDefault(scene, "DETAIL");
// 1. 幂等查询biz_type + biz_id + scene 唯一)
QrcodeRecordDO existed = qrcodeRecordMapper.selectOne(
new LambdaQueryWrapper<QrcodeRecordDO>()
.eq(QrcodeRecordDO::getBizType, bizType.getCode())
.eq(QrcodeRecordDO::getBizId, bizId)
.eq(QrcodeRecordDO::getBizCode,bizCode)
.eq(QrcodeRecordDO::getCodeType,"QR")
.eq(QrcodeRecordDO::getQrScene, qrScene)
.last("limit 1")
);
// 2. 组装二维码内容(统一扫码入口)
// String qrContent = "{\"type\":\"" + bizType.getCode()
// + "\",\"id\":" + bizId
// + (StrUtil.isNotBlank(bizCode) ? ",\"code\":\"" + bizCode + "\"" : "")
// + "}";
String qrContent = bizType.getCode() + "-" + bizId;
// 3. 生成二维码PNG
byte[] pngBytes = buildQrPng(qrContent, width, height);
// 4. 选择bucket + objectName
String bucket = resolveBucket(bizType); // 例如 yudao.qrcode.buckets.mold
String objectName = bizType.getCode().toLowerCase() + "/qr/" + LocalDate.now() + "/" + bizId + ".png";
String fileName = bizType.getCode().toLowerCase() + "_" + bizCode + ".png";
// 5. 上传文件(按你项目 FileApi 实际签名改)
// 如果支持bucket参数用这个
// FileRespDTO file = fileApi.createFile(bucket, objectName, "image/png", pngBytes);
// 默认上传
Map<String, String> file = fileApi.createFile(fileName, objectName, pngBytes);
String fileUrl = file.get("fileUrl");
// 6. upsert 记录
QrcodeRecordDO record = new QrcodeRecordDO();
record.setBizType(bizType.getCode());
record.setBizId(bizId);
record.setBizCode(bizCode);
record.setQrScene(qrScene);
record.setQrContent(qrContent);
record.setFileName(fileName);
record.setBucketName(bucket);
record.setObjectName(objectName);
record.setQrcodeFileUrl(fileUrl);
record.setMimeType("image/png");
record.setFileSize((long) pngBytes.length);
record.setStatus(1);
if (existed == null) {
qrcodeRecordMapper.insert(record);
} else {
record.setId(existed.getId());
qrcodeRecordMapper.updateById(record);
}
}
@Override
// @Transactional(rollbackFor = Exception.class)
public void generateOrRefreshBarcode(QrcodeBizTypeEnum bizType, Long bizId, String bizCode, String scene) throws UnsupportedEncodingException {
if (bizType == null || bizId == null) {
throw new IllegalArgumentException("bizType 或 bizId 不能为空");
}
String qrScene = StrUtil.blankToDefault(scene, "DETAIL");
QrcodeRecordDO existed = qrcodeRecordMapper.selectOne(
new LambdaQueryWrapper<QrcodeRecordDO>()
.eq(QrcodeRecordDO::getBizType, bizType.getCode())
.eq(QrcodeRecordDO::getBizId, bizId)
.eq(QrcodeRecordDO::getBizCode, bizCode)
.eq(QrcodeRecordDO::getCodeType, "BARCODE")
.eq(QrcodeRecordDO::getQrScene, qrScene)
.last("limit 1")
);
// String barcodeContent = "{\"type\":\"" + bizType.getCode()
// + "\",\"id\":" + bizId
// + (StrUtil.isNotBlank(bizCode) ? ",\"code\":\"" + bizCode + "\"" : "")
// + "}";
String barcodeContent = bizType.getCode() + "-" + bizId;
int barcodeWidth = 600;
int barcodeHeight = 180;
byte[] pngBytes = buildBarcodePng(barcodeContent, barcodeWidth, barcodeHeight);
String bucket = resolveBucket(bizType);
String objectName = bizType.getCode().toLowerCase() + "/barcode/" + LocalDate.now() + "/" + bizId + ".png";
String fileName = bizType.getCode().toLowerCase() + "_" + bizCode + "_barcode.png";
Map<String, String> file = fileApi.createFile(fileName, objectName, pngBytes);
String fileUrl = file.get("fileUrl");
QrcodeRecordDO record = new QrcodeRecordDO();
record.setBizType(bizType.getCode());
record.setBizId(bizId);
record.setBizCode(bizCode);
record.setCodeType("BARCODE");
record.setQrScene(qrScene);
record.setQrContent(barcodeContent);
record.setFileName(fileName);
record.setBucketName(bucket);
record.setObjectName(objectName);
record.setQrcodeFileUrl(fileUrl);
record.setMimeType("image/png");
record.setFileSize((long) pngBytes.length);
record.setStatus(1);
if (existed == null) {
qrcodeRecordMapper.insert(record);
} else {
record.setId(existed.getId());
qrcodeRecordMapper.updateById(record);
}
}
private byte[] buildBarcodePng(String content, int width, int height) {
try {
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix matrix = new MultiFormatWriter().encode(content, BarcodeFormat.CODE_128, width, height, hints);
BufferedImage image = MatrixToImageWriter.toBufferedImage(matrix);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(image, "png", os);
return os.toByteArray();
} catch (Exception e) {
throw new RuntimeException("生成条形码失败", e);
}
}
@Override
public String buildScanTransitHtml(String type, Long id,String code) {
String fallback = normalizeUrl(StrUtil.blankToDefault(failUrl, "/"));
if (StrUtil.isBlank(type) || id == null) {
return buildRedirectHtml(fallback);
}
if (StrUtil.isBlank(code)) {
return buildRedirectHtml(fallback);
}
QrcodeRecordDO record = qrcodeRecordMapper.selectOne(
new LambdaQueryWrapper<QrcodeRecordDO>()
.eq(QrcodeRecordDO::getBizType, type.trim().toUpperCase())
.eq(QrcodeRecordDO::getBizId, id)
.eq(QrcodeRecordDO::getQrScene, "DETAIL")
.last("limit 1")
);
if (record == null || !StrUtil.equals(record.getBizCode(), code)) {
return buildRedirectHtml(fallback);
}
QrcodeBizHandler handler = handlerMap.get(type.trim().toUpperCase());
if (handler == null) {
return buildRedirectHtml(fallback);
}
try {
if (!handler.exists(id)) {
return buildRedirectHtml(fallback);
}
String target = StrUtil.blankToDefault(handler.buildDeepLink(id), handler.buildH5Path(id));
if (StrUtil.isBlank(target)) {
return buildRedirectHtml(fallback);
}
return buildRedirectHtml(normalizeUrl(target));
} catch (Exception e) {
return buildRedirectHtml(fallback);
}
}
@Override
public String selectQrcodeUrlByIdAndCode(String bizType, Long bizId, String bizCode) {
if (StrUtil.isBlank(bizType) || bizId == null || StrUtil.isBlank(bizCode)) {
return null;
}
QrcodeRecordDO record = qrcodeRecordMapper.selectOne(Wrappers.<QrcodeRecordDO>lambdaQuery()
.eq(QrcodeRecordDO::getBizType, bizType)
.eq(QrcodeRecordDO::getBizId, bizId)
.eq(QrcodeRecordDO::getBizCode, bizCode)
.eq(QrcodeRecordDO::getStatus, 1)
.last("limit 1"));
if (record == null || StrUtil.isBlank(record.getQrcodeFileUrl())) {
return null;
}
return record.getQrcodeFileUrl();
}
@Override
public Map<String, Object> resolveScanBizId(String type, Long id, String code) {
Map<String, Object> result = new HashMap<>();
if (StrUtil.isBlank(type) || id == null || StrUtil.isBlank(code)) {
return null;
}
QrcodeRecordDO record = qrcodeRecordMapper.selectOne(
new LambdaQueryWrapper<QrcodeRecordDO>()
.eq(QrcodeRecordDO::getBizType, type)
.eq(QrcodeRecordDO::getBizId, id)
.eq(QrcodeRecordDO::getBizCode,code)
.eq(QrcodeRecordDO::getQrScene, "DETAIL")
.last("limit 1")
);
if (record == null) {
return null;
}
QrcodeBizHandler handler = handlerMap.get(type.trim().toUpperCase());
if (handler == null) {
return null;
}
result.put("type", type);
result.put("id", id);
return result;
}
private String normalizeUrl(String url) {
if (StrUtil.isBlank(url)) {
return "/";
}
if (StrUtil.startWithAny(url, "http://", "https://", "besure://")) {
return url;
}
String base = StrUtil.blankToDefault(serverBaseUrl, "");
if (StrUtil.isBlank(base)) {
return url.startsWith("/") ? url : "/" + url;
}
return StrUtil.removeSuffix(base, "/") + "/" + StrUtil.removePrefix(url, "/");
}
private String buildRedirectHtml(String targetUrl) {
String safe = escapeHtml(StrUtil.blankToDefault(targetUrl, "/"));
return "<!doctype html><html><head><meta charset=\"UTF-8\">"
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
+ "<meta http-equiv=\"Cache-Control\" content=\"no-store, no-cache, must-revalidate, max-age=0\">"
+ "<meta http-equiv=\"Pragma\" content=\"no-cache\">"
+ "<meta http-equiv=\"Expires\" content=\"0\">"
+ "<title>跳转中...</title></head><body>"
+ "<script>window.location.replace('" + safe + "');</script>"
+ "<noscript><a href=\"" + safe + "\">点击继续</a></noscript>"
+ "</body></html>";
}
private String escapeHtml(String s) {
return s.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;")
.replace("\"", "&quot;")
.replace("'", "&#39;");
}
private String resolveBucket(QrcodeBizTypeEnum bizType) {
if (bizType == null) {
return defaultBucket;
}
if (bucketMap == null || bucketMap.isEmpty()) {
return defaultBucket;
}
String bucket = bucketMap.get(bizType.getCode().toLowerCase());
return StrUtil.blankToDefault(bucket, defaultBucket);
}
private byte[] buildQrPng(String content, int width, int height) {
try {
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix matrix = new MultiFormatWriter()
.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
BufferedImage image = MatrixToImageWriter.toBufferedImage(matrix);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(image, "png", os);
return os.toByteArray();
} catch (Exception e) {
throw new RuntimeException("生成二维码失败", e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteByBiz(QrcodeBizTypeEnum bizType, Long bizId) {
if (bizType == null || bizId == null) {
return;
}
List<QrcodeRecordDO> records = qrcodeRecordMapper.selectList(
Wrappers.<QrcodeRecordDO>lambdaQuery()
.eq(QrcodeRecordDO::getBizType, bizType.getCode())
.eq(QrcodeRecordDO::getBizId, bizId)
);
if (records == null || records.isEmpty()) {
return;
}
for (QrcodeRecordDO record : records) {
try {
String objectName = record.getObjectName();
if (StrUtil.isBlank(objectName)) {
continue;
}
// 通过 path(objectName) 找到 infra_file
Long id = fileApi.getFileByPath(objectName);
if (id == null) {
// 可选log.warn("未找到文件记录, qrcodeId={}, path={}", record.getId(), objectName);
continue;
}
// 用文件主键删除(会删存储+删infra_file记录
fileApi.deleteFile(id);
} catch (Exception e) {
// 你可按策略选择:继续 or 抛异常回滚
// 建议先打日志
log.warn("删除文件失败, qrcodeId={}, path={}", record.getId(), record.getObjectName(), e);
}
}
qrcodeRecordMapper.delete(
Wrappers.<QrcodeRecordDO>lambdaQuery()
.eq(QrcodeRecordDO::getBizType, bizType.getCode())
.eq(QrcodeRecordDO::getBizId, bizId)
);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void regenerateByCodeType(QrcodeBizTypeEnum bizType, Long bizId, String bizCode, String scene, String codeType)
throws UnsupportedEncodingException {
if (bizType == null || bizId == null) {
throw new IllegalArgumentException("bizType 或 bizId 不能为空");
}
String qrScene = StrUtil.blankToDefault(scene, "DETAIL");
String normalizedCodeType = StrUtil.blankToDefault(codeType, "QR").trim().toUpperCase();
if (!StrUtil.equalsAny(normalizedCodeType, "QR", "BARCODE")) {
throw new IllegalArgumentException("codeType 仅支持 QR 或 BARCODE");
}
// 1. 按业务唯一键 + 码类型查询
QrcodeRecordDO existed = qrcodeRecordMapper.selectOne(
new LambdaQueryWrapper<QrcodeRecordDO>()
.eq(QrcodeRecordDO::getBizType, bizType.getCode())
.eq(QrcodeRecordDO::getBizId, bizId)
.eq(QrcodeRecordDO::getBizCode, bizCode)
// .eq(QrcodeRecordDO::getCodeType, normalizedCodeType)
.eq(QrcodeRecordDO::getQrScene, qrScene)
.last("limit 1")
);
// 2. 组装内容
// String content = "{\"type\":\"" + bizType.getCode()
// + "\",\"id\":" + bizId
// + (StrUtil.isNotBlank(bizCode) ? ",\"code\":\"" + bizCode + "\"" : "")
// + "}";
String content = bizType.getCode() + "-" + bizId;
// 3. 生成图片(按类型)
byte[] pngBytes;
String objectDir;
String fileNameSuffix;
if (StrUtil.equals(normalizedCodeType, "BARCODE")) {
pngBytes = buildBarcodePng(content, 600, 180);
objectDir = "barcode";
fileNameSuffix = "_barcode.png";
} else {
pngBytes = buildQrPng(content, width, height);
objectDir = "qr";
fileNameSuffix = ".png";
}
// 4. 组织文件信息
String bucket = resolveBucket(bizType);
String objectName = bizType.getCode().toLowerCase() + "/" + objectDir + "/" + LocalDate.now() + "/" + bizId + ".png";
String fileName = bizType.getCode().toLowerCase() + "_" + StrUtil.blankToDefault(bizCode, String.valueOf(bizId)) + fileNameSuffix;
// 5. 如果已存在先删旧文件MinIO + infra_file
if (existed != null && StrUtil.isNotBlank(existed.getObjectName())) {
try {
Long fileId = fileApi.getFileByPath(existed.getObjectName());
if (fileId != null) {
fileApi.deleteFile(fileId);
}
} catch (Exception e) {
log.warn("删除旧二维码/条形码文件失败, qrcodeId={}, path={}", existed.getId(), existed.getObjectName(), e);
}
}
// 6. 上传新文件
Map<String, String> file = fileApi.createFile(fileName, objectName, pngBytes);
String fileUrl = file.get("fileUrl");
// 7. upsert 记录
QrcodeRecordDO record = new QrcodeRecordDO();
record.setBizType(bizType.getCode());
record.setBizId(bizId);
record.setBizCode(bizCode);
record.setCodeType(normalizedCodeType);
record.setQrScene(qrScene);
record.setQrContent(content);
record.setFileName(fileName);
record.setBucketName(bucket);
record.setObjectName(objectName);
record.setQrcodeFileUrl(fileUrl);
record.setMimeType("image/png");
record.setFileSize((long) pngBytes.length);
record.setStatus(1);
if (existed == null) {
qrcodeRecordMapper.insert(record);
} else {
record.setId(existed.getId());
qrcodeRecordMapper.updateById(record);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void generateOrRefresh(QrcodeBizTypeEnum bizType,
Long bizId,
String bizCode,
String scene,
CodeTypeEnum codeType) throws UnsupportedEncodingException {
if (codeType == null) {
log.info("codeType为空");
return;
}
if (codeType == CodeTypeEnum.BARCODE) {
generateOrRefreshBarcode(bizType, bizId, bizCode, scene);
} else {
generateOrRefresh(bizType, bizId, bizCode, scene);
}
}
}

@ -0,0 +1,12 @@
<?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="cn.iocoder.yudao.module.common.dal.mysql.qrcoderecord.QrcodeRecordMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

@ -133,6 +133,11 @@ public interface ErrorCodeConstants {
// ========== ERP 产品 1-030-500-000 ========== // ========== ERP 产品 1-030-500-000 ==========
ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在"); ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在");
ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_030_500_001, "产品({})未启用"); ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_030_500_001, "产品({})未启用");
ErrorCode PRODUCT_CODE_EXISTS = new ErrorCode(1_030_500_002, "产品编码已存在");
ErrorCode PRODUCT_NAME_AND_STANDARD_EXISTS = new ErrorCode(1_030_500_003, "名称+规格已存在且不能重复");
ErrorCode PRODUCT_CODE_NOT_EXISTS = new ErrorCode(1_030_500_004, "产品编码不存在");
ErrorCode PRODUCT_DEVICE_REL_NOT_EXISTS = new ErrorCode(1_030_500_005, "产品-设备关联不存在");
ErrorCode PRODUCT_MOLD_REL_NOT_EXISTS = new ErrorCode(1_030_500_006, "产品-模具关联不存在");
// ========== ERP 产品分类 1-030-501-000 ========== // ========== ERP 产品分类 1-030-501-000 ==========
ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_501_000, "产品分类不存在"); ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_501_000, "产品分类不存在");

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.erp.controller.admin.autocode; package cn.iocoder.yudao.module.erp.controller.admin.autocode;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.erp.controller.admin.autocode.enums.ErpBarcodeTypeEnum;
import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil; import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil;
import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.Parameters;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -91,6 +93,16 @@ public class AutocodeRuleController {
HttpServletResponse response) throws IOException { HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<AutocodeRuleDO> list = autocodeRuleService.getAutocodeRulePage(pageReqVO).getList(); List<AutocodeRuleDO> list = autocodeRuleService.getAutocodeRulePage(pageReqVO).getList();
List<AutocodeRuleRespVO> autocodeRuleRespVOS = BeanUtils.toBean(list, AutocodeRuleRespVO.class);
if (CollUtil.isNotEmpty(autocodeRuleRespVOS)) {
for (AutocodeRuleRespVO respVO : autocodeRuleRespVOS) {
if (respVO.getBarcodeType()!=null){
respVO.setBarcodeTypeName(ErpBarcodeTypeEnum.getDescByType(respVO.getBarcodeType()));
}
}
}
// 导出 Excel // 导出 Excel
ExcelUtils.write(response, "编码规则.xls", "数据", AutocodeRuleRespVO.class, ExcelUtils.write(response, "编码规则.xls", "数据", AutocodeRuleRespVO.class,
BeanUtils.toBean(list, AutocodeRuleRespVO.class)); BeanUtils.toBean(list, AutocodeRuleRespVO.class));

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.erp.controller.admin.autocode.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* /
*/
@Getter
@AllArgsConstructor
public enum ErpBarcodeTypeEnum {
BARCODE(1, "条形码"),
QRCODE(2, "二维码"),
BOTH(3, "条形码+二维码");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpBarcodeTypeEnum::getType).toArray();
private final Integer type;
private final String desc;
/**
*
*/
public static String getDescByType(Integer type) {
if (type == null) {
return "";
}
for (ErpBarcodeTypeEnum value : values()) {
if (value.getType().equals(type)) {
return value.getDesc();
}
}
return "未知";
}
}

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.autocode.util;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.module.common.enums.CodeTypeEnum;
import cn.iocoder.yudao.module.erp.controller.admin.autocode.vo.AutocodeRecordSaveReqVO; import cn.iocoder.yudao.module.erp.controller.admin.autocode.vo.AutocodeRecordSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.autocode.AutocodePartDO; import cn.iocoder.yudao.module.erp.dal.dataobject.autocode.AutocodePartDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.autocode.AutocodeRecordDO; import cn.iocoder.yudao.module.erp.dal.dataobject.autocode.AutocodeRecordDO;
@ -184,4 +185,14 @@ public class AutoCodeUtil {
return autoCode; return autoCode;
} }
public CodeTypeEnum queryCodeType(String ruleCode) {
AutocodeRuleDO rule = iAutoCodeRuleService.getAutocodeRuleByRuleCode(ruleCode);
if (rule == null) {
return null;
}
return CodeTypeEnum.fromBarcodeType(rule.getBarcodeType());
}
} }

@ -46,4 +46,7 @@ public class AutocodeRulePageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime; private LocalDateTime[] createTime;
@Schema(description = "码类型条形码-1 二维码-2", example = "")
private Integer barcodeType;
} }

@ -27,6 +27,13 @@ public class AutocodeRuleRespVO {
@ExcelProperty("规则名称") @ExcelProperty("规则名称")
private String ruleName; private String ruleName;
@Schema(description = "码类型条形码-1 二维码-2", example = "")
private Integer barcodeType;
@Schema(description = "码类型", example = "")
@ExcelProperty("码类型")
private String barcodeTypeName;
@Schema(description = "描述") @Schema(description = "描述")
@ExcelProperty("描述") @ExcelProperty("描述")
private String ruleDesc; private String ruleDesc;

@ -45,4 +45,8 @@ public class AutocodeRuleSaveReqVO {
@Schema(description = "编码规则组成列表") @Schema(description = "编码规则组成列表")
private List<AutocodePartDO> autocodeParts; private List<AutocodePartDO> autocodeParts;
@Schema(description = "码类型条形码-1 二维码-2", example = "")
private Integer barcodeType;
} }

@ -27,6 +27,7 @@ import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
@ -143,7 +144,7 @@ public class MoldBrandController {
@PostMapping("/mold/create") @PostMapping("/mold/create")
@Operation(summary = "创建模具") @Operation(summary = "创建模具")
@PreAuthorize("@ss.hasPermission('erp:mold-brand:create')") @PreAuthorize("@ss.hasPermission('erp:mold-brand:create')")
public CommonResult<Long> createMold(@Valid @RequestBody MoldSaveReqVO createReqVO) { public CommonResult<Long> createMold(@Valid @RequestBody MoldSaveReqVO createReqVO) throws UnsupportedEncodingException {
return success(moldBrandService.createMold(createReqVO)); return success(moldBrandService.createMold(createReqVO));
} }
@ -186,6 +187,15 @@ public class MoldBrandController {
ExcelUtils.write(response, "模具.xls", "数据", MoldRespVO.class, list); ExcelUtils.write(response, "模具.xls", "数据", MoldRespVO.class, list);
} }
@PostMapping("/regenerate-code")
public CommonResult<Boolean> regenerateCode(@RequestParam("id") Long id,
@RequestParam("code") String code) throws UnsupportedEncodingException {
moldBrandService.regenerateCode(id, code);
return success(true);
}
// ==================== 子表(模具产品) ==================== // ==================== 子表(模具产品) ====================
@GetMapping("/mold-brand-product/page") @GetMapping("/mold-brand-product/page")

@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProductCategoryListReqVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProductCategoryListReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.*; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.*;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
@ -15,6 +16,8 @@ import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper;
import cn.iocoder.yudao.module.erp.framework.bean.ProductTypeEnum; import cn.iocoder.yudao.module.erp.framework.bean.ProductTypeEnum;
import cn.iocoder.yudao.module.erp.service.product.ErpProductCategoryService; import cn.iocoder.yudao.module.erp.service.product.ErpProductCategoryService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.Parameters;
@ -28,14 +31,17 @@ import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.MOLD_CODE_DUPLICATE;
@Tag(name = "管理后台 - ERP 产品") @Tag(name = "管理后台 - ERP 产品")
@RestController @RestController
@ -51,18 +57,20 @@ public class ErpProductController {
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建产品") @Operation(summary = "创建产品")
@PreAuthorize("@ss.hasPermission('erp:product:create')") @PreAuthorize("@ss.hasPermission('erp:product:create')")
public CommonResult<Long> createProduct(@Valid @RequestBody ProductSaveReqVO createReqVO) { public CommonResult<Long> createProduct(@Valid @RequestBody ProductSaveReqVO createReqVO) throws UnsupportedEncodingException {
ErpProductPageReqVO productPageReqVO = new ErpProductPageReqVO(); // ErpProductPageReqVO productPageReqVO = new ErpProductPageReqVO();
productPageReqVO.setName(createReqVO.getName()); // productPageReqVO.setName(createReqVO.getName());
productPageReqVO.setStandard(createReqVO.getStandard()); // productPageReqVO.setStandard(createReqVO.getStandard());
if (productMapper.selectProductExist(productPageReqVO)) { // if (productMapper.selectProductExist(productPageReqVO)) {
return error(400,"名称+规格不能重复"); // return error(400,"名称+规格不能重复");
} // }
productPageReqVO = new ErpProductPageReqVO(); // productPageReqVO = new ErpProductPageReqVO();
productPageReqVO.setCode(createReqVO.getBarCode());
if (!productMapper.selectProductCodeExist(productPageReqVO).getList().isEmpty()) { // productPageReqVO.setCode(createReqVO.getBarCode());
return error(400,"编码不能重复"); // if (!productMapper.selectProductCodeExist(productPageReqVO).getList().isEmpty()) {
} // return error(400,"编码不能重复");
// }
return success(productService.createProduct(createReqVO)); return success(productService.createProduct(createReqVO));
} }
@ -99,8 +107,7 @@ public class ErpProductController {
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('erp:product:query')") @PreAuthorize("@ss.hasPermission('erp:product:query')")
public CommonResult<ErpProductRespVO> getProduct(@RequestParam("id") Long id) { public CommonResult<ErpProductRespVO> getProduct(@RequestParam("id") Long id) {
ErpProductDO product = productService.getProduct(id); return success(productService.getProduct(id));
return success(BeanUtils.toBean(product, ErpProductRespVO.class));
} }
@GetMapping("/page") @GetMapping("/page")
@ -231,4 +238,12 @@ public class ErpProductController {
return success(productService.importProductList(list, updateSupport)); return success(productService.importProductList(list, updateSupport));
} }
@PostMapping("/regenerate-code")
public CommonResult<Boolean> regenerateCode(@RequestParam("id") Long id,
@RequestParam("code") String code) throws UnsupportedEncodingException {
productService.regenerateCode(id, code);
return success(true);
// s
}
} }

@ -92,7 +92,12 @@ public class ErpProductUnitController {
@Operation(summary = "获得产品单位精简列表", description = "只包含被开启的单位,主要用于前端的下拉选项") @Operation(summary = "获得产品单位精简列表", description = "只包含被开启的单位,主要用于前端的下拉选项")
public CommonResult<List<ErpProductUnitRespVO>> getProductUnitSimpleList() { public CommonResult<List<ErpProductUnitRespVO>> getProductUnitSimpleList() {
List<ErpProductUnitDO> list = productUnitService.getProductUnitListByStatus(CommonStatusEnum.ENABLE.getStatus()); List<ErpProductUnitDO> list = productUnitService.getProductUnitListByStatus(CommonStatusEnum.ENABLE.getStatus());
return success(convertList(list, unit -> new ErpProductUnitRespVO().setId(unit.getId()).setName(unit.getName()))); list.stream().forEach(item -> {
item.setValue(item.getId().toString());
item.setLabel(item.getName());
});
List<ErpProductUnitRespVO> erpProductUnitRespVOS = convertList(list, unit -> new ErpProductUnitRespVO().setId(unit.getId()).setName(unit.getName()).setValue(unit.getId().toString()).setLabel(unit.getName()));
return success(erpProductUnitRespVOS);
} }
@GetMapping("/export-excel") @GetMapping("/export-excel")

@ -17,6 +17,9 @@ public class ErpProductPageReqVO extends PageParam {
@Schema(description = "产品名称", example = "李四") @Schema(description = "产品名称", example = "李四")
private String name; private String name;
@Schema(description = "规格型号", example = "")
private String deviceSpec;
@Schema(description = "产品分类编号", example = "11161") @Schema(description = "产品分类编号", example = "11161")
private Long categoryId; private Long categoryId;

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.erp.controller.admin.product.vo.product; package cn.iocoder.yudao.module.erp.controller.admin.product.vo.product;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
@ -7,11 +8,12 @@ import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - ERP 产品 Response VO") @Schema(description = "管理后台 - ERP 产品 Response VO")
@Data @Data
@ExcelIgnoreUnannotated @ExcelIgnoreUnannotated
public class ErpProductRespVO { public class ErpProductRespVO extends ErpProductDO {
@Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15672") @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15672")
@ExcelProperty("产品编号") @ExcelProperty("产品编号")
@ -21,6 +23,10 @@ public class ErpProductRespVO {
@ExcelProperty("产品名称") @ExcelProperty("产品名称")
private String name; private String name;
@Schema(description = "规格型号", example = "")
@ExcelProperty("规格型号")
private String deviceSpec;
@Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "X110") @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "X110")
@ExcelProperty("产品条码") @ExcelProperty("产品条码")
private String barCode; private String barCode;
@ -83,4 +89,20 @@ public class ErpProductRespVO {
@Schema(description = "预警库存", example = "161.87") @Schema(description = "预警库存", example = "161.87")
@ExcelProperty("预警库存") @ExcelProperty("预警库存")
private BigDecimal safetyNumber; private BigDecimal safetyNumber;
@Schema(description = "二维码地址", example = "")
private String qrcodeUrl;
//
// @Schema(description = "关联设备ID列表", example = "[11,15,23]")
// private List<Long> deviceIds;
//
// @Schema(description = "关联模具D列表", example = "[11,15,23]")
// private List<Long> moldIds;
@Schema(description = "关联设备列表")
private List<ProductRelationRespVO> devices;
@Schema(description = "关联模具列表")
private List<ProductRelationRespVO> molds;
} }

@ -0,0 +1,15 @@
package cn.iocoder.yudao.module.erp.controller.admin.product.vo.product;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class ProductRelationRespVO {
@Schema(description = "ID", example = "1")
private Long id;
@Schema(description = "名称", example = "设备A")
private String name;
}

@ -1,11 +1,13 @@
package cn.iocoder.yudao.module.erp.controller.admin.product.vo.product; package cn.iocoder.yudao.module.erp.controller.admin.product.vo.product;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List;
@Schema(description = "管理后台 - ERP 产品新增/修改 Request VO") @Schema(description = "管理后台 - ERP 产品新增/修改 Request VO")
@Data @Data
@ -18,8 +20,11 @@ public class ProductSaveReqVO {
@NotEmpty(message = "产品名称不能为空") @NotEmpty(message = "产品名称不能为空")
private String name; private String name;
@Schema(description = "规格型号", example = "")
private String deviceSpec;
@Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "X110") @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "X110")
@NotEmpty(message = "产品条码不能为空") // @NotEmpty(message = "产品条码不能为空")
private String barCode; private String barCode;
@Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11161") @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11161")
@ -57,4 +62,10 @@ public class ProductSaveReqVO {
@Schema(description = "预警库存", example = "161.87") @Schema(description = "预警库存", example = "161.87")
private BigDecimal safetyNumber; private BigDecimal safetyNumber;
@Schema(description = "关联设备ID列表", example = "[11,15,23]")
private List<Long> deviceIds;
@Schema(description = "关联模具D列表", example = "[11,15,23]")
private List<Long> moldIds;
} }

@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.module.system.enums.DictTypeConstants; import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@ -43,4 +44,7 @@ public class ErpProductUnitRespVO {
@ExcelProperty("创建时间") @ExcelProperty("创建时间")
private LocalDateTime createTime; private LocalDateTime createTime;
private String value;
private String label;
} }

@ -0,0 +1,96 @@
package cn.iocoder.yudao.module.erp.controller.admin.productdevicerel;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.erp.controller.admin.productdevicerel.vo.*;
import cn.iocoder.yudao.module.erp.dal.dataobject.productdevicerel.ProductDeviceRelDO;
import cn.iocoder.yudao.module.erp.service.productdevicerel.ProductDeviceRelService;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
@Tag(name = "管理后台 - 产品-设备关联")
@RestController
@RequestMapping("/erp/product-device-rel")
@Validated
public class ProductDeviceRelController {
@Resource
private ProductDeviceRelService productDeviceRelService;
@PostMapping("/create")
@Operation(summary = "创建产品-设备关联")
@PreAuthorize("@ss.hasPermission('erp:product-device-rel:create')")
public CommonResult<Long> createProductDeviceRel(@Valid @RequestBody ProductDeviceRelSaveReqVO createReqVO) {
return success(productDeviceRelService.createProductDeviceRel(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新产品-设备关联")
@PreAuthorize("@ss.hasPermission('erp:product-device-rel:update')")
public CommonResult<Boolean> updateProductDeviceRel(@Valid @RequestBody ProductDeviceRelSaveReqVO updateReqVO) {
productDeviceRelService.updateProductDeviceRel(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除产品-设备关联")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('erp:product-device-rel:delete')")
public CommonResult<Boolean> deleteProductDeviceRel(@RequestParam("id") Long id) {
productDeviceRelService.deleteProductDeviceRel(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得产品-设备关联")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('erp:product-device-rel:query')")
public CommonResult<ProductDeviceRelRespVO> getProductDeviceRel(@RequestParam("id") Long id) {
ProductDeviceRelDO productDeviceRel = productDeviceRelService.getProductDeviceRel(id);
return success(BeanUtils.toBean(productDeviceRel, ProductDeviceRelRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得产品-设备关联分页")
@PreAuthorize("@ss.hasPermission('erp:product-device-rel:query')")
public CommonResult<PageResult<ProductDeviceRelRespVO>> getProductDeviceRelPage(@Valid ProductDeviceRelPageReqVO pageReqVO) {
PageResult<ProductDeviceRelDO> pageResult = productDeviceRelService.getProductDeviceRelPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, ProductDeviceRelRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出产品-设备关联 Excel")
@PreAuthorize("@ss.hasPermission('erp:product-device-rel:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportProductDeviceRelExcel(@Valid ProductDeviceRelPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<ProductDeviceRelDO> list = productDeviceRelService.getProductDeviceRelPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "产品-设备关联.xls", "数据", ProductDeviceRelRespVO.class,
BeanUtils.toBean(list, ProductDeviceRelRespVO.class));
}
}

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.erp.controller.admin.productdevicerel.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 产品-设备关联分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ProductDeviceRelPageReqVO extends PageParam {
@Schema(description = "产品ID", example = "18574")
private Long productId;
@Schema(description = "设备ID", example = "21075")
private Long deviceId;
@Schema(description = "排序")
private Integer sort;
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.erp.controller.admin.productdevicerel.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 产品-设备关联 Response VO")
@Data
@ExcelIgnoreUnannotated
public class ProductDeviceRelRespVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "28748")
@ExcelProperty("主键")
private Long id;
@Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "18574")
@ExcelProperty("产品ID")
private Long productId;
@Schema(description = "设备ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21075")
@ExcelProperty("设备ID")
private Long deviceId;
@Schema(description = "排序")
@ExcelProperty("排序")
private Integer sort;
@Schema(description = "备注", example = "随便")
@ExcelProperty("备注")
private String remark;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.erp.controller.admin.productdevicerel.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import javax.validation.constraints.NotNull;
import java.util.*;
@Schema(description = "管理后台 - 产品-设备关联新增/修改 Request VO")
@Data
public class ProductDeviceRelSaveReqVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "28748")
private Long id;
@Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "18574")
@NotNull(message = "产品ID不能为空")
private Long productId;
@Schema(description = "设备ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21075")
@NotNull(message = "设备ID不能为空")
private Long deviceId;
@Schema(description = "排序")
private Integer sort;
@Schema(description = "备注", example = "随便")
private String remark;
}

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.erp.controller.admin.productmoldrel;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.erp.controller.admin.productmoldrel.vo.*;
import cn.iocoder.yudao.module.erp.dal.dataobject.productmoldrel.ProductMoldRelDO;
import cn.iocoder.yudao.module.erp.service.productmoldrel.ProductMoldRelService;
@Tag(name = "管理后台 - 产品-模具关联")
@RestController
@RequestMapping("/erp/product-mold-rel")
@Validated
public class ProductMoldRelController {
@Resource
private ProductMoldRelService productMoldRelService;
@PostMapping("/create")
@Operation(summary = "创建产品-模具关联")
@PreAuthorize("@ss.hasPermission('erp:product-mold-rel:create')")
public CommonResult<Long> createProductMoldRel(@Valid @RequestBody ProductMoldRelSaveReqVO createReqVO) {
return success(productMoldRelService.createProductMoldRel(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新产品-模具关联")
@PreAuthorize("@ss.hasPermission('erp:product-mold-rel:update')")
public CommonResult<Boolean> updateProductMoldRel(@Valid @RequestBody ProductMoldRelSaveReqVO updateReqVO) {
productMoldRelService.updateProductMoldRel(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除产品-模具关联")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('erp:product-mold-rel:delete')")
public CommonResult<Boolean> deleteProductMoldRel(@RequestParam("id") Long id) {
productMoldRelService.deleteProductMoldRel(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得产品-模具关联")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('erp:product-mold-rel:query')")
public CommonResult<ProductMoldRelRespVO> getProductMoldRel(@RequestParam("id") Long id) {
ProductMoldRelDO productMoldRel = productMoldRelService.getProductMoldRel(id);
return success(BeanUtils.toBean(productMoldRel, ProductMoldRelRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得产品-模具关联分页")
@PreAuthorize("@ss.hasPermission('erp:product-mold-rel:query')")
public CommonResult<PageResult<ProductMoldRelRespVO>> getProductMoldRelPage(@Valid ProductMoldRelPageReqVO pageReqVO) {
PageResult<ProductMoldRelDO> pageResult = productMoldRelService.getProductMoldRelPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, ProductMoldRelRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出产品-模具关联 Excel")
@PreAuthorize("@ss.hasPermission('erp:product-mold-rel:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportProductMoldRelExcel(@Valid ProductMoldRelPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<ProductMoldRelDO> list = productMoldRelService.getProductMoldRelPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "产品-模具关联.xls", "数据", ProductMoldRelRespVO.class,
BeanUtils.toBean(list, ProductMoldRelRespVO.class));
}
}

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.erp.controller.admin.productmoldrel.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 产品-模具关联分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ProductMoldRelPageReqVO extends PageParam {
@Schema(description = "产品ID", example = "30420")
private Long productId;
@Schema(description = "模具ID", example = "243")
private Long moldId;
@Schema(description = "排序")
private Integer sort;
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.erp.controller.admin.productmoldrel.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 产品-模具关联 Response VO")
@Data
@ExcelIgnoreUnannotated
public class ProductMoldRelRespVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "11772")
@ExcelProperty("主键")
private Long id;
@Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "30420")
@ExcelProperty("产品ID")
private Long productId;
@Schema(description = "模具ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "243")
@ExcelProperty("模具ID")
private Long moldId;
@Schema(description = "排序")
@ExcelProperty("排序")
private Integer sort;
@Schema(description = "备注", example = "随便")
@ExcelProperty("备注")
private String remark;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.erp.controller.admin.productmoldrel.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
@Schema(description = "管理后台 - 产品-模具关联新增/修改 Request VO")
@Data
public class ProductMoldRelSaveReqVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "11772")
private Long id;
@Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "30420")
@NotNull(message = "产品ID不能为空")
private Long productId;
@Schema(description = "模具ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "243")
@NotNull(message = "模具ID不能为空")
private Long moldId;
@Schema(description = "排序")
private Integer sort;
@Schema(description = "备注", example = "随便")
private String remark;
}

@ -70,4 +70,10 @@ public class AutocodeRuleDO extends BaseDO {
*/ */
private Boolean isEnable; private Boolean isEnable;
/**
* -1 -2
*
*/
private Integer barcodeType;
} }

@ -1,9 +1,12 @@
package cn.iocoder.yudao.module.erp.dal.dataobject.product; package cn.iocoder.yudao.module.erp.dal.dataobject.product;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*; import lombok.*;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -32,6 +35,11 @@ public class ErpProductDO extends BaseDO {
* *
*/ */
private String name; private String name;
/**
*
*/
private String deviceSpec;
/** /**
* *
*/ */
@ -100,4 +108,10 @@ public class ErpProductDO extends BaseDO {
* *
*/ */
private BigDecimal safetyNumber; private BigDecimal safetyNumber;
/**
*
*/
@TableField(exist = false)
private String qrcodeUrl;
} }

@ -46,6 +46,10 @@ public class ErpProductUnitDO extends BaseDO {
/** /**
* *
*/ */
private Integer status;
private Integer status;
@TableField(exist = false)
private String value;
@TableField(exist = false)
private String label;
} }

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.erp.dal.dataobject.productdevicerel;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* - DO
*
* @author
*/
@TableName("erp_product_device_rel")
@KeySequence("erp_product_device_rel_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ProductDeviceRelDO extends BaseDO {
/**
*
*/
@TableId
private Long id;
/**
* ID
*/
private Long productId;
/**
* ID
*/
private Long deviceId;
/**
*
*/
private Integer sort;
/**
*
*/
private String remark;
}

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.erp.dal.dataobject.productmoldrel;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* - DO
*
* @author
*/
@TableName("erp_product_mold_rel")
@KeySequence("erp_product_mold_rel_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ProductMoldRelDO extends BaseDO {
/**
*
*/
@TableId
private Long id;
/**
* ID
*/
private Long productId;
/**
* ID
*/
private Long moldId;
/**
*
*/
private Integer sort;
/**
*
*/
private String remark;
}

@ -6,10 +6,12 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductRelationRespVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
@ -39,16 +41,18 @@ public interface ErpProductMapper extends BaseMapperX<ErpProductDO> {
.orderByAsc(ErpProductDO::getId)); .orderByAsc(ErpProductDO::getId));
} }
default Boolean selectProductExist(ErpProductPageReqVO reqVO) { default Boolean selectProductExist(ErpProductDO reqVO) {
LambdaQueryWrapperX<ErpProductDO> queryWrapper = (LambdaQueryWrapperX<ErpProductDO>) new LambdaQueryWrapperX<ErpProductDO>() if (!StringUtils.hasText(reqVO.getName()) || !StringUtils.hasText(reqVO.getStandard())) {
.orderByAsc(ErpProductDO::getId); return false;
if (StringUtils.hasText(reqVO.getName()) && StringUtils.hasText(reqVO.getStandard())) {
// 组合查询name 和 standard 必须同时匹配
queryWrapper.eq(ErpProductDO::getName, reqVO.getName())
.eq(ErpProductDO::getStandard, reqVO.getStandard());
return !selectPage(reqVO, queryWrapper).getList().isEmpty();
} }
return false;
// 直接使用 count 查询
Long count = selectCount(new LambdaQueryWrapper<ErpProductDO>()
.eq(ErpProductDO::getName, reqVO.getName())
.eq(ErpProductDO::getStandard, reqVO.getStandard()));
return count > 0;
} }
default Long selectCountByCategoryId(Long categoryId) { default Long selectCountByCategoryId(Long categoryId) {
@ -83,5 +87,8 @@ public interface ErpProductMapper extends BaseMapperX<ErpProductDO> {
return selectList(new LambdaQueryWrapperX<ErpProductDO>().in(ErpProductDO::getName, names)); return selectList(new LambdaQueryWrapperX<ErpProductDO>().in(ErpProductDO::getName, names));
} }
List<ProductRelationRespVO> selectDevicesByProductId(@Param("productId") Long productId);
List<ProductRelationRespVO> selectMoldsByProductId(@Param("productId") Long productId);
} }

@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.erp.dal.mysql.productdevicerel;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.erp.dal.dataobject.productdevicerel.ProductDeviceRelDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.erp.controller.admin.productdevicerel.vo.*;
/**
* - Mapper
*
* @author
*/
@Mapper
public interface ProductDeviceRelMapper extends BaseMapperX<ProductDeviceRelDO> {
default PageResult<ProductDeviceRelDO> selectPage(ProductDeviceRelPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<ProductDeviceRelDO>()
.eqIfPresent(ProductDeviceRelDO::getProductId, reqVO.getProductId())
.eqIfPresent(ProductDeviceRelDO::getDeviceId, reqVO.getDeviceId())
.eqIfPresent(ProductDeviceRelDO::getSort, reqVO.getSort())
.eqIfPresent(ProductDeviceRelDO::getRemark, reqVO.getRemark())
.betweenIfPresent(ProductDeviceRelDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(ProductDeviceRelDO::getId));
}
}

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.erp.dal.mysql.productmoldrel;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.erp.dal.dataobject.productmoldrel.ProductMoldRelDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.erp.controller.admin.productmoldrel.vo.*;
/**
* - Mapper
*
* @author
*/
@Mapper
public interface ProductMoldRelMapper extends BaseMapperX<ProductMoldRelDO> {
default PageResult<ProductMoldRelDO> selectPage(ProductMoldRelPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<ProductMoldRelDO>()
.eqIfPresent(ProductMoldRelDO::getProductId, reqVO.getProductId())
.eqIfPresent(ProductMoldRelDO::getMoldId, reqVO.getMoldId())
.eqIfPresent(ProductMoldRelDO::getSort, reqVO.getSort())
.eqIfPresent(ProductMoldRelDO::getRemark, reqVO.getRemark())
.betweenIfPresent(ProductMoldRelDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(ProductMoldRelDO::getId));
}
}

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.erp.handler;
import cn.iocoder.yudao.module.common.dal.mysql.mold.MoldMapper;
import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum;
import cn.iocoder.yudao.module.common.handler.QrcodeBizHandler;
import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class ProductQrcodeBizHandler implements QrcodeBizHandler {
@Resource
private ErpProductMapper productMapper;
public String getBizType() {
return QrcodeBizTypeEnum.PRODUCT.getCode();
}
public boolean exists(Long id) { return productMapper.selectById(id) != null; }
public String buildDeepLink(Long id) {
// return "besure://mold/detail?id=" + id;
//TODO 替换成app连接
return "https://www.baidu.com";
}
public String buildH5Path(Long id) {
// return "/h5/mold/view?id=" + id;
//TODO 替换成app连接不存在页面
return "https://baike.baidu.com/item/%E6%98%9F%E5%BA%A7/8072715?fr=aladdin";
}
}

@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.erp.controller.admin.mold.vo.MoldBrandTreeRespVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -96,7 +97,7 @@ public interface MoldBrandService {
* @param mold * @param mold
* @return * @return
*/ */
Long createMold(@Valid MoldSaveReqVO createReqVO); Long createMold(@Valid MoldSaveReqVO createReqVO) throws UnsupportedEncodingException;
/** /**
* *
@ -184,4 +185,6 @@ public interface MoldBrandService {
} }
List<MoldBrandTreeRespVO> getMoldBrandTree(); List<MoldBrandTreeRespVO> getMoldBrandTree();
void regenerateCode(Long id, String code) throws UnsupportedEncodingException;
} }

@ -15,6 +15,10 @@ import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO;
import cn.iocoder.yudao.module.common.dal.dataobject.moldrepair.MoldRepairDO; import cn.iocoder.yudao.module.common.dal.dataobject.moldrepair.MoldRepairDO;
import cn.iocoder.yudao.module.common.dal.dataobject.moldrepair.MoldRepairLineDO; import cn.iocoder.yudao.module.common.dal.dataobject.moldrepair.MoldRepairLineDO;
import cn.iocoder.yudao.module.common.dal.dataobject.moldticketresults.MoldTicketResultsDO; import cn.iocoder.yudao.module.common.dal.dataobject.moldticketresults.MoldTicketResultsDO;
import cn.iocoder.yudao.module.common.enums.CodeTypeEnum;
import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum;
import cn.iocoder.yudao.module.common.service.qrcordrecord.QrcodeRecordService;
import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil;
import cn.iocoder.yudao.module.erp.controller.admin.mold.vo.MoldBrandTreeRespVO; import cn.iocoder.yudao.module.erp.controller.admin.mold.vo.MoldBrandTreeRespVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
@ -29,18 +33,23 @@ import cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService; import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.common.api.mold.enums.ErrorCodeConstants.FAILED_TO_REGENERATE;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
/** /**
@ -50,6 +59,7 @@ import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
*/ */
@Service @Service
@Validated @Validated
@Slf4j
public class MoldBrandServiceImpl implements MoldBrandService { public class MoldBrandServiceImpl implements MoldBrandService {
@Resource @Resource
@ -66,6 +76,12 @@ public class MoldBrandServiceImpl implements MoldBrandService {
private ErpProductUnitService productUnitService; private ErpProductUnitService productUnitService;
@Resource @Resource
private ErpProductService productService; private ErpProductService productService;
@Resource
private QrcodeRecordService qrcodeService;
@Autowired
private AutoCodeUtil autoCodeUtil;
@Override @Override
public Long createMoldBrand(MoldBrandSaveReqVO createReqVO) { public Long createMoldBrand(MoldBrandSaveReqVO createReqVO) {
// 插入 // 插入
@ -173,19 +189,48 @@ public class MoldBrandServiceImpl implements MoldBrandService {
}); });
} }
@Override @Override
public Long createMold(MoldSaveReqVO createReqVO) { public Long createMold(MoldSaveReqVO createReqVO) throws UnsupportedEncodingException {
String Code = createReqVO.getCode(); String Code = createReqVO.getCode();
if (StrUtil.isBlank(Code)) { // if (StrUtil.isBlank(Code)) {
throw new ServiceException(ErrorCodeConstants.MOLD_CODE_EMPTY); // throw new ServiceException(ErrorCodeConstants.MOLD_CODE_EMPTY);
} // }
boolean exists = moldMapper.exists(
new LambdaQueryWrapperX<MoldDO>().eq(MoldDO::getCode, Code) // boolean exists = moldMapper.exists(
); // new LambdaQueryWrapperX<MoldDO>().eq(MoldDO::getCode, Code)
if (exists) { // );
throw new ServiceException(ErrorCodeConstants.MOLD_CODE_DUPLICATE); // if (exists) {
} // throw new ServiceException(ErrorCodeConstants.MOLD_CODE_DUPLICATE);
// }
MoldDO mold = BeanUtils.toBean(createReqVO, MoldDO.class); MoldDO mold = BeanUtils.toBean(createReqVO, MoldDO.class);
if (StringUtils.isBlank(Code)) {
mold.setCode(autoCodeUtil.genSerialCode("MOLD_CODE_GENERATE",null));
} else {
if (moldMapper.selectOne(Wrappers.<MoldDO>lambdaQuery().eq(MoldDO::getCode,Code)) != null) {
throw exception(MOLD_CODE_DUPLICATE);
}
}
moldMapper.insert(mold); moldMapper.insert(mold);
CodeTypeEnum codeType = autoCodeUtil.queryCodeType("MOLD_CODE_GENERATE");
if (codeType==null){
log.warn("[创建模具]未配置码类型跳过生产ruleCode={}","MOLD_CODE_GENERATE");
return mold.getId();
}
qrcodeService.generateOrRefresh(
QrcodeBizTypeEnum.MOLD,
mold.getId(),
mold.getCode(),
"DETAIL",
codeType
);
return mold.getId(); return mold.getId();
} }
@ -201,6 +246,10 @@ public class MoldBrandServiceImpl implements MoldBrandService {
public void deleteMold(Long id) { public void deleteMold(Long id) {
// 校验存在 // 校验存在
validateMoldExists(id); validateMoldExists(id);
// 删除二维码/条形码
qrcodeService.deleteByBiz(QrcodeBizTypeEnum.MOLD, id);
// 删除 // 删除
moldMapper.deleteById(id); moldMapper.deleteById(id);
} }
@ -255,7 +304,8 @@ public class MoldBrandServiceImpl implements MoldBrandService {
if(CollectionUtils.isNotEmpty(moldRepairDOMap)){ if(CollectionUtils.isNotEmpty(moldRepairDOMap)){
moldDO.setRepairList(moldRepairDOMap); moldDO.setRepairList(moldRepairDOMap);
} }
String qrcodeUrl = qrcodeService.selectQrcodeUrlByIdAndCode(QrcodeBizTypeEnum.MOLD.getCode(),id,moldDO.getCode());
moldDO.setQrcodeUrl(qrcodeUrl);
return moldDO; return moldDO;
} }
@Override @Override
@ -353,6 +403,27 @@ public class MoldBrandServiceImpl implements MoldBrandService {
return buildMoldBrandTree(allMoldBrands); return buildMoldBrandTree(allMoldBrands);
} }
@Override
public void regenerateCode(Long id, String code) throws UnsupportedEncodingException {
if(moldMapper.selectById(id)==null){
throw exception(MOLD_BRAND_PRODUCT_NOT_EXISTS);
}
if(StringUtils.isBlank(code)){
throw exception(MOLD_CODE_EMPTY);
}
CodeTypeEnum codeGenerate = autoCodeUtil.queryCodeType("MOLD_CODE_GENERATE");
//
qrcodeService.regenerateByCodeType(
QrcodeBizTypeEnum.MOLD,
id,
code,
"DETAIL",
codeGenerate.getCode()
);
}
/** /**
* *
*/ */

@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -30,7 +31,7 @@ public interface ErpProductService {
* @param createReqVO * @param createReqVO
* @return * @return
*/ */
Long createProduct(@Valid ProductSaveReqVO createReqVO); Long createProduct(@Valid ProductSaveReqVO createReqVO) throws UnsupportedEncodingException;
/** /**
* *
@ -60,7 +61,7 @@ public interface ErpProductService {
* @param id * @param id
* @return * @return
*/ */
ErpProductDO getProduct(Long id); ErpProductRespVO getProduct(Long id);
/** /**
* VO * VO
@ -134,4 +135,6 @@ public interface ErpProductService {
* @return * @return
*/ */
ErpProductImportRespVO importProductList(List<ErpProductImportExcelVO> importProducts, boolean isUpdateSupport); ErpProductImportRespVO importProductList(List<ErpProductImportExcelVO> importProducts, boolean isUpdateSupport);
void regenerateCode(Long id, String code) throws UnsupportedEncodingException;
} }

@ -8,21 +8,29 @@ import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductImportExcelVO; import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductImportRespVO; import cn.iocoder.yudao.module.common.enums.CodeTypeEnum;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO; import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; import cn.iocoder.yudao.module.common.service.qrcordrecord.QrcodeRecordService;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO; import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.*;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.productdevicerel.ProductDeviceRelDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.productmoldrel.ProductMoldRelDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductCategoryMapper; import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductCategoryMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper; import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.productdevicerel.ProductDeviceRelMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.productmoldrel.ProductMoldRelMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper;
import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -32,11 +40,13 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.ConstraintViolationException; import javax.validation.ConstraintViolationException;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@ -49,6 +59,7 @@ import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
*/ */
@Service @Service
@Validated @Validated
@Slf4j
public class ErpProductServiceImpl implements ErpProductService { public class ErpProductServiceImpl implements ErpProductService {
@Resource @Resource
@ -65,17 +76,47 @@ public class ErpProductServiceImpl implements ErpProductService {
@Resource @Resource
private ErpStockMapper erpStockMapper; private ErpStockMapper erpStockMapper;
@Resource
private ProductDeviceRelMapper productDeviceRelMapper;
@Resource
private ProductMoldRelMapper productMoldRelMapper;
@Resource @Resource
@Lazy // 延迟注入 @Lazy // 延迟注入
private ErpStockService erpStockService; private ErpStockService erpStockService;
@Resource
private QrcodeRecordService qrcodeService;
@Autowired
private AutoCodeUtil autoCodeUtil;
@Override @Override
public Long createProduct(ProductSaveReqVO createReqVO) { @Transactional(rollbackFor = Exception.class)
public Long createProduct(ProductSaveReqVO createReqVO) throws UnsupportedEncodingException {
String code = createReqVO.getBarCode();
ErpProductDO product = BeanUtils.toBean(createReqVO, ErpProductDO.class);
if (productMapper.selectProductExist(product)) {
throw exception(PRODUCT_NAME_AND_STANDARD_EXISTS);
}
if (StringUtils.isBlank(code)) {
code = autoCodeUtil.genSerialCode("PRODUCT_CODE_GENERATE", null);
} else {
if (productMapper.selectOne(Wrappers.<ErpProductDO>lambdaQuery().eq(ErpProductDO::getBarCode,code)) != null) {
throw exception(PRODUCT_CODE_EXISTS);
}
}
// TODO 芋艿:校验分类 // TODO 芋艿:校验分类
// 插入 // 插入
ErpProductDO product = BeanUtils.toBean(createReqVO, ErpProductDO.class);
ErpProductCategoryDO productCategory = productCategoryMapper.selectById(product.getCategoryId()); ErpProductCategoryDO productCategory = productCategoryMapper.selectById(product.getCategoryId());
Long id = productCategory.getParentId(); Long id = productCategory.getParentId();
product.setSubCategoryName(productCategory.getName()); product.setSubCategoryName(productCategory.getName());
@ -85,12 +126,69 @@ public class ErpProductServiceImpl implements ErpProductService {
product.setCategoryId(id); product.setCategoryId(id);
id = productCategory.getParentId(); id = productCategory.getParentId();
} }
product.setBarCode(productCategory.getCode()+ "-" + code);
productMapper.insert(product); productMapper.insert(product);
//插入关联设备
List<Long> deviceIds = createReqVO.getDeviceIds();
if (CollUtil.isNotEmpty(deviceIds)) {
List<Long> distinctIds = deviceIds.stream().distinct().collect(Collectors.toList());
List<ProductDeviceRelDO> relList = distinctIds.stream()
.map(deviceId -> {
ProductDeviceRelDO rel = new ProductDeviceRelDO();
rel.setProductId(product.getId());
rel.setDeviceId(deviceId);
return rel;
})
.collect(Collectors.toList());
productDeviceRelMapper.insertBatch(relList);
}
// 插入关联模具
List<Long> moldIds = createReqVO.getMoldIds();
if (CollUtil.isNotEmpty(moldIds)) {
List<Long> distinctIds = moldIds.stream().distinct().collect(Collectors.toList());
List<ProductMoldRelDO> relList = distinctIds.stream()
.map(moldId -> {
ProductMoldRelDO rel = new ProductMoldRelDO();
rel.setProductId(product.getId());
rel.setMoldId(moldId);
return rel;
})
.collect(Collectors.toList());
productMoldRelMapper.insertBatch(relList);
}
// 生成二维码
CodeTypeEnum codeType = autoCodeUtil.queryCodeType("PRODUCT_CODE_GENERATE");
if (codeType==null){
log.warn("[创建产品物料]未配置码类型跳过生产ruleCode={}","PRODUCT_CODE_GENERATE");
return product.getId();
}
qrcodeService.generateOrRefresh(
QrcodeBizTypeEnum.PRODUCT,
product.getId(),
product.getBarCode(),
"DETAIL",
codeType
);
// 返回 // 返回
return product.getId(); return product.getId();
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void updateProduct(ProductSaveReqVO updateReqVO) { public void updateProduct(ProductSaveReqVO updateReqVO) {
// TODO 芋艿:校验分类 // TODO 芋艿:校验分类
// 校验存在 // 校验存在
@ -107,6 +205,49 @@ public class ErpProductServiceImpl implements ErpProductService {
id = productCategory.getParentId(); id = productCategory.getParentId();
} }
productMapper.updateById(updateObj); productMapper.updateById(updateObj);
// 先删除旧关联(推荐逻辑删;如果你们没做逻辑删,也可以物理删)
productDeviceRelMapper.delete(Wrappers.<ProductDeviceRelDO>lambdaQuery()
.eq(ProductDeviceRelDO::getProductId,updateObj.getId()));
// 再插入新关联
List<Long> deviceIds = updateReqVO.getDeviceIds();
if (CollUtil.isNotEmpty(deviceIds)) {
List<Long> distinctIds = deviceIds.stream().distinct().collect(Collectors.toList());
List<ProductDeviceRelDO> relList = distinctIds.stream()
.map(deviceId -> {
ProductDeviceRelDO rel = new ProductDeviceRelDO();
rel.setProductId(updateReqVO.getId());
rel.setDeviceId(deviceId);
return rel;
})
.collect(Collectors.toList());
productDeviceRelMapper.insertBatch(relList);
}
// 删除旧模具关联
productMoldRelMapper.delete(Wrappers.<ProductMoldRelDO>lambdaQuery()
.eq(ProductMoldRelDO::getProductId, updateObj.getId()));
// 新增模具关联
List<Long> moldIds = updateReqVO.getMoldIds();
if (CollUtil.isNotEmpty(moldIds)) {
List<Long> distinctIds = moldIds.stream().distinct().collect(Collectors.toList());
List<ProductMoldRelDO> relList = distinctIds.stream()
.map(moldId -> {
ProductMoldRelDO rel = new ProductMoldRelDO();
rel.setProductId(updateReqVO.getId());
rel.setMoldId(moldId);
return rel;
})
.collect(Collectors.toList());
productMoldRelMapper.insertBatch(relList);
}
} }
@Override @Override
@ -153,10 +294,33 @@ public class ErpProductServiceImpl implements ErpProductService {
} }
@Override @Override
public ErpProductDO getProduct(Long id) { public ErpProductRespVO getProduct(Long id) {
return productMapper.selectById(id); ErpProductDO product = productMapper.selectById(id);
if (product == null) {
return null;
}
String qrcodeUrl = qrcodeService.selectQrcodeUrlByIdAndCode(
QrcodeBizTypeEnum.PRODUCT.getCode(), id, product.getBarCode());
product.setQrcodeUrl(qrcodeUrl);
ErpProductRespVO respVO = BeanUtils.toBean(product, ErpProductRespVO.class);
respVO.setDevices(productMapper.selectDevicesByProductId(id));
respVO.setMolds(productMapper.selectMoldsByProductId(id));
//
// respVO.setDeviceIds(respVO.getDevices().stream()
// .map(ProductRelationRespVO::getId)
// .collect(Collectors.toList()));
// respVO.setMoldIds(respVO.getMolds().stream()
// .map(ProductRelationRespVO::getId)
// .collect(Collectors.toList()));
return respVO;
} }
@Override @Override
public List<ErpProductRespVO> getProductVOListByStatus(Integer status,Integer categoryId) { public List<ErpProductRespVO> getProductVOListByStatus(Integer status,Integer categoryId) {
@ -324,6 +488,26 @@ public class ErpProductServiceImpl implements ErpProductService {
return respVO; return respVO;
} }
@Override
public void regenerateCode(Long id, String code) throws UnsupportedEncodingException {
if(productMapper.selectById(id)==null){
throw exception(PRODUCT_NOT_EXISTS);
}
if(StringUtils.isBlank(code)){
throw exception(PRODUCT_CODE_NOT_EXISTS);
}
CodeTypeEnum moldCodeGenerate = autoCodeUtil.queryCodeType("PRODUCT_CODE_GENERATE");
//s
qrcodeService.regenerateByCodeType(
QrcodeBizTypeEnum.PRODUCT,
id,
code,
"DETAIL",
moldCodeGenerate.getCode()
);
}
private ErpProductDO convertToProductDO(ErpProductImportExcelVO importProduct) { private ErpProductDO convertToProductDO(ErpProductImportExcelVO importProduct) {
ErpProductDO productDO = BeanUtils.toBean(importProduct, ErpProductDO.class); ErpProductDO productDO = BeanUtils.toBean(importProduct, ErpProductDO.class);

@ -37,6 +37,7 @@ public class ErpProductUnitServiceImpl implements ErpProductUnitService {
@Lazy // 延迟加载,避免循环依赖 @Lazy // 延迟加载,避免循环依赖
private ErpProductService productService; private ErpProductService productService;
@Override @Override
public Long createProductUnit(ErpProductUnitSaveReqVO createReqVO) { public Long createProductUnit(ErpProductUnitSaveReqVO createReqVO) {
// 1. 校验名字唯一 // 1. 校验名字唯一

@ -0,0 +1,57 @@
package cn.iocoder.yudao.module.erp.service.productdevicerel;
import java.util.*;
import cn.iocoder.yudao.module.erp.controller.admin.productdevicerel.vo.*;
import cn.iocoder.yudao.module.erp.dal.dataobject.productdevicerel.ProductDeviceRelDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import javax.validation.Valid;
/**
* - Service
*
* @author
*/
public interface ProductDeviceRelService {
/**
* -
*
* @param createReqVO
* @return
*/
Long createProductDeviceRel(@Valid ProductDeviceRelSaveReqVO createReqVO);
/**
* -
*
* @param updateReqVO
*/
void updateProductDeviceRel(@Valid ProductDeviceRelSaveReqVO updateReqVO);
/**
* -
*
* @param id
*/
void deleteProductDeviceRel(Long id);
/**
* -
*
* @param id
* @return -
*/
ProductDeviceRelDO getProductDeviceRel(Long id);
/**
* -
*
* @param pageReqVO
* @return -
*/
PageResult<ProductDeviceRelDO> getProductDeviceRelPage(ProductDeviceRelPageReqVO pageReqVO);
}

@ -0,0 +1,75 @@
package cn.iocoder.yudao.module.erp.service.productdevicerel;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.iocoder.yudao.module.erp.controller.admin.productdevicerel.vo.*;
import cn.iocoder.yudao.module.erp.dal.dataobject.productdevicerel.ProductDeviceRelDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.dal.mysql.productdevicerel.ProductDeviceRelMapper;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
/**
* - Service
*
* @author
*/
@Service
@Validated
public class ProductDeviceRelServiceImpl implements ProductDeviceRelService {
@Resource
private ProductDeviceRelMapper productDeviceRelMapper;
@Override
public Long createProductDeviceRel(ProductDeviceRelSaveReqVO createReqVO) {
// 插入
ProductDeviceRelDO productDeviceRel = BeanUtils.toBean(createReqVO, ProductDeviceRelDO.class);
productDeviceRelMapper.insert(productDeviceRel);
// 返回
return productDeviceRel.getId();
}
@Override
public void updateProductDeviceRel(ProductDeviceRelSaveReqVO updateReqVO) {
// 校验存在
validateProductDeviceRelExists(updateReqVO.getId());
// 更新
ProductDeviceRelDO updateObj = BeanUtils.toBean(updateReqVO, ProductDeviceRelDO.class);
productDeviceRelMapper.updateById(updateObj);
}
@Override
public void deleteProductDeviceRel(Long id) {
// 校验存在
validateProductDeviceRelExists(id);
// 删除
productDeviceRelMapper.deleteById(id);
}
private void validateProductDeviceRelExists(Long id) {
if (productDeviceRelMapper.selectById(id) == null) {
throw exception(PRODUCT_DEVICE_REL_NOT_EXISTS);
}
}
@Override
public ProductDeviceRelDO getProductDeviceRel(Long id) {
return productDeviceRelMapper.selectById(id);
}
@Override
public PageResult<ProductDeviceRelDO> getProductDeviceRelPage(ProductDeviceRelPageReqVO pageReqVO) {
return productDeviceRelMapper.selectPage(pageReqVO);
}
}

@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.erp.service.productmoldrel;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.module.erp.controller.admin.productmoldrel.vo.*;
import cn.iocoder.yudao.module.erp.dal.dataobject.productmoldrel.ProductMoldRelDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* - Service
*
* @author
*/
public interface ProductMoldRelService {
/**
* -
*
* @param createReqVO
* @return
*/
Long createProductMoldRel(@Valid ProductMoldRelSaveReqVO createReqVO);
/**
* -
*
* @param updateReqVO
*/
void updateProductMoldRel(@Valid ProductMoldRelSaveReqVO updateReqVO);
/**
* -
*
* @param id
*/
void deleteProductMoldRel(Long id);
/**
* -
*
* @param id
* @return -
*/
ProductMoldRelDO getProductMoldRel(Long id);
/**
* -
*
* @param pageReqVO
* @return -
*/
PageResult<ProductMoldRelDO> getProductMoldRelPage(ProductMoldRelPageReqVO pageReqVO);
}

@ -0,0 +1,74 @@
package cn.iocoder.yudao.module.erp.service.productmoldrel;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.iocoder.yudao.module.erp.controller.admin.productmoldrel.vo.*;
import cn.iocoder.yudao.module.erp.dal.dataobject.productmoldrel.ProductMoldRelDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.dal.mysql.productmoldrel.ProductMoldRelMapper;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
/**
* - Service
*
* @author
*/
@Service
@Validated
public class ProductMoldRelServiceImpl implements ProductMoldRelService {
@Resource
private ProductMoldRelMapper productMoldRelMapper;
@Override
public Long createProductMoldRel(ProductMoldRelSaveReqVO createReqVO) {
// 插入
ProductMoldRelDO productMoldRel = BeanUtils.toBean(createReqVO, ProductMoldRelDO.class);
productMoldRelMapper.insert(productMoldRel);
// 返回
return productMoldRel.getId();
}
@Override
public void updateProductMoldRel(ProductMoldRelSaveReqVO updateReqVO) {
// 校验存在
validateProductMoldRelExists(updateReqVO.getId());
// 更新
ProductMoldRelDO updateObj = BeanUtils.toBean(updateReqVO, ProductMoldRelDO.class);
productMoldRelMapper.updateById(updateObj);
}
@Override
public void deleteProductMoldRel(Long id) {
// 校验存在
validateProductMoldRelExists(id);
// 删除
productMoldRelMapper.deleteById(id);
}
private void validateProductMoldRelExists(Long id) {
if (productMoldRelMapper.selectById(id) == null) {
throw exception(PRODUCT_MOLD_REL_NOT_EXISTS);
}
}
@Override
public ProductMoldRelDO getProductMoldRel(Long id) {
return productMoldRelMapper.selectById(id);
}
@Override
public PageResult<ProductMoldRelDO> getProductMoldRelPage(ProductMoldRelPageReqVO pageReqVO) {
return productMoldRelMapper.selectPage(pageReqVO);
}
}

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.common.controller.admin.mold.vo.MoldSaveReqVO; import cn.iocoder.yudao.module.common.controller.admin.mold.vo.MoldSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO;
import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO; import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO;
@ -151,9 +152,9 @@ public class ErpStockOutServiceImpl implements ErpStockOutService {
ErpStockRecordBizTypeEnum.OTHER_OUT.getType(), stockOutItem.getOutId(), stockOutItem.getId(), stockOut.getNo(),stockOut.getOutTime())); ErpStockRecordBizTypeEnum.OTHER_OUT.getType(), stockOutItem.getOutId(), stockOutItem.getId(), stockOut.getNo(),stockOut.getOutTime()));
} else { } else {
ErpProductDO productDO = productService.getProduct(stockOutItem.getProductId()); ErpProductRespVO product = productService.getProduct(stockOutItem.getProductId());
stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO(
stockOutItem.getProductId(),productDO.getCategoryId(), stockOutItem.getWarehouseId(), count, stockOutItem.getProductId(),product.getCategoryId(), stockOutItem.getWarehouseId(), count,
ErpStockRecordBizTypeEnum.getTypeByName(stockOut.getOutType(),status), stockOutItem.getOutId(), stockOutItem.getId(), stockOut.getNo(),stockOut.getOutTime())); ErpStockRecordBizTypeEnum.getTypeByName(stockOut.getOutType(),status), stockOutItem.getOutId(), stockOutItem.getId(), stockOut.getNo(),stockOut.getOutTime()));
} }

@ -0,0 +1,42 @@
<?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="cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
<select id="selectDevicesByProductId"
resultType="cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductRelationRespVO">
SELECT DISTINCT
rel.device_id AS id,
CASE
WHEN d.id IS NULL THEN CONCAT('设备[', rel.device_id, ']【已删除】')
WHEN d.deleted = b'1' THEN CONCAT(d.device_name, '(', d.device_code, ')【已删除】')
ELSE CONCAT(d.device_name, '(', d.device_code, ')')
END AS name
FROM erp_product_device_rel rel
LEFT JOIN mes_device_ledger d ON rel.device_id = d.id
WHERE rel.product_id = #{productId}
AND rel.deleted = b'0'
</select>
<select id="selectMoldsByProductId"
resultType="cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductRelationRespVO">
SELECT DISTINCT
rel.mold_id AS id,
CASE
WHEN m.id IS NULL THEN CONCAT('模具[', rel.mold_id, ']【已删除】')
WHEN m.deleted = b'1' THEN CONCAT(m.name, '(', m.code, ')【已删除】')
ELSE CONCAT(m.name, '(', m.code, ')')
END AS name
FROM erp_product_mold_rel rel
LEFT JOIN erp_mold m ON rel.mold_id = m.id
WHERE rel.product_id = #{productId}
AND rel.deleted = b'0'
</select>
</mapper>

@ -0,0 +1,12 @@
<?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="cn.iocoder.yudao.module.erp.dal.mysql.productdevicerel.ProductDeviceRelMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

@ -0,0 +1,12 @@
<?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="cn.iocoder.yudao.module.erp.dal.mysql.productmoldrel.ProductMoldRelMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

@ -40,4 +40,7 @@ public interface FileApi {
*/ */
Map<String,String> createFile(String name, String path, byte[] content); Map<String,String> createFile(String name, String path, byte[] content);
Long getFileByPath(String path);
void deleteFile(Long id) throws Exception;
} }

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.infra.api.file; package cn.iocoder.yudao.module.infra.api.file;
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
import cn.iocoder.yudao.module.infra.service.file.FileService; import cn.iocoder.yudao.module.infra.service.file.FileService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -24,4 +25,13 @@ public class FileApiImpl implements FileApi {
return fileService.createFile(name, path, content); return fileService.createFile(name, path, content);
} }
@Override
public Long getFileByPath(String path) {
return fileService.getFileByPath(path).getId();
}
@Override
public void deleteFile(Long id) throws Exception {
fileService.deleteFile(id);
}
} }

@ -23,6 +23,7 @@ public class SecurityConfiguration {
@Override @Override
public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) { public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
// Swagger 接口文档 // Swagger 接口文档
String aa="";
registry.requestMatchers("/v3/api-docs/**").permitAll() registry.requestMatchers("/v3/api-docs/**").permitAll()
.requestMatchers("/webjars/**").permitAll() .requestMatchers("/webjars/**").permitAll()
.requestMatchers("/swagger-ui.html").permitAll() .requestMatchers("/swagger-ui.html").permitAll()
@ -37,6 +38,40 @@ public class SecurityConfiguration {
.requestMatchers(adminSeverContextPath + "/**").permitAll(); .requestMatchers(adminSeverContextPath + "/**").permitAll();
// 文件读取 // 文件读取
registry.requestMatchers(buildAdminApi("/infra/file/*/get/**")).permitAll(); registry.requestMatchers(buildAdminApi("/infra/file/*/get/**")).permitAll();
//大屏跳转
registry.requestMatchers(buildAdminApi("/mes/plan/getProductPlans")).permitAll();
registry.requestMatchers(buildAdminApi("/mes/plan/getPlanCapacity")).permitAll();
registry.requestMatchers(buildAdminApi("/mes/plan/getWeekTrend")).permitAll();
registry.requestMatchers(buildAdminApi("/mes/plan/getLastSevenDaysCompletedCount")).permitAll();
registry.requestMatchers(buildAdminApi("/iot/device-operation-record/deviceOperationList")).permitAll();
registry.requestMatchers(buildAdminApi("/mes/plan/getLastDaysRate")).permitAll();
registry.requestMatchers(buildAdminApi("/mes/energy-type/list")).permitAll();
registry.requestMatchers(buildAdminApi("/mes/energy-device/latestSevenDaysStatistics")).permitAll();
registry.requestMatchers(buildAdminApi("/iot/device/getDeviceOperationalStatus")).permitAll();
registry.requestMatchers(buildAdminApi("/iot/device-warinning-record/getLastSevenHoursCount")).permitAll();
registry.requestMatchers(buildAdminApi("/mes/dashboard/getTaskStatistics")).permitAll();
registry.requestMatchers(buildAdminApi("/mes/dashboard/getAllTaskList")).permitAll();
registry.requestMatchers(buildAdminApi("/iot/device/device-attribute/batchList")).permitAll();
registry.requestMatchers(buildAdminApi("/mes/energy-device/lastEnergyStatistics")).permitAll();
registry.requestMatchers(buildAdminApi("/iot/device-warinning-record/getList")).permitAll();
} }
}; };

@ -65,4 +65,7 @@ public interface FileService {
*/ */
FilePresignedUrlRespVO getFilePresignedUrl(String path) throws Exception; FilePresignedUrlRespVO getFilePresignedUrl(String path) throws Exception;
FileDO getFileByPath(String path);
} }

@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePresignedUrlRespVO; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePresignedUrlRespVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper; import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -121,4 +122,16 @@ public class FileServiceImpl implements FileService {
object -> object.setConfigId(fileClient.getId())); object -> object.setConfigId(fileClient.getId()));
} }
@Override
public FileDO getFileByPath(String path) {
if (StrUtil.isBlank(path)) {
return null;
}
return fileMapper.selectOne(
Wrappers.<FileDO>lambdaQuery()
.eq(FileDO::getPath, path)
.orderByDesc(FileDO::getId)
.last("limit 1")
); }
} }

@ -84,6 +84,7 @@ public interface ErrorCodeConstants {
ErrorCode TABLE_CREATION_FAILED = new ErrorCode(1_004_000_008, "TDengine 表创建失败"); ErrorCode TABLE_CREATION_FAILED = new ErrorCode(1_004_000_008, "TDengine 表创建失败");
ErrorCode COLOUMN_CREATION_FAILED = new ErrorCode(1_004_000_008, "TDengine 列创建失败"); ErrorCode COLOUMN_CREATION_FAILED = new ErrorCode(1_004_000_008, "TDengine 列创建失败");
ErrorCode COLUMN_RENAME_FAILED = new ErrorCode(1_004_000_008, "列名修改失败");
} }

@ -323,7 +323,7 @@ public class DeviceController {
@GetMapping("/device-attribute/batchList") @GetMapping("/device-attribute/batchList")
@Operation(summary = "获得多个设备的属性数据") @Operation(summary = "获得多个设备的属性数据")
@Parameter(name = "goviewId", description = "大屏ID", required = true) @Parameter(name = "goviewId", description = "大屏ID", required = true)
@PreAuthorize("@ss.hasPermission('iot:device:query')") //@PreAuthorize("@ss.hasPermission('iot:device:query')")
public CommonResult<List<Map<String, Object>>> getMultiDeviceAttributes(@RequestParam("goviewId") Long goviewId) { public CommonResult<List<Map<String, Object>>> getMultiDeviceAttributes(@RequestParam("goviewId") Long goviewId) {
return success(deviceService.getMultiDeviceAttributes(goviewId)); return success(deviceService.getMultiDeviceAttributes(goviewId));
} }

@ -53,7 +53,7 @@ public class DeviceSaveReqVO {
private Boolean isEnable; private Boolean isEnable;
@Schema(description = "关联设备模型", example = "1") @Schema(description = "关联设备模型", example = "1")
@NotNull(message = "关联设备模型ID不能为空") // @NotNull(message = "关联设备模型ID不能为空")
private Long deviceModelId; private Long deviceModelId;
@Schema(description = "通讯协议", example = "OPCUA") @Schema(description = "通讯协议", example = "OPCUA")

@ -26,15 +26,15 @@ public class DeviceModelAttributeRespVO {
private String attributeName; private String attributeName;
@Schema(description = "采集点位类型编码", example = "1") @Schema(description = "采集点位类型编码", example = "1")
@ExcelProperty("采集点位类型编码") @ExcelProperty("点位类型编码")
private String attributeTypeCode; private String attributeTypeCode;
@Schema(description = "点位类型", example = "1") @Schema(description = "点位类型", example = "1")
@ExcelProperty("点位类型") // @ExcelProperty("点位类型")
private String attributeType; private String attributeType;
@Schema(description = "类型名称", example = "1") @Schema(description = "类型名称", example = "1")
@ExcelProperty("类型名称") // @ExcelProperty("类型名称")
private String typeName; private String typeName;
@Schema(description = "数据类型", example = "2") @Schema(description = "数据类型", example = "2")
@ -61,11 +61,11 @@ public class DeviceModelAttributeRespVO {
private String remark; private String remark;
@Schema(description = "采集设备模型id", requiredMode = Schema.RequiredMode.REQUIRED, example = "16848") @Schema(description = "采集设备模型id", requiredMode = Schema.RequiredMode.REQUIRED, example = "16848")
@ExcelProperty("采集设备模型id") // @ExcelProperty("采集设备模型id")
private Long deviceModelId; private Long deviceModelId;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间") // @ExcelProperty("创建时间")
@ColumnWidth(20) // 设置此列的宽度为 20 个字符的宽度 @ColumnWidth(20) // 设置此列的宽度为 20 个字符的宽度
private LocalDateTime createTime; private LocalDateTime createTime;

@ -106,7 +106,7 @@ public class DeviceOperationRecordController {
@GetMapping("/deviceOperationList") @GetMapping("/deviceOperationList")
@Operation(summary = "产线设备运行开机率/稼动率-大屏") @Operation(summary = "产线设备运行开机率/稼动率-大屏")
@PreAuthorize("@ss.hasPermission('iot:device-operation-record:query')") // @PreAuthorize("@ss.hasPermission('iot:device-operation-record:query')")
public CommonResult<List<DeviceTotalTimeRecordRespVO>> deviceOperationList(@Valid DeviceTotalTimeRecordReqVO pageReqVO) { public CommonResult<List<DeviceTotalTimeRecordRespVO>> deviceOperationList(@Valid DeviceTotalTimeRecordReqVO pageReqVO) {
List<DeviceTotalTimeRecordRespVO> deviceTotalTimeRecordRespVOList = deviceOperationRecordService.deviceOperationList(pageReqVO); List<DeviceTotalTimeRecordRespVO> deviceTotalTimeRecordRespVOList = deviceOperationRecordService.deviceOperationList(pageReqVO);
return success(deviceTotalTimeRecordRespVOList); return success(deviceTotalTimeRecordRespVOList);

@ -80,13 +80,30 @@ public class DevicePointRulesController {
public CommonResult<PageResult<DevicePointRulesRespVO>> getDevicePointRulesPage(@Valid DevicePointRulesPageReqVO pageReqVO) { public CommonResult<PageResult<DevicePointRulesRespVO>> getDevicePointRulesPage(@Valid DevicePointRulesPageReqVO pageReqVO) {
PageResult<DevicePointRulesDO> pageResult = devicePointRulesService.getDevicePointRulesPage(pageReqVO); PageResult<DevicePointRulesDO> pageResult = devicePointRulesService.getDevicePointRulesPage(pageReqVO);
PageResult<DevicePointRulesRespVO> rulesRespVOPageResult = BeanUtils.toBean(pageResult, DevicePointRulesRespVO.class); PageResult<DevicePointRulesRespVO> rulesRespVOPageResult = BeanUtils.toBean(pageResult, DevicePointRulesRespVO.class);
for (DevicePointRulesRespVO devicePointRulesRespVO : rulesRespVOPageResult.getList()) { //
if (StringUtils.isNotBlank(devicePointRulesRespVO.getFieldRule())) { // for (DevicePointRulesRespVO respVO : rulesRespVOPageResult.getList()) {
List<PointRulesRespVO> pointRulesVOList = JSON.parseArray(devicePointRulesRespVO.getFieldRule(), PointRulesRespVO.class); // String fieldRule = respVO.getFieldRule();
devicePointRulesRespVO.setPointRulesVOList(pointRulesVOList); // if (StringUtils.isBlank(fieldRule)) {
} // continue;
// }
} //
// String json = fieldRule.trim();
// try {
// if (json.startsWith("[")) {
// List<PointRulesRespVO> pointRulesVOList = JSON.parseArray(json, PointRulesRespVO.class);
// respVO.setPointRulesVOList(pointRulesVOList);
// continue;
// }
//
// if (json.startsWith("{")) {
// respVO.setPointRulesVOList(Collections.emptyList());
//
// }
// } catch (Exception e) {
// // 防御性处理,避免单条脏数据影响整页
// respVO.setPointRulesVOList(Collections.emptyList());
// }
// }
return success(rulesRespVOPageResult); return success(rulesRespVOPageResult);
} }

@ -97,7 +97,7 @@ public class DeviceWarinningRecordController {
@Operation(summary = "获得告警记录列表") @Operation(summary = "获得告警记录列表")
@Parameter(name = "deviceId", description = "设备Id", required = true, example = "1024") @Parameter(name = "deviceId", description = "设备Id", required = true, example = "1024")
@Parameter(name = "orgId", description = "产线组织Id", required = true, example = "1024") @Parameter(name = "orgId", description = "产线组织Id", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:device-warinning-record:query')") //@PreAuthorize("@ss.hasPermission('iot:device-warinning-record:query')")
public CommonResult<List<DeviceWarinningRecordDO>> getList(@RequestParam(name = "deviceId" ,required = false) Long id, public CommonResult<List<DeviceWarinningRecordDO>> getList(@RequestParam(name = "deviceId" ,required = false) Long id,
@RequestParam(name = "orgId" ,required = false) Long orgId) { @RequestParam(name = "orgId" ,required = false) Long orgId) {
List<DeviceWarinningRecordDO> deviceWarinningRecord = deviceWarinningRecordService.getList(id); List<DeviceWarinningRecordDO> deviceWarinningRecord = deviceWarinningRecordService.getList(id);
@ -108,7 +108,7 @@ public class DeviceWarinningRecordController {
@GetMapping("/getLastSevenHoursCount") @GetMapping("/getLastSevenHoursCount")
@Operation(summary = "获取过去7小时每小时告警数量") @Operation(summary = "获取过去7小时每小时告警数量")
@Parameter(name = "orgId", description = "产线组织Id", required = true, example = "1024") @Parameter(name = "orgId", description = "产线组织Id", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:device-warinning-record:query')") //@PreAuthorize("@ss.hasPermission('iot:device-warinning-record:query')")
public CommonResult<List<Map<String, Object>>> getLastSevenHoursCount( @RequestParam(name = "orgId" ,required = false) Long orgId) { public CommonResult<List<Map<String, Object>>> getLastSevenHoursCount( @RequestParam(name = "orgId" ,required = false) Long orgId) {
List<Map<String, Object>> hourCounts = deviceWarinningRecordService.getLastSevenHoursCount(); List<Map<String, Object>> hourCounts = deviceWarinningRecordService.getLastSevenHoursCount();
return success(hourCounts); return success(hourCounts);

@ -19,7 +19,7 @@ public interface DevicePointRulesMapper extends BaseMapperX<DevicePointRulesDO>
default PageResult<DevicePointRulesDO> selectPage(DevicePointRulesPageReqVO reqVO) { default PageResult<DevicePointRulesDO> selectPage(DevicePointRulesPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<DevicePointRulesDO>() return selectPage(reqVO, new LambdaQueryWrapperX<DevicePointRulesDO>()
.eqIfPresent(DevicePointRulesDO::getIdentifier, reqVO.getIdentifier()) .likeIfPresent(DevicePointRulesDO::getIdentifier, reqVO.getIdentifier())
.likeIfPresent(DevicePointRulesDO::getFieldName, reqVO.getFieldName()) .likeIfPresent(DevicePointRulesDO::getFieldName, reqVO.getFieldName())
.eqIfPresent(DevicePointRulesDO::getFieldRule, reqVO.getFieldRule()) .eqIfPresent(DevicePointRulesDO::getFieldRule, reqVO.getFieldRule())
.eqIfPresent(DevicePointRulesDO::getDefaultValue, reqVO.getDefaultValue()) .eqIfPresent(DevicePointRulesDO::getDefaultValue, reqVO.getDefaultValue())

@ -24,11 +24,14 @@ import cn.iocoder.yudao.module.iot.framework.mqtt.consumer.impl.AsyncService;
import cn.iocoder.yudao.module.iot.framework.mqtt.entity.MqttData; import cn.iocoder.yudao.module.iot.framework.mqtt.entity.MqttData;
import cn.iocoder.yudao.module.iot.framework.mqtt.utils.DateUtils; import cn.iocoder.yudao.module.iot.framework.mqtt.utils.DateUtils;
import cn.iocoder.yudao.module.iot.framework.mqtt.utils.MqttDataUtils; import cn.iocoder.yudao.module.iot.framework.mqtt.utils.MqttDataUtils;
import cn.iocoder.yudao.module.iot.framework.util.FormulaEvalUtils;
import cn.iocoder.yudao.module.iot.service.device.DeviceService; import cn.iocoder.yudao.module.iot.service.device.DeviceService;
import cn.iocoder.yudao.module.iot.service.device.TDengineService; import cn.iocoder.yudao.module.iot.service.device.TDengineService;
import cn.iocoder.yudao.module.iot.service.iotorganization.IotOrganizationService; import cn.iocoder.yudao.module.iot.service.iotorganization.IotOrganizationService;
import cn.iocoder.yudao.module.iot.service.mqttrecord.MqttRecordService; import cn.iocoder.yudao.module.iot.service.mqttrecord.MqttRecordService;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@ -42,6 +45,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -301,21 +305,55 @@ public class MqttDataHandler extends SuperConsumer<String> {
// 3. 入库 // 3. 入库
if (!validDataList.isEmpty()) { if (!validDataList.isEmpty()) {
saveToDatabase(deviceId, validDataList, successCount);
} else {
log.warn("设备 {} 未匹配到 MQTT 数据", deviceId);
}
saveToDatabase( // 4. 计算并写入产能
deviceId, try {
validDataList, handleCapacityFormula(device, varListMap);
successCount } catch (Exception e) {
); log.error("设备 {} 产能计算失败", deviceId, e);
}
}
} else { // handleCapacityFormula
private void handleCapacityFormula(DeviceDO device, Map<String, Object> varListMap) {
DevicePointRulesDO formulaRule = devicePointRulesMapper.selectOne(
Wrappers.<DevicePointRulesDO>lambdaQuery()
.eq(DevicePointRulesDO::getDeviceId, device.getId())
.eq(DevicePointRulesDO::getIdentifier, "COUNT")
.orderByDesc(DevicePointRulesDO::getUpdateTime)
.last("limit 1")
);
if (formulaRule == null || StringUtils.isBlank(formulaRule.getFieldRule())) {
return;
}
log.warn("设备 {} 未匹配到 MQTT 数据", deviceId); BigDecimal capacity = null;
String rule = formulaRule.getFieldRule().trim();
if (rule.startsWith("[")) {
JSONArray steps = JSON.parseArray(rule);
capacity = FormulaEvalUtils.evalStepArrayByCode(steps, varListMap);
} else {
// 如需兼容旧 expr 结构可保留
JSONObject root = JSON.parseObject(rule);
JSONObject expr = root.getJSONObject("expr");
if (expr != null) {
capacity = FormulaEvalUtils.evalExpr(expr, varListMap);
}
} }
if (capacity == null) {
return;
}
tDengineService.insertDeviceCapacityRecord(device.getId(), capacity.doubleValue());
} }
private DevicePointRulesDO getDevicePointRules(Long deviceId) { private DevicePointRulesDO getDevicePointRules(Long deviceId) {
List<DevicePointRulesDO> list = List<DevicePointRulesDO> list =

@ -0,0 +1,96 @@
package cn.iocoder.yudao.module.iot.framework.util;
// FormulaEvalUtils
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;
public class FormulaEvalUtils {
private FormulaEvalUtils() {}
public static BigDecimal evalExpr(JSONObject node, Map<String, Object> vars) {
if (node == null) return BigDecimal.ZERO;
if (node.containsKey("field")) {
Object value = vars.get(node.getString("field"));
return toBigDecimal(value);
}
if (node.containsKey("value")) {
return toBigDecimal(node.get("value"));
}
String op = node.getString("op");
BigDecimal left = evalExpr(node.getJSONObject("left"), vars);
BigDecimal right = evalExpr(node.getJSONObject("right"), vars);
return apply(left, right, op);
}
//
public static BigDecimal evalStepArrayByCode(JSONArray steps, Map<String, Object> vars) {
if (steps == null || steps.isEmpty()) {
return BigDecimal.ZERO;
}
BigDecimal result = null;
String pendingBigOp = null; // 上一步的 bigOperator
for (int i = 0; i < steps.size(); i++) {
JSONObject step = steps.getJSONObject(i);
if (step == null) continue;
String code = step.getString("code");
String operator = step.getString("operator");
Object valueObj = step.get("value");
BigDecimal codeValue = readCodeValue(code, vars);
BigDecimal value = toBigDecimal(valueObj);
BigDecimal current = apply(codeValue, value, operator); // A/B/C
if (result == null) {
result = current;
} else {
result = apply(result, current, pendingBigOp); // 用上一项的 bigOperator
}
pendingBigOp = step.getString("bigOperator"); // 留给下一轮使用
}
return result == null ? BigDecimal.ZERO : result;
}
private static BigDecimal readCodeValue(String code, Map<String, Object> vars) {
if (StringUtils.isBlank(code) || vars == null) {
return BigDecimal.ZERO;
}
return toBigDecimal(vars.get(code));
}
private static BigDecimal toBigDecimal(Object raw) {
if (raw == null || StringUtils.isBlank(String.valueOf(raw))) {
return BigDecimal.ZERO;
}
return new BigDecimal(String.valueOf(raw));
}
private static BigDecimal apply(BigDecimal left, BigDecimal right, String op) {
if (StringUtils.isBlank(op)) {
return left;
}
switch (op) {
case "+": return left.add(right);
case "-": return left.subtract(right);
case "*": return left.multiply(right);
case "/":
if (right.compareTo(BigDecimal.ZERO) == 0) return BigDecimal.ZERO;
return left.divide(right, 6, RoundingMode.HALF_UP);
default: throw new IllegalArgumentException("Unsupported op: " + op);
}
}
}

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.iot.service.device; package cn.iocoder.yudao.module.iot.service.device;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.DeviceConnectionStatusEnum; import cn.iocoder.yudao.framework.common.enums.DeviceConnectionStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
@ -144,6 +145,9 @@ public class DeviceServiceImpl implements DeviceService {
throw exception(DEVICE_CODE_ALREADY_EXISTS); throw exception(DEVICE_CODE_ALREADY_EXISTS);
} }
if (StrUtil.isNotBlank(createReqVO.getDeviceCode())) {
tdengineService.validateTableName(createReqVO.getDeviceCode());
}
DeviceModelDO deviceModelDO = deviceModelMapper.selectById(createReqVO.getDeviceModelId()); DeviceModelDO deviceModelDO = deviceModelMapper.selectById(createReqVO.getDeviceModelId());
@ -152,38 +156,46 @@ public class DeviceServiceImpl implements DeviceService {
device.setProtocol(deviceModelDO != null ? deviceModelDO.getProtocol() : ""); device.setProtocol(deviceModelDO != null ? deviceModelDO.getProtocol() : "");
//租户ID //租户ID
device.setTenantId("1"); device.setTenantId("1");
device.setProtocol(StringUtils.isBlank(device.getProtocol()) || device.getProtocol() == null ? "MQTT":device.getProtocol());
deviceMapper.insert(device); deviceMapper.insert(device);
//新增点位规则模板
insertTemplatePoint(createReqVO, device);
return device;
}
private void insertTemplatePoint(DeviceSaveReqVO createReqVO, DeviceDO device) {
//新增模板点位 //新增模板点位
LambdaQueryWrapper<DeviceModelAttributeDO> lambdaQueryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<DeviceModelAttributeDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(DeviceModelAttributeDO::getDeviceModelId,createReqVO.getDeviceModelId()).orderByDesc(DeviceModelAttributeDO::getId); lambdaQueryWrapper.eq(DeviceModelAttributeDO::getDeviceModelId, createReqVO.getDeviceModelId()).orderByDesc(DeviceModelAttributeDO::getId);
List<DeviceModelAttributeDO> deviceModelAttributeDOS = deviceModelAttributeMapper.selectList(lambdaQueryWrapper); List<DeviceModelAttributeDO> deviceModelAttributeDOS = deviceModelAttributeMapper.selectList(lambdaQueryWrapper);
if (deviceModelAttributeDOS.isEmpty()){
throw exception(DEVICE_MODEL_ATTRIBUTE_NOT_EXISTS);
}
List<DeviceContactModelDO> contactModelList = new ArrayList<>(); List<DeviceContactModelDO> contactModelList = new ArrayList<>();
for (DeviceModelAttributeDO attributeDO : deviceModelAttributeDOS) { if (!deviceModelAttributeDOS.isEmpty()) {
DeviceContactModelDO contactModel = new DeviceContactModelDO(); for (DeviceModelAttributeDO attributeDO : deviceModelAttributeDOS) {
BeanUtils.copyProperties(attributeDO, contactModel); DeviceContactModelDO contactModel = new DeviceContactModelDO();
contactModel.setId(null); BeanUtils.copyProperties(attributeDO, contactModel);
contactModel.setDeviceId(device.getId()); contactModel.setId(null);
contactModel.setCreateTime(LocalDateTime.now()); contactModel.setDeviceId(device.getId());
contactModel.setUpdateTime(LocalDateTime.now()); contactModel.setCreateTime(LocalDateTime.now());
contactModelList.add(contactModel); contactModel.setUpdateTime(LocalDateTime.now());
contactModelList.add(contactModel);
}
deviceContactModelMapper.insertBatch(contactModelList);
} }
deviceContactModelMapper.insertBatch(contactModelList);
//创建时序数据库 //创建时序数据库
// createTDengine(device.getId()); // createTDengine(device.getId());
//新增规则点位 //新增规则点位
addNewRulePoints(createReqVO.getDeviceModelId(),device.getId()); addNewRulePoints(createReqVO.getDeviceModelId(), device.getId());
tdengineService.createTdengineTable(device.getId(),contactModelList); tdengineService.createTdengineTable(device.getId(), contactModelList);
return device;
} }
private void addNewRulePoints(Long deviceModelId,Long deviceId) { private void addNewRulePoints(Long deviceModelId,Long deviceId) {
@ -191,6 +203,13 @@ public class DeviceServiceImpl implements DeviceService {
List<DevicePointRulesDO> devicePointRulesDOList = new ArrayList<>(); List<DevicePointRulesDO> devicePointRulesDOList = new ArrayList<>();
DeviceModelDO deviceModelDO = deviceModelMapper.selectById(deviceModelId); DeviceModelDO deviceModelDO = deviceModelMapper.selectById(deviceModelId);
if(deviceModelDO == null){ if(deviceModelDO == null){
DevicePointRulesDO devicePointRulesDO = new DevicePointRulesDO();
devicePointRulesDO.setIdentifier("RUNNING");
devicePointRulesDO.setFieldName("运行");
devicePointRulesDO.setDefaultValue("运行");
devicePointRulesDO.setDeviceId(deviceId);
devicePointRulesDOList.add(devicePointRulesDO);
devicePointRulesMapper.insert(devicePointRulesDO);
return; return;
} }
List<DeviceModelRulesDO> deviceModelRulesDOList = deviceModelRulesMapper.selectList(Wrappers.<DeviceModelRulesDO>lambdaQuery() List<DeviceModelRulesDO> deviceModelRulesDOList = deviceModelRulesMapper.selectList(Wrappers.<DeviceModelRulesDO>lambdaQuery()

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.iot.service.device; package cn.iocoder.yudao.module.iot.service.device;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.DeviceEdgeData; import cn.iocoder.yudao.framework.common.pojo.DeviceEdgeData;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.iot.controller.admin.device.enums.JavaToTdengineTypeEnum; import cn.iocoder.yudao.module.iot.controller.admin.device.enums.JavaToTdengineTypeEnum;
@ -38,8 +39,7 @@ import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.COLOUMN_CREATION_FAILED; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.TABLE_CREATION_FAILED;
@Service @Service
@Slf4j @Slf4j
@ -751,11 +751,9 @@ public class TDengineService {
// 1. 数据库名 // 1. 数据库名
String dbName = "besure_server"; String dbName = "besure_server";
// 2. 表名
String tableName = "d_" + deviceId; String tableName = "d_" + deviceId;
// 3. 确保数据库存在 // 2. 确保数据库存在
try { try {
String createDbSql = "CREATE DATABASE IF NOT EXISTS " + dbName; String createDbSql = "CREATE DATABASE IF NOT EXISTS " + dbName;
jdbcTemplate.execute(createDbSql); jdbcTemplate.execute(createDbSql);
@ -765,40 +763,50 @@ public class TDengineService {
throw exception(TABLE_CREATION_FAILED); throw exception(TABLE_CREATION_FAILED);
} }
// 4. 构建列SQLTDengine必须有 ts // 3. 构建列SQL
StringBuilder columnsSql = new StringBuilder("ts TIMESTAMP"); StringBuilder columnsSql = new StringBuilder("ts TIMESTAMP");
// 5. 遍历 contactModelList 构建列 // 4. 生成唯一列名
String uniqueColName = "val_" + deviceId + "_" + System.currentTimeMillis();
// 5. 如果 contactModelList 不为空,添加对应列
if (contactModelList != null && !contactModelList.isEmpty()) { if (contactModelList != null && !contactModelList.isEmpty()) {
for (DeviceContactModelDO contact : contactModelList) { for (DeviceContactModelDO contact : contactModelList) {
String attributeCode = contact.getAttributeCode(); String attributeCode = contact.getAttributeCode();
String dataType = contact.getDataType(); String dataType = contact.getDataType();
if (attributeCode == null || dataType == null) { if (StrUtil.isBlank(attributeCode) || StrUtil.isBlank(dataType)) {
continue; continue;
} }
// 使用枚举获取 TDengine 类型
String tdType = JavaToTdengineTypeEnum.getTdTypeByJavaType(dataType); String tdType = JavaToTdengineTypeEnum.getTdTypeByJavaType(dataType);
if (tdType == null) { if (tdType == null) {
tdType = "DOUBLE"; // 默认使用 DOUBLE tdType = "DOUBLE";
} }
// 拼接列
columnsSql.append(", ").append(attributeCode).append(" ").append(tdType); columnsSql.append(", ").append(attributeCode).append(" ").append(tdType);
} }
// 确保至少有一个数据列
if (columnsSql.toString().equals("ts TIMESTAMP")) {
columnsSql.append(", ").append(uniqueColName).append(" DOUBLE"); // 使用唯一列名
}
} else {
// 6. contactModelList 为空时,添加默认数据列
columnsSql.append(", ").append(uniqueColName).append(" DOUBLE"); // 使用唯一列名
} }
// 6. 构建完整 SQL // 7. 构建完整 SQL
String createTableSql = "CREATE TABLE IF NOT EXISTS " + dbName + "." + tableName + " (" String fullTableName = dbName + "." + tableName;
+ columnsSql.toString() + ")"; String createTableSql = "CREATE TABLE IF NOT EXISTS " + fullTableName +
" (" + columnsSql.toString() + ")";
// 7. 执行创建表 // 8. 执行创建表
try { try {
jdbcTemplate.execute(createTableSql); jdbcTemplate.execute(createTableSql);
log.info("TDengine 表创建成功: {}.{}", dbName, tableName); log.info("TDengine 表创建成功: {}", fullTableName);
} catch (Exception e) { } catch (Exception e) {
log.error("TDengine 表创建失败: {}.{}", dbName, tableName, e); log.error("TDengine 表创建失败: {}", fullTableName, e);
throw exception(TABLE_CREATION_FAILED); throw exception(TABLE_CREATION_FAILED);
} }
} }
@ -854,6 +862,8 @@ public class TDengineService {
} }
} }
/** /**
* *
* @param deviceId * @param deviceId
@ -976,6 +986,331 @@ public class TDengineService {
} }
/**
* TDengine
* @param deviceId ID
* @param oldColumnName
* @param newColumnName
*/
@DS("tdengine")
public void renameTDColumn(Long deviceId, String oldColumnName, String newColumnName) {
if (deviceId == null || StrUtil.isBlank(oldColumnName) || StrUtil.isBlank(newColumnName)) {
log.warn("修改列名参数错误: deviceId={}, oldColumnName={}, newColumnName={}",
deviceId, oldColumnName, newColumnName);
return;
}
// 1. 验证原列是否存在
if (!columnExists(deviceId, oldColumnName)) {
log.warn("原列不存在,无法修改: deviceId={}, column={}", deviceId, oldColumnName);
throw exception(COLUMN_RENAME_FAILED, "原列 '" + oldColumnName + "' 不存在");
}
// 2. 验证新列名是否已存在
if (columnExists(deviceId, newColumnName)) {
log.warn("新列名已存在: deviceId={}, column={}", deviceId, newColumnName);
throw exception(COLUMN_RENAME_FAILED, "新列名 '" + newColumnName + "' 已存在");
}
// 3. 验证新列名是否为保留关键字
if (isReservedKeyword(newColumnName)) {
log.warn("新列名是保留关键字: {}", newColumnName);
throw exception(COLUMN_RENAME_FAILED, "新列名 '" + newColumnName + "' 是保留关键字");
}
// 表名
String tableName = "besure_server.d_" + deviceId;
// ALTER TABLE RENAME COLUMN SQL
String alterSql = "ALTER TABLE " + tableName
+ " RENAME COLUMN " + oldColumnName + " " + newColumnName;
try {
jdbcTemplate.execute(alterSql);
log.info("TDengine 表修改列名成功: table={}, oldColumn={}, newColumn={}",
tableName, oldColumnName, newColumnName);
} catch (Exception e) {
// 处理特定错误
String errorMsg = e.getMessage();
if (errorMsg != null) {
if (errorMsg.contains("column not exist") || errorMsg.contains("column does not exist")) {
log.warn("原列不存在,无法修改: table={}, column={}", tableName, oldColumnName);
}
if (errorMsg.contains("duplicate column") || errorMsg.contains("column already exists")) {
log.warn("新列名已存在: table={}, newColumn={}", tableName, newColumnName);
}
if (errorMsg.contains("reserved keyword") || errorMsg.toLowerCase().contains("syntax")) {
log.warn("新列名包含保留关键字: {}", newColumnName);
}
}
log.error("TDengine 表修改列名失败: table={}, oldColumn={}, newColumn={}",
tableName, oldColumnName, newColumnName, e);
throw exception(COLUMN_RENAME_FAILED);
}
}
/**
* 线-
*/
@DS("tdengine")
public synchronized int calculateSequence(Long deviceId, String originalName, String date) {
log.info("=== 开始计算序号 ===");
log.info("参数: deviceId={}, originalName={}, date={}", deviceId, originalName, date);
String tableName = "besure_server.d_" + deviceId;
log.info("表名: {}", tableName);
try {
// 检查表是否存在
boolean exists = tableExists(deviceId);
log.info("表是否存在: {}", exists);
if (!exists) {
log.info("表不存在,返回 1");
return 1;
}
// 查询所有列
String sql = "DESC " + tableName;
log.info("执行SQL: {}", sql);
List<Map<String, Object>> columns = jdbcTemplate.queryForList(sql);
log.info("查询到 {} 列", columns.size());
// 打印所有列
for (int i = 0; i < columns.size(); i++) {
Map<String, Object> column = columns.get(i);
String colName = (String) column.get("Field");
String colType = (String) column.get("Type");
log.info("列[{}]: {} ({})", i, colName, colType);
}
int maxSequence = 0;
String prefix = "del_" + originalName + "_" + date + "_";
log.info("查找前缀: {}", prefix);
log.info("前缀长度: {}", prefix.length());
for (Map<String, Object> column : columns) {
String colName = (String) column.get("Field");
log.info("检查列: {}", colName);
if (colName != null) {
log.info("列长度: {}, 是否以前缀开头: {}",
colName.length(), colName.startsWith(prefix));
if (colName.startsWith(prefix)) {
String seqStr = colName.substring(prefix.length());
log.info("匹配成功! 提取序号字符串: '{}'", seqStr);
try {
int seq = Integer.parseInt(seqStr);
log.info("转换为数字: {}", seq);
if (seq > maxSequence) {
maxSequence = seq;
log.info("更新最大序号为: {}", maxSequence);
}
} catch (NumberFormatException e) {
log.warn("序号不是数字: '{}'", seqStr);
}
}
}
}
int result = maxSequence + 1;
log.info("最终结果: {} + 1 = {}", maxSequence, result);
log.info("=== 计算序号结束 ===");
return result;
} catch (Exception e) {
log.error("计算历史列序号失败返回1", e);
return 1;
}
}
/**
*
*/
@DS("tdengine")
private boolean tableExists(Long deviceId) {
String tableName = "besure_server.d_" + deviceId;
try {
// 方法1直接尝试查询
String sql = "SELECT 1 FROM " + tableName + " LIMIT 0";
jdbcTemplate.execute(sql);
return true;
} catch (Exception e) {
// 如果错误包含"table not exist",说明表不存在
String errorMsg = e.getMessage();
if (errorMsg != null && (
errorMsg.contains("table not exist") ||
errorMsg.contains("table does not exist") ||
errorMsg.contains("unknown table") ||
errorMsg.contains("Table not found"))) {
return false;
}
// 其他错误,可能是权限问题等
log.warn("检查表是否存在时出错: table={}, error={}", tableName, errorMsg);
return false;
}
}
/**
*
*/
@DS("tdengine")
private boolean columnExists(Long deviceId, String columnName) {
if (deviceId == null || StrUtil.isBlank(columnName)) {
return false;
}
String tableName = "besure_server.d_" + deviceId;
try {
// 方法1直接尝试查询该列
String testSql = "SELECT " + columnName + " FROM " + tableName + " LIMIT 0";
jdbcTemplate.execute(testSql);
return true; // 执行成功,说明列存在
} catch (Exception e) {
String errorMsg = e.getMessage();
// 判断是否是"列不存在"的错误
if (errorMsg != null && (
errorMsg.contains("column not exist") ||
errorMsg.contains("column does not exist") ||
errorMsg.contains("Invalid column") ||
errorMsg.contains("column not found") ||
errorMsg.contains("unknown column"))) {
return false; // 列不存在
}
// 其他错误(如表不存在),记录日志
log.warn("检查列是否存在时发生未知错误: table={}, column={}, error={}",
tableName, columnName, errorMsg);
return false;
}
}
/**
*
*/
private boolean isReservedKeyword(String columnName) {
Set<String> reservedWords = new HashSet<>(Arrays.asList(
"value", "timestamp", "current", "database", "table",
"user", "password", "select", "insert", "update", "delete",
"create", "drop", "alter", "show", "describe", "use", "ts"
));
return reservedWords.contains(columnName.toLowerCase());
}
/**
* TDengine
*/
public void validateColumnName(String columnName) {
if (StrUtil.isBlank(columnName)) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS, "列名不能为空");
}
// TDengine 列名规则验证
// 1. 不能是保留关键字
Set<String> reservedKeywords = new HashSet<>(Arrays.asList(
"value", "timestamp", "current", "database", "table", "user", "password",
"select", "insert", "update", "delete", "create", "drop", "alter",
"show", "describe", "use", "ts", "now", "current_timestamp"
));
if (reservedKeywords.contains(columnName.toLowerCase())) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS,
"列名不能使用保留关键字: " + columnName);
}
// 2. 必须以字母开头
if (!Character.isLetter(columnName.charAt(0))) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS,
"列名必须以字母开头: " + columnName);
}
// 3. 只能包含字母、数字、下划线
if (!columnName.matches("^[a-zA-Z_][a-zA-Z0-9_]*$")) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS,
"列名只能包含字母、数字和下划线: " + columnName);
}
// 4. 长度限制根据TDengine文档
if (columnName.length() > 64) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS,
"列名长度不能超过64个字符: " + columnName);
}
// 5. 不能以下划线开头(虽然不是强制,但避免潜在问题)
if (columnName.startsWith("_")) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS,
"列名不能以下划线开头: " + columnName);
}
}
/**
* TDengine
*/
public void validateTableName(String tableName) {
if (StrUtil.isBlank(tableName)) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS, "表名不能为空");
}
// TDengine 表名规则验证
// 1. 不能是保留关键字
Set<String> reservedKeywords = new HashSet<>(Arrays.asList(
"value", "timestamp", "current", "database", "table", "user", "password",
"select", "insert", "update", "delete", "create", "drop", "alter",
"show", "describe", "use", "ts", "now", "current_timestamp"
));
if (reservedKeywords.contains(tableName.toLowerCase())) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS,
"表名不能使用保留关键字: " + tableName);
}
// 2. 必须以字母开头
if (!Character.isLetter(tableName.charAt(0))) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS,
"表名必须以字母开头: " + tableName);
}
// 3. 只能包含字母、数字、下划线
if (!tableName.matches("^[a-zA-Z][a-zA-Z0-9_]*$")) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS,
"表名只能包含字母、数字和下划线: " + tableName);
}
// 4. 长度限制TDengine表名最大长度通常为192
if (tableName.length() > 192) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS,
"表名长度不能超过192个字符: " + tableName);
}
// 5. 不能以下划线开头(与列名策略保持一致)
if (tableName.startsWith("_")) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS,
"表名不能以下划线开头: " + tableName);
}
}
/** /**
* deviceId * deviceId
* @param deviceIds * @param deviceIds
@ -2181,4 +2516,23 @@ public class TDengineService {
return record; return record;
} }
}
// ========================= 产能相关接口 ===================
@DS("tdengine")
public boolean insertDeviceCapacityRecord(Long deviceId, Double capacityValue) {
if (deviceId == null || capacityValue == null) {
return false;
}
try {
String sql = "INSERT INTO iot_device_capacity_record (ts, capacity_value, device_id) VALUES (NOW, "
+ capacityValue + ", " + deviceId + ")";
jdbcTemplate.execute(sql);
return true;
} catch (Exception e) {
log.error("insertDeviceCapacityRecord failed, deviceId={}, capacityValue={}", deviceId, capacityValue, e);
return false;
}
}
}

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.iot.service.devicecontactmodel; package cn.iocoder.yudao.module.iot.service.devicecontactmodel;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.iot.dal.dataobject.devicecontactmodel.DeviceContactModelDO; import cn.iocoder.yudao.module.iot.dal.dataobject.devicecontactmodel.DeviceContactModelDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.devicemodelattribute.DeviceModelAttributeDO; import cn.iocoder.yudao.module.iot.dal.dataobject.devicemodelattribute.DeviceModelAttributeDO;
import cn.iocoder.yudao.module.iot.dal.mysql.deviceattributetype.DeviceAttributeTypeMapper; import cn.iocoder.yudao.module.iot.dal.mysql.deviceattributetype.DeviceAttributeTypeMapper;
@ -7,6 +8,8 @@ import cn.iocoder.yudao.module.iot.service.device.TDengineService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.constraints.NotEmpty;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.module.iot.controller.admin.devicecontactmodel.vo.*; import cn.iocoder.yudao.module.iot.controller.admin.devicecontactmodel.vo.*;
@ -15,7 +18,10 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.iot.dal.mysql.devicecontactmodel.DeviceContactModelMapper; import cn.iocoder.yudao.module.iot.dal.mysql.devicecontactmodel.DeviceContactModelMapper;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.DEVICE_CONTACT_MODEL_NOT_EXISTS; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.DEVICE_CONTACT_MODEL_NOT_EXISTS;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -52,6 +58,11 @@ public class DeviceContactModelServiceImpl implements DeviceContactModelService
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS); throw exception(DEVICE_MODEL_POINT_CODE_EXISTS);
} }
// 2. 检查attributeCode是否符合TDengine列名规则
if (StrUtil.isNotBlank(createReqVO.getAttributeCode())) {
tDengineService.validateColumnName(createReqVO.getAttributeCode());
}
// 插入 // 插入
DeviceContactModelDO deviceContactModel = BeanUtils.toBean(createReqVO, DeviceContactModelDO.class); DeviceContactModelDO deviceContactModel = BeanUtils.toBean(createReqVO, DeviceContactModelDO.class);
// deviceContactModel.setTypeName(deviceAttributeTypeMapper.selectById(createReqVO.getAttributeCode()).getName()); // deviceContactModel.setTypeName(deviceAttributeTypeMapper.selectById(createReqVO.getAttributeCode()).getName());
@ -78,11 +89,45 @@ public class DeviceContactModelServiceImpl implements DeviceContactModelService
for (Long id : ids) { for (Long id : ids) {
// 校验存在 // 校验存在
validateDeviceContactModelExists(id); validateDeviceContactModelExists(id);
DeviceContactModelDO deviceContactModelDO = deviceContactModelMapper.selectById(id);
if (deviceContactModelDO == null) {
continue;
}
Long deviceId = deviceContactModelDO.getDeviceId();
String oldColumnName = deviceContactModelDO.getAttributeCode();
if (deviceId != null && StrUtil.isNotBlank(oldColumnName)) {
// 生成带序号的历史列名
String newColumnName = generateHistoryColumnName(deviceId, oldColumnName);
// 重命名列
tDengineService.renameTDColumn(deviceId, oldColumnName, newColumnName);
}
// 删除 // 删除
deviceContactModelMapper.deleteById(id); deviceContactModelMapper.deleteById(id);
} }
} }
/**
*
* : DEL_{}_{}_{}
* : DEL_temperature_20260327_1
*/
private String generateHistoryColumnName(Long deviceId, String originalName) {
String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
// 获取当前序号
int sequence = tDengineService.calculateSequence(deviceId, originalName, date);
return String.format("DEL_%s_%s_%d", originalName, date, sequence);
}
private void validateDeviceContactModelExists(Long id) { private void validateDeviceContactModelExists(Long id) {
if (deviceContactModelMapper.selectById(id) == null) { if (deviceContactModelMapper.selectById(id) == null) {
throw exception(DEVICE_CONTACT_MODEL_NOT_EXISTS); throw exception(DEVICE_CONTACT_MODEL_NOT_EXISTS);

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.iot.service.devicemodelattribute; package cn.iocoder.yudao.module.iot.service.devicemodelattribute;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
@ -68,6 +69,10 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
@Resource @Resource
private ErpProductUnitService productUnitService; private ErpProductUnitService productUnitService;
@Resource
@Lazy
private TDengineService tDengineService;
@Override @Override
public Long createDeviceModelAttribute(DeviceModelAttributeSaveReqVO createReqVO) { public Long createDeviceModelAttribute(DeviceModelAttributeSaveReqVO createReqVO) {
@ -82,9 +87,15 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
throw exception(DEVICE_MODEL_ATTRIBUTE_POTIN_CODE_EXISTS); throw exception(DEVICE_MODEL_ATTRIBUTE_POTIN_CODE_EXISTS);
} }
// 插入 // 插入
DeviceModelAttributeDO deviceModelAttribute = BeanUtils.toBean(createReqVO, DeviceModelAttributeDO.class); DeviceModelAttributeDO deviceModelAttribute = BeanUtils.toBean(createReqVO, DeviceModelAttributeDO.class);
// deviceModelAttribute.setTypeName(deviceAttributeTypeMapper.selectById(createReqVO.getAttributeCode()).getName()); // deviceModelAttribute.setTypeName(deviceAttributeTypeMapper.selectById(createReqVO.getAttributeCode()).getName());
//检查attributeCode是否符合TDengine列名规则
if (StrUtil.isNotBlank(createReqVO.getAttributeCode())) {
tDengineService.validateColumnName(createReqVO.getAttributeCode());
}
deviceModelAttributeMapper.insert(deviceModelAttribute); deviceModelAttributeMapper.insert(deviceModelAttribute);
// 返回 // 返回
return deviceModelAttribute.getId(); return deviceModelAttribute.getId();
@ -295,7 +306,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
// 不能为空 // 不能为空
if (StringUtils.isBlank(code)) { if (StringUtils.isBlank(code)) {
respVO.getFailureCodes().put(importAttribute.getAttributeCode(), "点位类型名称不能为空"); respVO.getFailureCodes().put(importAttribute.getAttributeCode(), "点位类型编码不能为空");
return; return;
} }
// 必须存在于数据库类型列表中(防止乱填) // 必须存在于数据库类型列表中(防止乱填)

@ -46,11 +46,11 @@ public class DevicePointRulesServiceImpl implements DevicePointRulesService {
validateDevicePointRulesExists(updateReqVO.getId()); validateDevicePointRulesExists(updateReqVO.getId());
// 更新 // 更新
DevicePointRulesDO updateObj = BeanUtils.toBean(updateReqVO, DevicePointRulesDO.class); DevicePointRulesDO updateObj = BeanUtils.toBean(updateReqVO, DevicePointRulesDO.class);
if (!updateReqVO.getPointRulesVOList().isEmpty()){ // if (!updateReqVO.getPointRulesVOList().isEmpty()){
String jsonString = JSON.toJSONString(updateReqVO.getPointRulesVOList()); // String jsonString = JSON.toJSONString(updateReqVO.getPointRulesVOList());
updateObj.setFieldRule(jsonString); // updateObj.setFieldRule(jsonString);
//
} // }
devicePointRulesMapper.updateById(updateObj); devicePointRulesMapper.updateById(updateObj);
} }

@ -144,14 +144,17 @@ public interface ErrorCodeConstants {
ErrorCode DEVICE_LEDGER_EXISTS = new ErrorCode(1002000010, "设备台账编码已存在"); ErrorCode DEVICE_LEDGER_EXISTS = new ErrorCode(1002000010, "设备台账编码已存在");
ErrorCode SUBJECT_EXISTS = new ErrorCode(1002000010, "项目编码已存在"); ErrorCode SUBJECT_EXISTS = new ErrorCode(1002000010, "项目编码已存在");
ErrorCode TASK_MANAGEMENT_NOT_EXISTS = new ErrorCode(1002000011, "设备类型不存在"); ErrorCode TASK_MANAGEMENT_NOT_EXISTS = new ErrorCode(1002000011, "设备类型不存在");
ErrorCode TASK_CORN_NOT_EXISTS = new ErrorCode(1002000011, "设备corn表达式为空"); ErrorCode TASK_CORN_NOT_EXISTS = new ErrorCode(1002000012, "设备corn表达式为空");
ErrorCode TASK_CORN_NOT_LE_HOUR = new ErrorCode(1002000011, "corn表达式不能小于一小时"); ErrorCode TASK_CORN_NOT_LE_HOUR = new ErrorCode(1002000013, "corn表达式不能小于一小时");
ErrorCode DEVICE_LEDGER_CODE_NOT_EXISTS = new ErrorCode(1002000013, "设备台账编码不存在");
ErrorCode TICKET_MANAGEMENT_NOT_EXISTS = new ErrorCode(1002000012, "工单管理不存在"); ErrorCode TICKET_MANAGEMENT_NOT_EXISTS = new ErrorCode(1002000012, "工单管理不存在");
ErrorCode TICKET_RESULTS_NOT_EXISTS = new ErrorCode(1002000013, "工单检验结果不存在"); ErrorCode TICKET_RESULTS_NOT_EXISTS = new ErrorCode(1002000013, "工单检验结果不存在");
ErrorCode TICKET_RESULTS_ID_NOT_NULL = new ErrorCode(1002000014, "工单检验结果Id不存在"); ErrorCode TICKET_RESULTS_ID_NOT_NULL = new ErrorCode(1002000014, "工单检验结果Id不存在");
ErrorCode CRITICAL_COMPONENT_NOT_EXISTS = new ErrorCode(1002000015, "设备关键件不存在"); ErrorCode CRITICAL_COMPONENT_NOT_EXISTS = new ErrorCode(1002000015, "设备关键件不存在");
ErrorCode CRITICAL_COMPONENT_CODE_EXISTS = new ErrorCode(1002000015, "设备关键件编码已存在"); ErrorCode CRITICAL_COMPONENT_CODE_EXISTS = new ErrorCode(1002000015, "设备关键件编码已存在");
ErrorCode CRITICAL_COMPONENT_CODE_NOT_EXISTS = new ErrorCode(1002000015, "设备关键件编码不存在");
ErrorCode CRITICAL_COMPONENT_REFERENCES= new ErrorCode(1002000015, "存在设备关键件已被引用,请先删除引用"); ErrorCode CRITICAL_COMPONENT_REFERENCES= new ErrorCode(1002000015, "存在设备关键件已被引用,请先删除引用");

@ -11,6 +11,7 @@ import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*; import javax.validation.constraints.*;
import javax.validation.*; import javax.validation.*;
import javax.servlet.http.*; import javax.servlet.http.*;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -48,7 +49,7 @@ public class CriticalComponentController {
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建设备关键件") @Operation(summary = "创建设备关键件")
@PreAuthorize("@ss.hasPermission('mes:critical-component:create')") @PreAuthorize("@ss.hasPermission('mes:critical-component:create')")
public CommonResult<Long> createCriticalComponent(@Valid @RequestBody CriticalComponentSaveReqVO createReqVO) { public CommonResult<Long> createCriticalComponent(@Valid @RequestBody CriticalComponentSaveReqVO createReqVO) throws UnsupportedEncodingException {
return success(criticalComponentService.createCriticalComponent(createReqVO)); return success(criticalComponentService.createCriticalComponent(createReqVO));
} }
@ -170,4 +171,12 @@ public class CriticalComponentController {
return success(criticalComponentService.importCriticalComponentList(list, updateSupport)); return success(criticalComponentService.importCriticalComponentList(list, updateSupport));
} }
@PostMapping("/regenerate-code")
public CommonResult<Boolean> regenerateCode(@RequestParam("id") Long id,
@RequestParam("code") String code) throws UnsupportedEncodingException {
criticalComponentService.regenerateCode(id, code);
return success(true);
}
} }

@ -28,6 +28,10 @@ public class CriticalComponentExcelVO {
@ExcelProperty("名称") @ExcelProperty("名称")
private String name; private String name;
@Schema(description = "规格型号", example = "")
@ExcelProperty("规格型号")
private String deviceSpec;
@Schema(description = "描述") @Schema(description = "描述")
@ExcelProperty("描述") @ExcelProperty("描述")
private String description; private String description;

@ -27,6 +27,10 @@ public class CriticalComponentImportExcelVO {
@ExcelProperty("名称") @ExcelProperty("名称")
private String name; private String name;
@Schema(description = "规格型号", example = "")
@ExcelProperty("规格型号")
private String deviceSpec;
@ExcelProperty("描述") @ExcelProperty("描述")
private String description; private String description;

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.mes.controller.admin.criticalcomponent.vo; package cn.iocoder.yudao.module.mes.controller.admin.criticalcomponent.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.*; import lombok.*;
import java.util.*; import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
@ -21,6 +22,9 @@ public class CriticalComponentPageReqVO extends PageParam {
@Schema(description = "名称", example = "张三") @Schema(description = "名称", example = "张三")
private String name; private String name;
@Schema(description = "规格型号", example = "")
private String deviceSpec;
@Schema(description = "描述", example = "你说的对") @Schema(description = "描述", example = "你说的对")
private String description; private String description;

@ -25,6 +25,10 @@ public class CriticalComponentRespVO {
@ExcelProperty("名称") @ExcelProperty("名称")
private String name; private String name;
@Schema(description = "规格型号", example = "")
@ExcelProperty("规格型号")
private String deviceSpec;
@Schema(description = "描述", example = "你说的对") @Schema(description = "描述", example = "你说的对")
@ExcelProperty("描述") @ExcelProperty("描述")
private String description; private String description;
@ -41,4 +45,7 @@ public class CriticalComponentRespVO {
@Schema(description = "数量", example = "2") @Schema(description = "数量", example = "2")
private Integer count; private Integer count;
@Schema(description = "二维码", example = "2")
private String qrcodeUrl;
} }

@ -13,13 +13,16 @@ public class CriticalComponentSaveReqVO {
private Long id; private Long id;
@Schema(description = "编码(唯一标识)", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "编码(唯一标识)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "编码(唯一标识)不能为空") // @NotEmpty(message = "编码(唯一标识)不能为空")
private String code; private String code;
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
@NotEmpty(message = "名称不能为空") @NotEmpty(message = "名称不能为空")
private String name; private String name;
@Schema(description = "规格型号", example = "")
private String deviceSpec;
@Schema(description = "描述", example = "你说的对") @Schema(description = "描述", example = "你说的对")
private String description; private String description;

@ -497,7 +497,7 @@ public class DashboardController {
@GetMapping("/getTaskStatistics") @GetMapping("/getTaskStatistics")
@Operation(summary = "获得各设备统计个数") @Operation(summary = "获得各设备统计个数")
@Parameter(name = "orgId", description = "产线组织Id") @Parameter(name = "orgId", description = "产线组织Id")
@PreAuthorize("@ss.hasPermission('mes:device-ledger:query')") //@PreAuthorize("@ss.hasPermission('mes:device-ledger:query')")
public CommonResult<EventStatisticsVO> getTaskStatistics(@RequestParam(name = "orgId") Long orgId) { public CommonResult<EventStatisticsVO> getTaskStatistics(@RequestParam(name = "orgId") Long orgId) {
EventStatisticsVO vo = new EventStatisticsVO(); EventStatisticsVO vo = new EventStatisticsVO();
@ -559,7 +559,7 @@ public class DashboardController {
@GetMapping("/getAllTaskList") @GetMapping("/getAllTaskList")
@Operation(summary = "获得所有任务") @Operation(summary = "获得所有任务")
@Parameter(name = "orgId", description = "产线组织Id") @Parameter(name = "orgId", description = "产线组织Id")
@PreAuthorize("@ss.hasPermission('mes:bom:query')") //@PreAuthorize("@ss.hasPermission('mes:bom:query')")
public CommonResult<List<TaskVO>> getAllTaskList(@RequestParam(name = "orgId") Long orgId) { public CommonResult<List<TaskVO>> getAllTaskList(@RequestParam(name = "orgId") Long orgId) {
List<TaskVO> taskVOList = new ArrayList<>(); List<TaskVO> taskVOList = new ArrayList<>();

@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.mes.controller.admin.deviceledger;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO; import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO;
import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum;
import cn.iocoder.yudao.module.common.service.qrcordrecord.QrcodeRecordService;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.mes.controller.admin.deviceledger.utils.ResumeNameUtils; import cn.iocoder.yudao.module.mes.controller.admin.deviceledger.utils.ResumeNameUtils;
import cn.iocoder.yudao.module.mes.controller.admin.plan.vo.PlanRespVO; import cn.iocoder.yudao.module.mes.controller.admin.plan.vo.PlanRespVO;
@ -22,6 +24,7 @@ import io.swagger.v3.oas.annotations.Operation;
import javax.validation.*; import javax.validation.*;
import javax.servlet.http.*; import javax.servlet.http.*;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -60,11 +63,14 @@ public class DeviceLedgerController {
@Resource @Resource
private AdminUserApi adminUserApi; private AdminUserApi adminUserApi;
@Resource
private QrcodeRecordService qrcodeService;
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建设备台账") @Operation(summary = "创建设备台账")
@PreAuthorize("@ss.hasPermission('mes:device-ledger:create')") @PreAuthorize("@ss.hasPermission('mes:device-ledger:create')")
public CommonResult<Long> createDeviceLedger(@Valid @RequestBody DeviceLedgerSaveReqVO createReqVO) { public CommonResult<Long> createDeviceLedger(@Valid @RequestBody DeviceLedgerSaveReqVO createReqVO) throws UnsupportedEncodingException {
return success(deviceLedgerService.createDeviceLedger(createReqVO)); return success(deviceLedgerService.createDeviceLedger(createReqVO));
} }
@ -99,6 +105,10 @@ public class DeviceLedgerController {
public CommonResult<DeviceLedgerRespVO> getDeviceLedger(@RequestParam("id") Long id) { public CommonResult<DeviceLedgerRespVO> getDeviceLedger(@RequestParam("id") Long id) {
DeviceLedgerDO deviceLedger = deviceLedgerService.getDeviceLedger(id); DeviceLedgerDO deviceLedger = deviceLedgerService.getDeviceLedger(id);
DeviceLedgerRespVO respVO = BeanUtils.toBean(deviceLedger, DeviceLedgerRespVO.class); DeviceLedgerRespVO respVO = BeanUtils.toBean(deviceLedger, DeviceLedgerRespVO.class);
String qrcodeUrl = qrcodeService.selectQrcodeUrlByIdAndCode(QrcodeBizTypeEnum.EQUIPMENT.getCode(),id,respVO.getDeviceCode());
respVO.setQrcodeUrl(qrcodeUrl);
respVO.setCreatorName(adminUserApi.getUser(Long.valueOf(deviceLedger.getCreator())).getNickname()); respVO.setCreatorName(adminUserApi.getUser(Long.valueOf(deviceLedger.getCreator())).getNickname());
if (StringUtils.isNotBlank(respVO.getDeviceManager())) { if (StringUtils.isNotBlank(respVO.getDeviceManager())) {
String[] userIds = respVO.getDeviceManager().split(","); String[] userIds = respVO.getDeviceManager().split(",");
@ -250,4 +260,19 @@ public class DeviceLedgerController {
// 导出 Excel // 导出 Excel
ExcelUtils.write(response, fileName, "数据", MoldVO.class,list); ExcelUtils.write(response, fileName, "数据", MoldVO.class,list);
} }
@PostMapping("/regenerate-code")
public CommonResult<Boolean> regenerateCode(@RequestParam("id") Long id,
@RequestParam("code") String code) throws UnsupportedEncodingException {
deviceLedgerService.regenerateCode(id, code);
return success(true);
}
} }

@ -17,6 +17,9 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@ToString(callSuper = true) @ToString(callSuper = true)
public class DeviceLedgerPageReqVO extends PageParam { public class DeviceLedgerPageReqVO extends PageParam {
@Schema(description = "设备图片")
private String images;
@Schema(description = "设备编号") @Schema(description = "设备编号")
private String deviceCode; private String deviceCode;

@ -30,6 +30,9 @@ public class DeviceLedgerRespVO extends BaseDO {
// @ExcelProperty("id") // @ExcelProperty("id")
private Long id; private Long id;
@Schema(description = "设备图片")
private String images;
@Schema(description = "设备编号") @Schema(description = "设备编号")
@ExcelProperty("设备编号") @ExcelProperty("设备编号")
private String deviceCode; private String deviceCode;
@ -151,4 +154,13 @@ public class DeviceLedgerRespVO extends BaseDO {
@Schema(description = "关联采集设备id") @Schema(description = "关联采集设备id")
private Long dvId; private Long dvId;
@Schema(description = "二维码")
private String qrcodeUrl;
@Schema(description = "是否排产")
private Integer isScheduled;
@Schema(description = "额定产能")
private Integer ratedCapacity;
} }

@ -13,6 +13,9 @@ public class DeviceLedgerSaveReqVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24467") @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24467")
private Long id; private Long id;
@Schema(description = "设备图片")
private String images;
@Schema(description = "设备编号") @Schema(description = "设备编号")
private String deviceCode; private String deviceCode;
@ -78,4 +81,10 @@ public class DeviceLedgerSaveReqVO {
@Schema(description = "关联采集设备id") @Schema(description = "关联采集设备id")
private Long dvId; private Long dvId;
@Schema(description = "是否排产")
private Integer isScheduled;
@Schema(description = "额定产能")
private Integer ratedCapacity;
} }

@ -167,7 +167,7 @@ public class EnergyDeviceController {
@GetMapping("/lastEnergyStatistics") @GetMapping("/lastEnergyStatistics")
@Operation(summary = "获得近七小时能耗记录") @Operation(summary = "获得近七小时能耗记录")
@PreAuthorize("@ss.hasPermission('mes:energy-device:query')") //@PreAuthorize("@ss.hasPermission('mes:energy-device:query')")
public CommonResult<List<HourEnergyValueVO>> lastEnergyStatistics(@RequestParam("deviceTypeId") Long deviceTypeId, public CommonResult<List<HourEnergyValueVO>> lastEnergyStatistics(@RequestParam("deviceTypeId") Long deviceTypeId,
@RequestParam("orgId") Long orgId) { @RequestParam("orgId") Long orgId) {
@ -178,7 +178,7 @@ public class EnergyDeviceController {
@GetMapping("/latestSevenDaysStatistics") @GetMapping("/latestSevenDaysStatistics")
@Operation(summary = "获得近七天能耗记录") @Operation(summary = "获得近七天能耗记录")
@PreAuthorize("@ss.hasPermission('mes:energy-device:query')") // @PreAuthorize("@ss.hasPermission('mes:energy-device:query')")
public CommonResult<List<DayEnergyValueVO>> latestSevenDaysStatistics( public CommonResult<List<DayEnergyValueVO>> latestSevenDaysStatistics(
@RequestParam Long deviceTypeId, @RequestParam Long deviceTypeId,
@RequestParam Long orgId) { @RequestParam Long orgId) {

@ -114,68 +114,6 @@ public class PlanController {
zjProductRecordService.createZjProductRecord(BeanUtils.toBean(zjProductRecordDO, ZjProductRecordSaveReqVO.class)); zjProductRecordService.createZjProductRecord(BeanUtils.toBean(zjProductRecordDO, ZjProductRecordSaveReqVO.class));
} }
} }
// // 生成领料出库单据
// List<ErpStockOutSaveReqVO.Item> itemList;
//
// // 1 查询最新 BOM
// BomDO bomDO = bomMapper.selectOne(
// Wrappers.<BomDO>lambdaQuery()
// .eq(BomDO::getProductId, createReqVO.getProductId())
// .orderByDesc(BomDO::getCreateTime)
// .last("limit 1")
// );
//
// if (bomDO == null) {
// return success(false);
// }
//
// // 2 查询 BOM 明细
// List<BomDetailDO> bomDetails = bomDetailMapper.selectList(
// Wrappers.<BomDetailDO>lambdaQuery()
// .eq(BomDetailDO::getBomId, bomDO.getId())
// );
//
// if (bomDetails.isEmpty()) {
// return success(false);
// }
//
// // 3 查询仓库
// ErpWarehouseDO warehouse = erpWarehouseMapper.selectOne(
// Wrappers.<ErpWarehouseDO>lambdaQuery()
// .orderByDesc(ErpWarehouseDO::getCreateTime)
// .last("limit 1")
// );
//
// if (warehouse == null) {
// return success(false);
// }
//
// // 4 计算领料数量
// Long planNumber = Optional.ofNullable(createReqVO.getPlanNumber()).orElse(0L);
//
// itemList = bomDetails.stream().map(detail -> {
//
// BigDecimal usageNumber = Optional.ofNullable(detail.getUsageNumber()).orElse(BigDecimal.ZERO);
//
// BigDecimal count = usageNumber.multiply(BigDecimal.valueOf(planNumber));
//
// ErpStockOutSaveReqVO.Item item = new ErpStockOutSaveReqVO.Item();
// item.setProductId(detail.getProductId());
// item.setWarehouseId(warehouse.getId());
// item.setCount(count);
//
// return item;
//
// }).collect(Collectors.toList());
//
// // 5 构造出库单
// ErpStockOutSaveReqVO stockOut = new ErpStockOutSaveReqVO();
// stockOut.setOutType("领料出库");
// stockOut.setOutTime(LocalDateTime.now());
// stockOut.setItems(itemList);
//
// // 6 创建出库单
// erpStockOutService.createStockOut(stockOut);
return success(true); return success(true);
} }
@ -579,7 +517,7 @@ public class PlanController {
@GetMapping("/getLastSevenDaysCompletedCount") @GetMapping("/getLastSevenDaysCompletedCount")
@Operation(summary = "获取过去7天每天完工数量统计") @Operation(summary = "获取过去7天每天完工数量统计")
@PreAuthorize("@ss.hasPermission('mes:plan:query')") //@PreAuthorize("@ss.hasPermission('mes:plan:query')")
@Parameter(name = "orgId", description = "产线组织Id", required = true, example = "1024") @Parameter(name = "orgId", description = "产线组织Id", required = true, example = "1024")
public CommonResult<List<Map<String, Object>>> getLastSevenDaysCompletedCount( @RequestParam(name = "orgId" ,required = false) Long orgId) { public CommonResult<List<Map<String, Object>>> getLastSevenDaysCompletedCount( @RequestParam(name = "orgId" ,required = false) Long orgId) {
List<Map<String, Object>> dayCounts = planService.getLastSevenDaysCompletedCount(); List<Map<String, Object>> dayCounts = planService.getLastSevenDaysCompletedCount();

@ -113,8 +113,8 @@ public class TaskController {
@Operation(summary = "获得生产任务单分页") @Operation(summary = "获得生产任务单分页")
@PreAuthorize("@ss.hasPermission('mes:task:query')") @PreAuthorize("@ss.hasPermission('mes:task:query')")
public CommonResult<PageResult<TaskRespVO>> getTaskPage(@Valid TaskPageReqVO pageReqVO) { public CommonResult<PageResult<TaskRespVO>> getTaskPage(@Valid TaskPageReqVO pageReqVO) {
PageResult<TaskDO> pageResult = taskService.getTaskPage(pageReqVO); PageResult<TaskRespVO> pageResult = taskService.getTaskPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, TaskRespVO.class)); return success(pageResult);
} }
@GetMapping("/export-excel") @GetMapping("/export-excel")
@ -124,10 +124,10 @@ public class TaskController {
public void exportTaskExcel(@Valid TaskPageReqVO pageReqVO, public void exportTaskExcel(@Valid TaskPageReqVO pageReqVO,
HttpServletResponse response) throws IOException { HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<TaskDO> list = taskService.getTaskPage(pageReqVO).getList(); List<TaskRespVO> list = taskService.getTaskPage(pageReqVO).getList();
// 导出 Excel // 导出 Excel
ExcelUtils.write(response, "生产任务单.xls", "数据", TaskRespVO.class, ExcelUtils.write(response, "生产任务单.xls", "数据", TaskRespVO.class,
BeanUtils.toBean(list, TaskRespVO.class)); list);
} }
// ==================== 子表(生产任务单明细) ==================== // ==================== 子表(生产任务单明细) ====================

@ -27,9 +27,19 @@ public class TaskRespVO {
private LocalDateTime orderDate; private LocalDateTime orderDate;
@Schema(description = "交货日期", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "交货日期", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("交货日期")
private LocalDateTime deliveryDate; private LocalDateTime deliveryDate;
@Schema(description = "是否急单0-否 1-是 ", example = "1")
@ExcelProperty("是否急单")
@DictFormat("iot_1_or_0") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
private Integer isUrgent;
@Schema(description = "是否完成排产0-否 1-是 ", example = "1")
@ExcelProperty("是否完成排产")
@DictFormat("iot_1_or_0") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
private Integer isScheduled;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty(value = "状态", converter = DictConvert.class) @ExcelProperty(value = "状态", converter = DictConvert.class)
@DictFormat("mes_task_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 @DictFormat("mes_task_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
@ -51,7 +61,23 @@ public class TaskRespVO {
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间") @ExcelProperty("创建时间")
private LocalDateTime createTime; private LocalDateTime createTime;
@Schema(description = "任务单类型", example = "你猜")
@Schema(description = "任务单类型", example = "")
@ExcelProperty("任务单类型") @ExcelProperty("任务单类型")
private String taskType; private String taskType;
@Schema(description = "任务总数", example = "")
@ExcelProperty("任务总数")
private Long totalNumber;
@Schema(description = "已计划数量", example = "")
@ExcelProperty("已计划数量")
private Long planNumber;
@Schema(description = "未计划数量", example = "")
@ExcelProperty("未计划数量")
private Long unPlanNumber;
} }

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.mes.controller.admin.task.vo; package cn.iocoder.yudao.module.mes.controller.admin.task.vo;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.module.mes.dal.dataobject.task.TaskDetailDO; import cn.iocoder.yudao.module.mes.dal.dataobject.task.TaskDetailDO;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
@ -50,4 +52,11 @@ public class TaskSaveReqVO {
@Schema(description = "是否采用自动编码", example = "你猜") @Schema(description = "是否采用自动编码", example = "你猜")
private Boolean isCode; private Boolean isCode;
@Schema(description = "是否急单0-否 1-是 ", example = "1")
private Integer isUrgent;
@Schema(description = "是否完成排产0-否 1-是 ", example = "1")
private Integer isScheduled;
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save