diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 3e58c660b..4580fb6f3 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -70,10 +70,13 @@ 4.1.113.Final 1.2.5 0.6.9 + 3.5.3 + 2.17.0 1.27.1 1.12.777 + 2.41.33 1.0.8 1.7.8 4.6.0 @@ -589,6 +592,17 @@ ${aws-java-sdk-s3.version} + + + + + + + + + + + com.xingyuv spring-boot-starter-justauth @@ -648,6 +662,16 @@ logback-classic ${logback.version} + + com.google.zxing + core + ${qrcode.version} + + + com.google.zxing + javase + ${qrcode.version} + diff --git a/yudao-module-common/yudao-module-common-api/src/main/java/cn/iocoder/yudao/module/common/api/mold/enums/ErrorCodeConstants.java b/yudao-module-common/yudao-module-common-api/src/main/java/cn/iocoder/yudao/module/common/api/mold/enums/ErrorCodeConstants.java new file mode 100644 index 000000000..f3b45ca0a --- /dev/null +++ b/yudao-module-common/yudao-module-common-api/src/main/java/cn/iocoder/yudao/module/common/api/mold/enums/ErrorCodeConstants.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.common.api.mold.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * ERP 错误码枚举类 + *

+ * 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, "重新生成二维码/条形码错误。"); + +} diff --git a/yudao-module-common/yudao-module-common-biz/pom.xml b/yudao-module-common/yudao-module-common-biz/pom.xml index 418ad2281..6498dc13a 100644 --- a/yudao-module-common/yudao-module-common-biz/pom.xml +++ b/yudao-module-common/yudao-module-common-biz/pom.xml @@ -16,6 +16,12 @@ common 模块业务实现 + + + cn.iocoder.boot + yudao-common + + cn.iocoder.boot @@ -56,6 +62,14 @@ cn.iocoder.boot yudao-spring-boot-starter-excel + + com.google.zxing + core + + + com.google.zxing + javase + \ No newline at end of file diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/mold/vo/MoldSaveReqVO.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/mold/vo/MoldSaveReqVO.java index cccc7028c..c6574a0b2 100644 --- a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/mold/vo/MoldSaveReqVO.java +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/mold/vo/MoldSaveReqVO.java @@ -16,7 +16,7 @@ public class MoldSaveReqVO { private Long id; @Schema(description = "模具编码", requiredMode = Schema.RequiredMode.REQUIRED) - @NotEmpty(message = "模具编码不能为空") +// @NotEmpty(message = "模具编码不能为空") private String code; @Schema(description = "模具名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/qrcoderecord/QrcodeRecordController.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/qrcoderecord/QrcodeRecordController.java new file mode 100644 index 000000000..4223efcfe --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/qrcoderecord/QrcodeRecordController.java @@ -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 createRecord(@Valid @RequestBody QrcodeRecordSaveReqVO createReqVO) { + return success(qrcodeRecordService.createRecord(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新通用二维码记录") + @PreAuthorize("@ss.hasPermission('qrcode:record:update')") + public CommonResult 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 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 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> getRecordPage(@Valid QrcodeRecordPageReqVO pageReqVO) { + PageResult 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 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> resolveId(@RequestParam String type, + @RequestParam Long id, + @RequestParam String code) { + return success(qrcodeRecordService.resolveScanBizId(type, id, code)); + } + +} \ No newline at end of file diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/qrcoderecord/vo/QrcodeRecordPageReqVO.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/qrcoderecord/vo/QrcodeRecordPageReqVO.java new file mode 100644 index 000000000..c383a0757 --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/qrcoderecord/vo/QrcodeRecordPageReqVO.java @@ -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; +} \ No newline at end of file diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/qrcoderecord/vo/QrcodeRecordRespVO.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/qrcoderecord/vo/QrcodeRecordRespVO.java new file mode 100644 index 000000000..754f887ce --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/qrcoderecord/vo/QrcodeRecordRespVO.java @@ -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; + +} \ No newline at end of file diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/qrcoderecord/vo/QrcodeRecordSaveReqVO.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/qrcoderecord/vo/QrcodeRecordSaveReqVO.java new file mode 100644 index 000000000..a7c67bbff --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/controller/admin/qrcoderecord/vo/QrcodeRecordSaveReqVO.java @@ -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; + +} \ No newline at end of file diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/dal/dataobject/mold/MoldDO.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/dal/dataobject/mold/MoldDO.java index 622545641..620e7017b 100644 --- a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/dal/dataobject/mold/MoldDO.java +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/dal/dataobject/mold/MoldDO.java @@ -113,4 +113,10 @@ public class MoldDO extends BaseDO { @TableField(exist = false) private String moldType; + /** + * 二维码 + */ + @TableField(exist = false) + private String qrcodeUrl; + } \ No newline at end of file diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/dal/dataobject/qrcoderecord/QrcodeRecordDO.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/dal/dataobject/qrcoderecord/QrcodeRecordDO.java new file mode 100644 index 000000000..c495a6453 --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/dal/dataobject/qrcoderecord/QrcodeRecordDO.java @@ -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; + + +} \ No newline at end of file diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/dal/mysql/qrcoderecord/QrcodeRecordMapper.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/dal/mysql/qrcoderecord/QrcodeRecordMapper.java new file mode 100644 index 000000000..59456e00d --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/dal/mysql/qrcoderecord/QrcodeRecordMapper.java @@ -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 { + + default PageResult selectPage(QrcodeRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .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)); + } + +} \ No newline at end of file diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/enums/CodeTypeEnum.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/enums/CodeTypeEnum.java new file mode 100644 index 000000000..0fce7c546 --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/enums/CodeTypeEnum.java @@ -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; + } +} diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/enums/QrcodeBizTypeEnum.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/enums/QrcodeBizTypeEnum.java new file mode 100644 index 000000000..c4981aced --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/enums/QrcodeBizTypeEnum.java @@ -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; + } +} \ No newline at end of file diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/handler/QrcodeBizHandler.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/handler/QrcodeBizHandler.java new file mode 100644 index 000000000..d02bccff2 --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/handler/QrcodeBizHandler.java @@ -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); +} diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordService.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordService.java new file mode 100644 index 000000000..8673b4913 --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordService.java @@ -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 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 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; +} \ No newline at end of file diff --git a/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordServiceImpl.java b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordServiceImpl.java new file mode 100644 index 000000000..cd511acf7 --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/main/java/cn/iocoder/yudao/module/common/service/qrcordrecord/QrcodeRecordServiceImpl.java @@ -0,0 +1,598 @@ +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 bucketMap = new HashMap<>(); + + @Resource + private QrcodeRecordMapper qrcodeRecordMapper; + + + + + private final Map handlerMap; + + public QrcodeRecordServiceImpl(List 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 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() + .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 + "\"" : "") + + "}"; + + // 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 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() + .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 + "\"" : "") + + "}"; + + 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 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 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() + .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.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 resolveScanBizId(String type, Long id, String code) { + Map result = new HashMap<>(); + + if (StrUtil.isBlank(type) || id == null || StrUtil.isBlank(code)) { + return null; + } + + QrcodeRecordDO record = qrcodeRecordMapper.selectOne( + new LambdaQueryWrapper() + .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 "" + + "" + + "" + + "" + + "" + + "跳转中..." + + "" + + "" + + ""; + } + + + + + private String escapeHtml(String s) { + return s.replace("&", "&") + .replace("<", "<") + .replace(">", ">") + .replace("\"", """) + .replace("'", "'"); + } + + + + + + 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 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 records = qrcodeRecordMapper.selectList( + Wrappers.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.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() + .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 + "\"" : "") + + "}"; + + // 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 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); + } + } + + +} \ No newline at end of file diff --git a/yudao-module-common/yudao-module-common-biz/src/main/resources/mapper/qrcoderecord/QrcodeRecordMapper.xml b/yudao-module-common/yudao-module-common-biz/src/main/resources/mapper/qrcoderecord/QrcodeRecordMapper.xml new file mode 100644 index 000000000..a1fd8167f --- /dev/null +++ b/yudao-module-common/yudao-module-common-biz/src/main/resources/mapper/qrcoderecord/QrcodeRecordMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java index 211d3ec74..ad240414e 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -133,6 +133,10 @@ public interface ErrorCodeConstants { // ========== ERP 产品 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_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, "产品编码不存在"); + // ========== ERP 产品分类 1-030-501-000 ========== ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_501_000, "产品分类不存在"); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/AutocodeRuleController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/AutocodeRuleController.java index 1301464b2..64ae21f02 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/AutocodeRuleController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/AutocodeRuleController.java @@ -1,5 +1,7 @@ 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 io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; @@ -91,6 +93,16 @@ public class AutocodeRuleController { HttpServletResponse response) throws IOException { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); List list = autocodeRuleService.getAutocodeRulePage(pageReqVO).getList(); + List 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 ExcelUtils.write(response, "编码规则.xls", "数据", AutocodeRuleRespVO.class, BeanUtils.toBean(list, AutocodeRuleRespVO.class)); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/enums/ErpBarcodeTypeEnum.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/enums/ErpBarcodeTypeEnum.java new file mode 100644 index 000000000..296302131 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/enums/ErpBarcodeTypeEnum.java @@ -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 "未知"; + } + + +} \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/util/AutoCodeUtil.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/util/AutoCodeUtil.java index 2b32039d0..26dc0f7e9 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/util/AutoCodeUtil.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/util/AutoCodeUtil.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.autocode.util; import cn.hutool.core.date.DateUtil; 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.dal.dataobject.autocode.AutocodePartDO; import cn.iocoder.yudao.module.erp.dal.dataobject.autocode.AutocodeRecordDO; @@ -184,4 +185,14 @@ public class AutoCodeUtil { return autoCode; } + + + public CodeTypeEnum queryCodeType(String ruleCode) { + AutocodeRuleDO rule = iAutoCodeRuleService.getAutocodeRuleByRuleCode(ruleCode); + if (rule == null) { + return null; + } + return CodeTypeEnum.fromBarcodeType(rule.getBarcodeType()); + } + } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/vo/AutocodeRulePageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/vo/AutocodeRulePageReqVO.java index c10ca9b23..cb977f1d4 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/vo/AutocodeRulePageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/vo/AutocodeRulePageReqVO.java @@ -46,4 +46,7 @@ public class AutocodeRulePageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; + @Schema(description = "码类型条形码-1 二维码-2", example = "") + private Integer barcodeType; + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/vo/AutocodeRuleRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/vo/AutocodeRuleRespVO.java index 7b6d8e99c..e331c9629 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/vo/AutocodeRuleRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/vo/AutocodeRuleRespVO.java @@ -27,6 +27,13 @@ public class AutocodeRuleRespVO { @ExcelProperty("规则名称") private String ruleName; + @Schema(description = "码类型条形码-1 二维码-2", example = "") + private Integer barcodeType; + + @Schema(description = "码类型", example = "") + @ExcelProperty("码类型") + private String barcodeTypeName; + @Schema(description = "描述") @ExcelProperty("描述") private String ruleDesc; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/vo/AutocodeRuleSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/vo/AutocodeRuleSaveReqVO.java index b004db45f..0732699f3 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/vo/AutocodeRuleSaveReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/autocode/vo/AutocodeRuleSaveReqVO.java @@ -45,4 +45,8 @@ public class AutocodeRuleSaveReqVO { @Schema(description = "编码规则组成列表") private List autocodeParts; + @Schema(description = "码类型条形码-1 二维码-2", example = "") + private Integer barcodeType; + + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/mold/MoldBrandController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/mold/MoldBrandController.java index 925848f36..1790c069f 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/mold/MoldBrandController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/mold/MoldBrandController.java @@ -27,6 +27,7 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.util.List; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; @@ -143,7 +144,7 @@ public class MoldBrandController { @PostMapping("/mold/create") @Operation(summary = "创建模具") @PreAuthorize("@ss.hasPermission('erp:mold-brand:create')") - public CommonResult createMold(@Valid @RequestBody MoldSaveReqVO createReqVO) { + public CommonResult createMold(@Valid @RequestBody MoldSaveReqVO createReqVO) throws UnsupportedEncodingException { return success(moldBrandService.createMold(createReqVO)); } @@ -186,6 +187,15 @@ public class MoldBrandController { ExcelUtils.write(response, "模具.xls", "数据", MoldRespVO.class, list); } + + @PostMapping("/regenerate-code") + public CommonResult regenerateCode(@RequestParam("id") Long id, + @RequestParam("code") String code) throws UnsupportedEncodingException { + moldBrandService.regenerateCode(id, code); + return success(true); + } + + // ==================== 子表(模具产品) ==================== @GetMapping("/mold-brand-product/page") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java index 8209b4a3b..23cfd6073 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java @@ -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.util.object.BeanUtils; 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.product.*; 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.service.product.ErpProductCategoryService; 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.Parameter; import io.swagger.v3.oas.annotations.Parameters; @@ -28,14 +31,17 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; 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.success; 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 产品") @RestController @@ -51,18 +57,22 @@ public class ErpProductController { @PostMapping("/create") @Operation(summary = "创建产品") @PreAuthorize("@ss.hasPermission('erp:product:create')") - public CommonResult createProduct(@Valid @RequestBody ProductSaveReqVO createReqVO) { - ErpProductPageReqVO productPageReqVO = new ErpProductPageReqVO(); - productPageReqVO.setName(createReqVO.getName()); - productPageReqVO.setStandard(createReqVO.getStandard()); - if (productMapper.selectProductExist(productPageReqVO)) { - return error(400,"名称+规格不能重复"); - } - productPageReqVO = new ErpProductPageReqVO(); - productPageReqVO.setCode(createReqVO.getBarCode()); - if (!productMapper.selectProductCodeExist(productPageReqVO).getList().isEmpty()) { - return error(400,"编码不能重复"); - } + public CommonResult createProduct(@Valid @RequestBody ProductSaveReqVO createReqVO) throws UnsupportedEncodingException { +// ErpProductPageReqVO productPageReqVO = new ErpProductPageReqVO(); +// productPageReqVO.setName(createReqVO.getName()); +// productPageReqVO.setStandard(createReqVO.getStandard()); +// if (productMapper.selectProductExist(productPageReqVO)) { +// return error(400,"名称+规格不能重复"); +// } +// productPageReqVO = new ErpProductPageReqVO(); + +// productPageReqVO.setCode(createReqVO.getBarCode()); +// if (!productMapper.selectProductCodeExist(productPageReqVO).getList().isEmpty()) { +// return error(400,"编码不能重复"); +// } + + + return success(productService.createProduct(createReqVO)); } @@ -231,4 +241,12 @@ public class ErpProductController { return success(productService.importProductList(list, updateSupport)); } + + @PostMapping("/regenerate-code") + public CommonResult regenerateCode(@RequestParam("id") Long id, + @RequestParam("code") String code) throws UnsupportedEncodingException { + productService.regenerateCode(id, code); + return success(true); +// s + } } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java index 366bb7170..fbda49cab 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductRespVO.java @@ -83,4 +83,7 @@ public class ErpProductRespVO { @Schema(description = "预警库存", example = "161.87") @ExcelProperty("预警库存") private BigDecimal safetyNumber; + + @Schema(description = "二维码地址", example = "") + private String qrcodeUrl; } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java index 01325d92b..b898a48ba 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java @@ -19,7 +19,7 @@ public class ProductSaveReqVO { private String name; @Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "X110") - @NotEmpty(message = "产品条码不能为空") +// @NotEmpty(message = "产品条码不能为空") private String barCode; @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11161") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/autocode/AutocodeRuleDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/autocode/AutocodeRuleDO.java index fe6646fbc..d0ca70df3 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/autocode/AutocodeRuleDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/autocode/AutocodeRuleDO.java @@ -70,4 +70,10 @@ public class AutocodeRuleDO extends BaseDO { */ private Boolean isEnable; + /** + * 码类型条形码-1 二维码-2 + * + */ + private Integer barcodeType; + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java index cdd53e29d..d4a8dec02 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.erp.dal.dataobject.product; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; @@ -100,4 +101,10 @@ public class ErpProductDO extends BaseDO { * 预警库存 */ private BigDecimal safetyNumber; + + /** + * 二维码 + */ + @TableField(exist = false) + private String qrcodeUrl; } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java index 2ff01adbf..1608b826e 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java @@ -39,16 +39,18 @@ public interface ErpProductMapper extends BaseMapperX { .orderByAsc(ErpProductDO::getId)); } - default Boolean selectProductExist(ErpProductPageReqVO reqVO) { - LambdaQueryWrapperX queryWrapper = (LambdaQueryWrapperX) new LambdaQueryWrapperX() - .orderByAsc(ErpProductDO::getId); - 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(); + default Boolean selectProductExist(ErpProductDO reqVO) { + if (!StringUtils.hasText(reqVO.getName()) || !StringUtils.hasText(reqVO.getStandard())) { + return false; } - return false; + + // 直接使用 count 查询 + Long count = selectCount(new LambdaQueryWrapper() + .eq(ErpProductDO::getName, reqVO.getName()) + .eq(ErpProductDO::getStandard, reqVO.getStandard())); + + return count > 0; + } default Long selectCountByCategoryId(Long categoryId) { diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/handler/ProductQrcodeBizHandler.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/handler/ProductQrcodeBizHandler.java new file mode 100644 index 000000000..5c38c9234 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/handler/ProductQrcodeBizHandler.java @@ -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"; + + } +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/mold/MoldBrandService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/mold/MoldBrandService.java index e88ac0e5e..66b34e8b2 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/mold/MoldBrandService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/mold/MoldBrandService.java @@ -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 javax.validation.Valid; +import java.io.UnsupportedEncodingException; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -96,7 +97,7 @@ public interface MoldBrandService { * @param mold 创建信息 * @return 编号 */ - Long createMold(@Valid MoldSaveReqVO createReqVO); + Long createMold(@Valid MoldSaveReqVO createReqVO) throws UnsupportedEncodingException; /** * 更新模具 @@ -184,4 +185,6 @@ public interface MoldBrandService { } List getMoldBrandTree(); + + void regenerateCode(Long id, String code) throws UnsupportedEncodingException; } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/mold/MoldBrandServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/mold/MoldBrandServiceImpl.java index a5afa3777..fa24e61f6 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/mold/MoldBrandServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/mold/MoldBrandServiceImpl.java @@ -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.MoldRepairLineDO; 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.dal.dataobject.product.ErpProductDO; 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.ErpProductUnitService; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; 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.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.io.UnsupportedEncodingException; import java.util.*; import java.util.stream.Collectors; 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.convertSet; +import static cn.iocoder.yudao.module.common.api.mold.enums.ErrorCodeConstants.FAILED_TO_REGENERATE; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; /** @@ -50,6 +59,7 @@ import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; */ @Service @Validated +@Slf4j public class MoldBrandServiceImpl implements MoldBrandService { @Resource @@ -66,6 +76,12 @@ public class MoldBrandServiceImpl implements MoldBrandService { private ErpProductUnitService productUnitService; @Resource private ErpProductService productService; + @Resource + private QrcodeRecordService qrcodeService; + + @Autowired + private AutoCodeUtil autoCodeUtil; + @Override public Long createMoldBrand(MoldBrandSaveReqVO createReqVO) { // 插入 @@ -173,19 +189,48 @@ public class MoldBrandServiceImpl implements MoldBrandService { }); } @Override - public Long createMold(MoldSaveReqVO createReqVO) { + public Long createMold(MoldSaveReqVO createReqVO) throws UnsupportedEncodingException { String Code = createReqVO.getCode(); - if (StrUtil.isBlank(Code)) { - throw new ServiceException(ErrorCodeConstants.MOLD_CODE_EMPTY); - } - boolean exists = moldMapper.exists( - new LambdaQueryWrapperX().eq(MoldDO::getCode, Code) - ); - if (exists) { - throw new ServiceException(ErrorCodeConstants.MOLD_CODE_DUPLICATE); - } +// if (StrUtil.isBlank(Code)) { +// throw new ServiceException(ErrorCodeConstants.MOLD_CODE_EMPTY); +// } + +// boolean exists = moldMapper.exists( +// new LambdaQueryWrapperX().eq(MoldDO::getCode, Code) +// ); +// if (exists) { +// throw new ServiceException(ErrorCodeConstants.MOLD_CODE_DUPLICATE); +// } + + + MoldDO mold = BeanUtils.toBean(createReqVO, MoldDO.class); + + if (StringUtils.isBlank(Code)) { + mold.setCode(autoCodeUtil.genSerialCode("MOLD_CODE_GENERATE",null)); + } else { + if (moldMapper.selectOne(Wrappers.lambdaQuery().eq(MoldDO::getCode,Code)) != null) { + throw exception(MOLD_CODE_DUPLICATE); + } + } + 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(); } @@ -201,6 +246,10 @@ public class MoldBrandServiceImpl implements MoldBrandService { public void deleteMold(Long id) { // 校验存在 validateMoldExists(id); + + // 删除二维码/条形码 + qrcodeService.deleteByBiz(QrcodeBizTypeEnum.MOLD, id); + // 删除 moldMapper.deleteById(id); } @@ -255,7 +304,8 @@ public class MoldBrandServiceImpl implements MoldBrandService { if(CollectionUtils.isNotEmpty(moldRepairDOMap)){ moldDO.setRepairList(moldRepairDOMap); } - + String qrcodeUrl = qrcodeService.selectQrcodeUrlByIdAndCode(QrcodeBizTypeEnum.MOLD.getCode(),id,moldDO.getCode()); + moldDO.setQrcodeUrl(qrcodeUrl); return moldDO; } @Override @@ -353,6 +403,27 @@ public class MoldBrandServiceImpl implements MoldBrandService { 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() + ); + + } + /** * 构建树形结构 */ diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java index 0153a3fdf..1b8a45ca3 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java @@ -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 javax.validation.Valid; +import java.io.UnsupportedEncodingException; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -30,7 +31,7 @@ public interface ErpProductService { * @param createReqVO 创建信息 * @return 编号 */ - Long createProduct(@Valid ProductSaveReqVO createReqVO); + Long createProduct(@Valid ProductSaveReqVO createReqVO) throws UnsupportedEncodingException; /** * 更新产品 @@ -134,4 +135,6 @@ public interface ErpProductService { * @return 导入结果 */ ErpProductImportRespVO importProductList(List importProducts, boolean isUpdateSupport); + + void regenerateCode(Long id, String code) throws UnsupportedEncodingException; } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java index 8069822d8..c173156b5 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java @@ -8,6 +8,11 @@ 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.validation.ValidationUtils; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; +import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO; +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.product.vo.product.ErpProductImportExcelVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductImportRespVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO; @@ -22,7 +27,10 @@ import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper; import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; 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.dao.DuplicateKeyException; import org.springframework.stereotype.Service; @@ -32,11 +40,13 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.ConstraintViolationException; import javax.validation.Valid; +import java.io.UnsupportedEncodingException; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; 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.convertMap; 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 @Validated +@Slf4j public class ErpProductServiceImpl implements ErpProductService { @Resource @@ -69,13 +80,34 @@ public class ErpProductServiceImpl implements ErpProductService { @Lazy // 延迟注入 private ErpStockService erpStockService; + @Resource + private QrcodeRecordService qrcodeService; + @Autowired + private AutoCodeUtil autoCodeUtil; @Override - public Long createProduct(ProductSaveReqVO createReqVO) { + 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.lambdaQuery().eq(ErpProductDO::getBarCode,code)) != null) { + throw exception(PRODUCT_CODE_EXISTS); + } + } + // TODO 芋艿:校验分类 // 插入 - ErpProductDO product = BeanUtils.toBean(createReqVO, ErpProductDO.class); ErpProductCategoryDO productCategory = productCategoryMapper.selectById(product.getCategoryId()); Long id = productCategory.getParentId(); product.setSubCategoryName(productCategory.getName()); @@ -85,7 +117,39 @@ public class ErpProductServiceImpl implements ErpProductService { product.setCategoryId(id); id = productCategory.getParentId(); } + + + product.setBarCode(productCategory.getCode()+ "-" + code); productMapper.insert(product); + + // 生成二维码 + +// try { +// qrcodeService.generateOrRefresh( +// QrcodeBizTypeEnum.PRODUCT, // bizType +// product.getId(), // bizId +// product.getBarCode(), // bizCode +// "DETAIL" // scene +// ); +// } catch (Exception e) { +// log.error("[产品物料] 生成二维码失败,id={}, code={}", +// product.getId(), product.getBarCode(), e); +// } + // 生成二维码 + 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(); } @@ -154,7 +218,11 @@ public class ErpProductServiceImpl implements ErpProductService { @Override public ErpProductDO getProduct(Long id) { - return productMapper.selectById(id); + ErpProductDO erpProductDO = productMapper.selectById(id); + + String qrcodeUrl = qrcodeService.selectQrcodeUrlByIdAndCode(QrcodeBizTypeEnum.PRODUCT.getCode(),id,erpProductDO.getBarCode()); + erpProductDO.setQrcodeUrl(qrcodeUrl); + return erpProductDO ; } @Override @@ -324,6 +392,26 @@ public class ErpProductServiceImpl implements ErpProductService { 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) { ErpProductDO productDO = BeanUtils.toBean(importProduct, ErpProductDO.class); diff --git a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java index cfed8d1ee..8d34c0642 100644 --- a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java +++ b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java @@ -40,4 +40,7 @@ public interface FileApi { */ Map createFile(String name, String path, byte[] content); + Long getFileByPath(String path); + + void deleteFile(Long id) throws Exception; } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java index ffac1b0f6..f901c924c 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java @@ -1,5 +1,6 @@ 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 org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -24,4 +25,13 @@ public class FileApiImpl implements FileApi { 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); + } } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java index bba2ef9a2..a105b6c22 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java @@ -65,4 +65,7 @@ public interface FileService { */ FilePresignedUrlRespVO getFilePresignedUrl(String path) throws Exception; + FileDO getFileByPath(String path); + + } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java index ba97771e9..b6980f3eb 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java @@ -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.dal.dataobject.file.FileDO; import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.SneakyThrows; import org.springframework.stereotype.Service; @@ -121,4 +122,16 @@ public class FileServiceImpl implements FileService { object -> object.setConfigId(fileClient.getId())); } + @Override + public FileDO getFileByPath(String path) { + if (StrUtil.isBlank(path)) { + return null; + } + return fileMapper.selectOne( + Wrappers.lambdaQuery() + .eq(FileDO::getPath, path) + .orderByDesc(FileDO::getId) + .last("limit 1") + ); } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceSaveReqVO.java index 264ac27c9..77c34e256 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceSaveReqVO.java @@ -53,7 +53,7 @@ public class DeviceSaveReqVO { private Boolean isEnable; @Schema(description = "关联设备模型", example = "1") - @NotNull(message = "关联设备模型ID不能为空") +// @NotNull(message = "关联设备模型ID不能为空") private Long deviceModelId; @Schema(description = "通讯协议", example = "OPCUA") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelattribute/vo/DeviceModelAttributeRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelattribute/vo/DeviceModelAttributeRespVO.java index 72c140cb6..cbc2c8d01 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelattribute/vo/DeviceModelAttributeRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/devicemodelattribute/vo/DeviceModelAttributeRespVO.java @@ -26,15 +26,15 @@ public class DeviceModelAttributeRespVO { private String attributeName; @Schema(description = "采集点位类型编码", example = "1") - @ExcelProperty("采集点位类型编码") + @ExcelProperty("点位类型编码") private String attributeTypeCode; @Schema(description = "点位类型", example = "1") - @ExcelProperty("点位类型") +// @ExcelProperty("点位类型") private String attributeType; @Schema(description = "类型名称", example = "1") - @ExcelProperty("类型名称") +// @ExcelProperty("类型名称") private String typeName; @Schema(description = "数据类型", example = "2") @@ -61,11 +61,11 @@ public class DeviceModelAttributeRespVO { private String remark; @Schema(description = "采集设备模型id", requiredMode = Schema.RequiredMode.REQUIRED, example = "16848") - @ExcelProperty("采集设备模型id") +// @ExcelProperty("采集设备模型id") private Long deviceModelId; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") +// @ExcelProperty("创建时间") @ColumnWidth(20) // 设置此列的宽度为 20 个字符的宽度 private LocalDateTime createTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java index 56cccc60e..e54959650 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java @@ -154,13 +154,19 @@ public class DeviceServiceImpl implements DeviceService { device.setTenantId("1"); deviceMapper.insert(device); + if (createReqVO.getDeviceModelId()!=null){ + insertTemplatePoint(createReqVO, device); + } + return device; + } + private void insertTemplatePoint(DeviceSaveReqVO createReqVO, DeviceDO device) { //新增模板点位 LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.eq(DeviceModelAttributeDO::getDeviceModelId,createReqVO.getDeviceModelId()).orderByDesc(DeviceModelAttributeDO::getId); + lambdaQueryWrapper.eq(DeviceModelAttributeDO::getDeviceModelId, createReqVO.getDeviceModelId()).orderByDesc(DeviceModelAttributeDO::getId); List deviceModelAttributeDOS = deviceModelAttributeMapper.selectList(lambdaQueryWrapper); - if (deviceModelAttributeDOS.isEmpty()){ + if (deviceModelAttributeDOS.isEmpty()) { throw exception(DEVICE_MODEL_ATTRIBUTE_NOT_EXISTS); } @@ -180,10 +186,8 @@ public class DeviceServiceImpl implements DeviceService { // createTDengine(device.getId()); //新增规则点位 - addNewRulePoints(createReqVO.getDeviceModelId(),device.getId()); - tdengineService.createTdengineTable(device.getId(),contactModelList); - - return device; + addNewRulePoints(createReqVO.getDeviceModelId(), device.getId()); + tdengineService.createTdengineTable(device.getId(), contactModelList); } private void addNewRulePoints(Long deviceModelId,Long deviceId) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicemodelattribute/DeviceModelAttributeServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicemodelattribute/DeviceModelAttributeServiceImpl.java index 438cb918a..7b334303f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicemodelattribute/DeviceModelAttributeServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/devicemodelattribute/DeviceModelAttributeServiceImpl.java @@ -295,7 +295,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; // 不能为空 if (StringUtils.isBlank(code)) { - respVO.getFailureCodes().put(importAttribute.getAttributeCode(), "点位类型名称不能为空"); + respVO.getFailureCodes().put(importAttribute.getAttributeCode(), "点位类型编码不能为空"); return; } // 必须存在于数据库类型列表中(防止乱填) diff --git a/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java index 9ad40f36a..1abef087e 100644 --- a/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java +++ b/yudao-module-mes/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java @@ -144,14 +144,17 @@ public interface ErrorCodeConstants { ErrorCode DEVICE_LEDGER_EXISTS = new ErrorCode(1002000010, "设备台账编码已存在"); ErrorCode SUBJECT_EXISTS = new ErrorCode(1002000010, "项目编码已存在"); ErrorCode TASK_MANAGEMENT_NOT_EXISTS = new ErrorCode(1002000011, "设备类型不存在"); - ErrorCode TASK_CORN_NOT_EXISTS = new ErrorCode(1002000011, "设备corn表达式为空"); - ErrorCode TASK_CORN_NOT_LE_HOUR = new ErrorCode(1002000011, "corn表达式不能小于一小时"); + ErrorCode TASK_CORN_NOT_EXISTS = new ErrorCode(1002000012, "设备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_RESULTS_NOT_EXISTS = new ErrorCode(1002000013, "工单检验结果不存在"); ErrorCode TICKET_RESULTS_ID_NOT_NULL = new ErrorCode(1002000014, "工单检验结果Id不存在"); ErrorCode CRITICAL_COMPONENT_NOT_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, "存在设备关键件已被引用,请先删除引用"); diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/criticalcomponent/CriticalComponentController.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/criticalcomponent/CriticalComponentController.java index 88a7300f2..6b0fcacca 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/criticalcomponent/CriticalComponentController.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/criticalcomponent/CriticalComponentController.java @@ -11,6 +11,7 @@ import io.swagger.v3.oas.annotations.Operation; import javax.validation.constraints.*; import javax.validation.*; import javax.servlet.http.*; +import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -48,7 +49,7 @@ public class CriticalComponentController { @PostMapping("/create") @Operation(summary = "创建设备关键件") @PreAuthorize("@ss.hasPermission('mes:critical-component:create')") - public CommonResult createCriticalComponent(@Valid @RequestBody CriticalComponentSaveReqVO createReqVO) { + public CommonResult createCriticalComponent(@Valid @RequestBody CriticalComponentSaveReqVO createReqVO) throws UnsupportedEncodingException { return success(criticalComponentService.createCriticalComponent(createReqVO)); } @@ -170,4 +171,12 @@ public class CriticalComponentController { return success(criticalComponentService.importCriticalComponentList(list, updateSupport)); } + + @PostMapping("/regenerate-code") + public CommonResult regenerateCode(@RequestParam("id") Long id, + @RequestParam("code") String code) throws UnsupportedEncodingException { + criticalComponentService.regenerateCode(id, code); + return success(true); + } + } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/criticalcomponent/vo/CriticalComponentRespVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/criticalcomponent/vo/CriticalComponentRespVO.java index cbdbec9c0..5523c4cf4 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/criticalcomponent/vo/CriticalComponentRespVO.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/criticalcomponent/vo/CriticalComponentRespVO.java @@ -41,4 +41,7 @@ public class CriticalComponentRespVO { @Schema(description = "数量", example = "2") private Integer count; + @Schema(description = "二维码", example = "2") + private String qrcodeUrl; + } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/criticalcomponent/vo/CriticalComponentSaveReqVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/criticalcomponent/vo/CriticalComponentSaveReqVO.java index 9d37e040a..5b0f52ae4 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/criticalcomponent/vo/CriticalComponentSaveReqVO.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/criticalcomponent/vo/CriticalComponentSaveReqVO.java @@ -13,7 +13,7 @@ public class CriticalComponentSaveReqVO { private Long id; @Schema(description = "编码(唯一标识)", requiredMode = Schema.RequiredMode.REQUIRED) - @NotEmpty(message = "编码(唯一标识)不能为空") +// @NotEmpty(message = "编码(唯一标识)不能为空") private String code; @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/deviceledger/DeviceLedgerController.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/deviceledger/DeviceLedgerController.java index 6f3aca196..5780a59d2 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/deviceledger/DeviceLedgerController.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/deviceledger/DeviceLedgerController.java @@ -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.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.mes.controller.admin.deviceledger.utils.ResumeNameUtils; 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.servlet.http.*; +import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -60,11 +63,14 @@ public class DeviceLedgerController { @Resource private AdminUserApi adminUserApi; + @Resource + private QrcodeRecordService qrcodeService; + @PostMapping("/create") @Operation(summary = "创建设备台账") @PreAuthorize("@ss.hasPermission('mes:device-ledger:create')") - public CommonResult createDeviceLedger(@Valid @RequestBody DeviceLedgerSaveReqVO createReqVO) { + public CommonResult createDeviceLedger(@Valid @RequestBody DeviceLedgerSaveReqVO createReqVO) throws UnsupportedEncodingException { return success(deviceLedgerService.createDeviceLedger(createReqVO)); } @@ -99,6 +105,10 @@ public class DeviceLedgerController { public CommonResult getDeviceLedger(@RequestParam("id") Long id) { DeviceLedgerDO deviceLedger = deviceLedgerService.getDeviceLedger(id); 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()); if (StringUtils.isNotBlank(respVO.getDeviceManager())) { String[] userIds = respVO.getDeviceManager().split(","); @@ -250,4 +260,19 @@ public class DeviceLedgerController { // 导出 Excel ExcelUtils.write(response, fileName, "数据", MoldVO.class,list); } + + + @PostMapping("/regenerate-code") + public CommonResult regenerateCode(@RequestParam("id") Long id, + @RequestParam("code") String code) throws UnsupportedEncodingException { + deviceLedgerService.regenerateCode(id, code); + return success(true); + + } + + + + + + } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/deviceledger/vo/DeviceLedgerRespVO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/deviceledger/vo/DeviceLedgerRespVO.java index 41207cce6..a9f9b1787 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/deviceledger/vo/DeviceLedgerRespVO.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/deviceledger/vo/DeviceLedgerRespVO.java @@ -151,4 +151,7 @@ public class DeviceLedgerRespVO extends BaseDO { @Schema(description = "关联采集设备id") private Long dvId; + + @Schema(description = "二维码") + private String qrcodeUrl; } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/criticalcomponent/CriticalComponentDO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/criticalcomponent/CriticalComponentDO.java index 440343fb4..6e87639be 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/criticalcomponent/CriticalComponentDO.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/criticalcomponent/CriticalComponentDO.java @@ -47,5 +47,10 @@ public class CriticalComponentDO extends BaseDO { * 备注 */ private Integer count; + /** + * 二维码 + */ + @TableField(exist = false) + private String qrcodeUrl; } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/deviceledger/DeviceLedgerDO.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/deviceledger/DeviceLedgerDO.java index 3fb4d6eab..085716486 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/deviceledger/DeviceLedgerDO.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/deviceledger/DeviceLedgerDO.java @@ -175,4 +175,9 @@ public class DeviceLedgerDO extends BaseDO { */ private Long dvId; + /** + * 二维码 + */ + @TableField(exist = false) + private String qrcodeUrl; } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/handler/CriticalComponentQrcodeBizHandler.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/handler/CriticalComponentQrcodeBizHandler.java new file mode 100644 index 000000000..a97d3fa7d --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/handler/CriticalComponentQrcodeBizHandler.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.mes.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.mes.dal.mysql.criticalcomponent.CriticalComponentMapper; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +@Component +public class CriticalComponentQrcodeBizHandler implements QrcodeBizHandler { + @Resource + private CriticalComponentMapper criticalComponentMapper; + + public String getBizType() { + return QrcodeBizTypeEnum.KEY_PART.getCode(); + } + + public boolean exists(Long id) { return criticalComponentMapper.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"; + + } +} diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/handler/DeviceLedgerQrcodeBizHandler.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/handler/DeviceLedgerQrcodeBizHandler.java new file mode 100644 index 000000000..cbefe57be --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/handler/DeviceLedgerQrcodeBizHandler.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.mes.handler; + +import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum; +import cn.iocoder.yudao.module.common.handler.QrcodeBizHandler; +import cn.iocoder.yudao.module.mes.dal.mysql.deviceledger.DeviceLedgerMapper; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +@Component +public class DeviceLedgerQrcodeBizHandler implements QrcodeBizHandler { + @Resource + private DeviceLedgerMapper deviceLedgerMapper; + + public String getBizType() { + return QrcodeBizTypeEnum.EQUIPMENT.getCode(); + } + + public boolean exists(Long id) { return deviceLedgerMapper.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"; + + } +} diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/handler/MoldQrcodeBizHandler.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/handler/MoldQrcodeBizHandler.java new file mode 100644 index 000000000..9b3e51623 --- /dev/null +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/handler/MoldQrcodeBizHandler.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.mes.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 org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +@Component +public class MoldQrcodeBizHandler implements QrcodeBizHandler { + @Resource + private MoldMapper moldMapper; + + public String getBizType() { + return QrcodeBizTypeEnum.MOLD.getCode(); + } + + public boolean exists(Long id) { return moldMapper.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"; + + } +} diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/criticalcomponent/CriticalComponentService.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/criticalcomponent/CriticalComponentService.java index 92f16c6b9..36b473997 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/criticalcomponent/CriticalComponentService.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/criticalcomponent/CriticalComponentService.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.mes.service.criticalcomponent; +import java.io.UnsupportedEncodingException; import java.util.*; import javax.validation.*; import cn.iocoder.yudao.module.mes.controller.admin.criticalcomponent.vo.*; @@ -20,7 +21,7 @@ public interface CriticalComponentService { * @param createReqVO 创建信息 * @return 编号 */ - Long createCriticalComponent(@Valid CriticalComponentSaveReqVO createReqVO); + Long createCriticalComponent(@Valid CriticalComponentSaveReqVO createReqVO) throws UnsupportedEncodingException; /** * 更新设备关键件 @@ -61,4 +62,5 @@ public interface CriticalComponentService { */ CriticalComponentImportRespVO importCriticalComponentList(List importComponents, boolean isUpdateSupport); + void regenerateCode(Long id, String code) throws UnsupportedEncodingException; } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/criticalcomponent/CriticalComponentServiceImpl.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/criticalcomponent/CriticalComponentServiceImpl.java index a156c7ceb..385968f9c 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/criticalcomponent/CriticalComponentServiceImpl.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/criticalcomponent/CriticalComponentServiceImpl.java @@ -1,5 +1,10 @@ package cn.iocoder.yudao.module.mes.service.criticalcomponent; +import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO; +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.iot.dal.dataobject.devicemodelattribute.DeviceModelAttributeDO; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; @@ -11,6 +16,8 @@ import cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants; import com.alibaba.excel.util.StringUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; 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 javax.annotation.Resource; import javax.validation.ConstraintViolationException; @@ -18,6 +25,7 @@ import javax.validation.ConstraintViolationException; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import java.io.UnsupportedEncodingException; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; @@ -30,6 +38,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.mes.dal.mysql.criticalcomponent.CriticalComponentMapper; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_MODEL_ATTRIBUTE_POTIN_CODE_EXISTS; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; @@ -40,6 +49,7 @@ import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; */ @Service @Validated +@Slf4j public class CriticalComponentServiceImpl implements CriticalComponentService { @Resource @@ -51,24 +61,49 @@ public class CriticalComponentServiceImpl implements CriticalComponentService { @Resource private RepairTemsMapper repairTemsMapper; + @Resource + private QrcodeRecordService qrcodeService; + + @Autowired + private AutoCodeUtil autoCodeUtil; @Override - public Long createCriticalComponent(CriticalComponentSaveReqVO createReqVO) { + public Long createCriticalComponent(CriticalComponentSaveReqVO createReqVO) throws UnsupportedEncodingException { //判断编码是否唯一 - boolean exists = criticalComponentMapper.exists( - Wrappers.lambdaQuery() - .eq(CriticalComponentDO::getCode, createReqVO.getCode())); +// boolean exists = criticalComponentMapper.exists( +// Wrappers.lambdaQuery() +// .eq(CriticalComponentDO::getCode, createReqVO.getCode())); +// +// if (exists) { +// throw exception(CRITICAL_COMPONENT_CODE_EXISTS); +// } + CriticalComponentDO criticalComponent = BeanUtils.toBean(createReqVO, CriticalComponentDO.class); - if (exists) { - throw exception(CRITICAL_COMPONENT_CODE_EXISTS); + //判断编码是否唯一 + if (StringUtils.isBlank(createReqVO.getCode())) { + criticalComponent.setCode(autoCodeUtil.genSerialCode("COMPONENT_CODE_GENERATE",null)); + } else { + if (criticalComponentMapper.selectOne(Wrappers.lambdaQuery().eq(CriticalComponentDO::getCode,createReqVO.getCode())) != null) { + throw exception(CRITICAL_COMPONENT_CODE_EXISTS); + } } - - - // 插入 - CriticalComponentDO criticalComponent = BeanUtils.toBean(createReqVO, CriticalComponentDO.class); criticalComponentMapper.insert(criticalComponent); + + CodeTypeEnum codeType = autoCodeUtil.queryCodeType("COMPONENT_CODE_GENERATE"); + if (codeType==null){ + log.warn("[创建设备关键件]未配置码类型,跳过生产,ruleCode={}","COMPONENT_CODE_GENERATE"); + return criticalComponent.getId(); + } + + qrcodeService.generateOrRefresh( + QrcodeBizTypeEnum.KEY_PART, + criticalComponent.getId(), + criticalComponent.getCode(), + "DETAIL", + codeType + ); // 返回 return criticalComponent.getId(); } @@ -162,7 +197,11 @@ public class CriticalComponentServiceImpl implements CriticalComponentService { @Override public CriticalComponentDO getCriticalComponent(Long id) { - return criticalComponentMapper.selectById(id); + CriticalComponentDO criticalComponentDO = criticalComponentMapper.selectById(id); + String qrcodeUrl = qrcodeService.selectQrcodeUrlByIdAndCode(QrcodeBizTypeEnum.KEY_PART.getCode(),id,criticalComponentDO.getCode()); + criticalComponentDO.setQrcodeUrl(qrcodeUrl); + return criticalComponentDO; + } @Override @@ -278,4 +317,25 @@ public class CriticalComponentServiceImpl implements CriticalComponentService { return respVO; } + + @Override + public void regenerateCode(Long id, String code) throws UnsupportedEncodingException { + if(criticalComponentMapper.selectById(id)==null){ + throw exception(CRITICAL_COMPONENT_NOT_EXISTS); + } + if(StringUtils.isBlank(code)){ + throw exception(CRITICAL_COMPONENT_CODE_NOT_EXISTS); + } + + CodeTypeEnum codeGenerate = autoCodeUtil.queryCodeType("COMPONENT_CODE_GENERATE"); + + qrcodeService.regenerateByCodeType( + QrcodeBizTypeEnum.KEY_PART, + id, + code, + "DETAIL", + codeGenerate.getCode() + ); + + } } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/deviceledger/DeviceLedgerService.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/deviceledger/DeviceLedgerService.java index e11f9509c..85867d2ea 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/deviceledger/DeviceLedgerService.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/deviceledger/DeviceLedgerService.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.mes.service.deviceledger; +import java.io.UnsupportedEncodingException; import java.util.*; import javax.validation.*; @@ -25,7 +26,7 @@ public interface DeviceLedgerService { * @param createReqVO 创建信息 * @return 编号 */ - Long createDeviceLedger(@Valid DeviceLedgerSaveReqVO createReqVO); + Long createDeviceLedger(@Valid DeviceLedgerSaveReqVO createReqVO) throws UnsupportedEncodingException; /** * 更新设备类型 @@ -80,4 +81,6 @@ public interface DeviceLedgerService { List exportSpareBased(Long id); List exportMold(Long id); + + void regenerateCode(Long id, String code) throws UnsupportedEncodingException; } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/deviceledger/DeviceLedgerServiceImpl.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/deviceledger/DeviceLedgerServiceImpl.java index 116fc3870..93c9771f2 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/deviceledger/DeviceLedgerServiceImpl.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/deviceledger/DeviceLedgerServiceImpl.java @@ -2,6 +2,10 @@ package cn.iocoder.yudao.module.mes.service.deviceledger; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +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.MoldRespVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldBrandDO; @@ -31,11 +35,14 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; 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.stereotype.Service; import javax.annotation.Resource; import org.springframework.validation.annotation.Validated; +import java.io.UnsupportedEncodingException; import java.util.*; import java.util.stream.Collectors; @@ -48,6 +55,7 @@ import cn.iocoder.yudao.module.mes.dal.mysql.deviceledger.DeviceLedgerMapper; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; /** @@ -57,6 +65,7 @@ import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; */ @Service @Validated +@Slf4j public class DeviceLedgerServiceImpl implements DeviceLedgerService { @Resource @@ -90,13 +99,27 @@ public class DeviceLedgerServiceImpl implements DeviceLedgerService { @Resource private DeviceService deviceService; + @Resource + private QrcodeRecordService qrcodeService; + + @Autowired + private AutoCodeUtil autoCodeUtil; + @Override - public Long createDeviceLedger(DeviceLedgerSaveReqVO createReqVO) { + public Long createDeviceLedger(DeviceLedgerSaveReqVO createReqVO) throws UnsupportedEncodingException { + DeviceLedgerDO deviceLedger = BeanUtils.toBean(createReqVO, DeviceLedgerDO.class); //验证是否唯一编码 - validateCodeOnly(createReqVO.getDeviceCode()); - // 插入 - DeviceLedgerDO deviceLedger = BeanUtils.toBean(createReqVO, DeviceLedgerDO.class); +// validateCodeOnly(createReqVO.getDeviceCode()); + if (StringUtils.isBlank(createReqVO.getDeviceCode())) { + deviceLedger.setDeviceCode(autoCodeUtil.genSerialCode("DEVICE_CODE_GENERATE",null)); + } else { + if (deviceLedgerMapper.selectOne(Wrappers.lambdaQuery().eq(DeviceLedgerDO::getDeviceCode,createReqVO.getDeviceCode())) != null) { + throw exception(DEVICE_LEDGER_EXISTS); + } + } + + // 创建台账 deviceLedgerMapper.insert(deviceLedger); @@ -107,6 +130,23 @@ public class DeviceLedgerServiceImpl implements DeviceLedgerService { // deviceRespVO.setOrg(Long.valueOf(deviceLedger.getWorkshop())); // deviceService.updateDevice(BeanUtils.toBean(deviceRespVO, DeviceSaveReqVO.class)); // } + + + // 生成二维码 + CodeTypeEnum codeType = autoCodeUtil.queryCodeType("DEVICE_CODE_GENERATE"); + if (codeType==null){ + log.warn("[创建设备台账]未配置码类型,跳过生产,ruleCode={}","DEVICE_CODE_GENERATE"); + return deviceLedger.getId(); + } + + qrcodeService.generateOrRefresh( + QrcodeBizTypeEnum.EQUIPMENT, + deviceLedger.getId(), + deviceLedger.getDeviceCode(), + "DETAIL", + codeType + ); + // 返回 return deviceLedger.getId(); } @@ -335,6 +375,25 @@ public class DeviceLedgerServiceImpl implements DeviceLedgerService { return BeanUtils.toBean(moldList, MoldVO.class); } + @Override + public void regenerateCode(Long id, String code) throws UnsupportedEncodingException { + if(deviceLedgerMapper.selectById(id)==null){ + throw exception(DEVICE_LEDGER_NOT_EXISTS); + } + if(StringUtils.isBlank(code)){ + throw exception(DEVICE_LEDGER_CODE_NOT_EXISTS); + } + CodeTypeEnum codeGenerate = autoCodeUtil.queryCodeType("DEVICE_CODE_GENERATE"); +//s + qrcodeService.regenerateByCodeType( + QrcodeBizTypeEnum.EQUIPMENT, + id, + code, + "DETAIL", + codeGenerate.getCode() + ); + + } } \ No newline at end of file diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index cbcfa2748..5ac80ed16 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -77,11 +77,11 @@ spring: # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 redis: - host: 47.106.185.127 # 地址 - port: 6379 # 端口 + host: ngsk.tech # 地址 + port: 36378 # 端口 database: 0 # 数据库索引 #password: bkcaydy8ydhZZnS2 # 密码,建议生产环境开启 - password: BstPwd258 + password: ngsk0809 --- #################### 定时任务相关配置 #################### @@ -235,6 +235,22 @@ yudao: demo: false # 关闭演示模式 tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc + qrcode: + scan-base-url: http://192.168.5.167:48081/admin-api/qrcode/record/scan/resolve-id + transit-url: http://10.10.10.20:8080/h5/qrcode/transit + fail-url: https://chat.baidu.com/search?extParams=%7B%22enter_type%22%3A%22home_operate%22%7D&isShowHello=1 + width: 300 + height: 300 + default-bucket: common-qrcode + buckets: + mold: mold-qrcode + product: product-qrcode + equipment: equipment-qrcode + part: part-qrcode + spare: spare-qrcode + work-order: workorder-qrcode + + justauth: enabled: true type: diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index b5f389448..09d654310 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -264,6 +264,9 @@ yudao: - /admin-api/mp/open/** # 微信公众号开放平台,微信回调接口,无法携带租户编号 - /admin-api/iot/mqtt-server/** - /admin-api/home/info/** + - /admin-api/qrcode/record/scan/resolve-id + + # - /admin-api/qrcode/record/scan # 扫描二维码 ignore-tables: - system_tenant - system_tenant_package