diff --git a/win-module-eam/win-module-eam-api/src/main/java/com/win/module/eam/enums/ErrorCodeConstants.java b/win-module-eam/win-module-eam-api/src/main/java/com/win/module/eam/enums/ErrorCodeConstants.java
index f3d7898..ebf65ec 100644
--- a/win-module-eam/win-module-eam-api/src/main/java/com/win/module/eam/enums/ErrorCodeConstants.java
+++ b/win-module-eam/win-module-eam-api/src/main/java/com/win/module/eam/enums/ErrorCodeConstants.java
@@ -167,6 +167,6 @@ public interface ErrorCodeConstants {
ErrorCode LOCATION_EXISTS = new ErrorCode(1_000_020_021, "该库位已与备件绑定不可重复绑定");
ErrorCode ITEM_EXISTS = new ErrorCode(1_000_020_021, "该备件已绑定不可重复绑定");
-
+ ErrorCode ENCRYPTION_STR_FORMAT_IS_ERROR = new ErrorCode(1_000_020_064, "授权码字符串格式错误");
}
diff --git a/win-module-eam/win-module-eam-biz/pom.xml b/win-module-eam/win-module-eam-biz/pom.xml
index a501a4f..77d6dbd 100644
--- a/win-module-eam/win-module-eam-biz/pom.xml
+++ b/win-module-eam/win-module-eam-biz/pom.xml
@@ -124,6 +124,12 @@
com.alibaba
fastjson
+
+ com.google.zxing
+ core
+ 3.3.1
+ compile
+
diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/licences/LicencesController.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/licences/LicencesController.java
new file mode 100644
index 0000000..204a31a
--- /dev/null
+++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/licences/LicencesController.java
@@ -0,0 +1,59 @@
+package com.win.module.eam.controller.licences;
+
+import cn.hutool.extra.qrcode.QrCodeUtil;
+import com.win.framework.common.pojo.CommonResult;
+import com.win.module.eam.controller.licences.vo.GenerateLicenceReqVO;
+import com.win.module.eam.service.licences.LicencesService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.io.IOException;
+
+import static com.win.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "接口-续期许可")
+@RestController
+@RequestMapping("/eam/basic/licences")
+@Validated
+public class LicencesController {
+ @Resource
+ private LicencesService licencesService;
+
+ @PostMapping("/licenceDiscernByCodeFile")
+ @Operation(summary = "识别续期许可(二维码图片)")
+ @Parameters({
+ @Parameter(name = "file", description = "续期二维码图片", required = true)
+ })
+ @PreAuthorize("@ss.hasPermission('basic:licences:licenceDiscern')")
+ public CommonResult licenceDiscernByCodeFile(@Valid @NotNull @RequestParam("file") MultipartFile file) throws IOException {
+ licencesService.licencesDiscern(QrCodeUtil.decode(file.getInputStream()));
+ return success(true);
+ }
+
+ @PostMapping("/licenceDiscernByCodeStr")
+ @Operation(summary = "识别续期许可(二维码字符串)")
+ @Parameters({
+ @Parameter(name = "code", description = "续期二维码识别出来的字符串", required = true)
+ })
+ @PreAuthorize("@ss.hasPermission('basic:licences:licenceDiscern')")
+ public CommonResult licenceDiscernByCodeStr(@RequestBody String code) {
+ licencesService.licencesDiscern(code);
+ return success(true);
+ }
+ @PostMapping("/generateLicence")
+ @Operation(summary = "生成续期二维码")
+ @PreAuthorize("@ss.hasPermission('basic:licences:licenceDiscern')")
+ public void generateLicence(@Valid @RequestBody GenerateLicenceReqVO req,HttpServletResponse response) throws Exception {
+ licencesService.generateLicence(req,response);
+ }
+}
diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/licences/vo/GenerateLicenceReqVO.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/licences/vo/GenerateLicenceReqVO.java
new file mode 100644
index 0000000..693728d
--- /dev/null
+++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/controller/licences/vo/GenerateLicenceReqVO.java
@@ -0,0 +1,20 @@
+package com.win.module.eam.controller.licences.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 生成续期码 Request VO")
+@Data
+@ToString(callSuper = true)
+public class GenerateLicenceReqVO {
+ @NotNull(message = "公司编码不能为空")
+ @Schema(description = "公司编码")
+ private String companyCode;
+
+ @NotNull(message = "到期时间不能为空")
+ @Schema(description = "到期时间")
+ private String endTime;
+}
diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/message/LicencesMessage.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/message/LicencesMessage.java
new file mode 100644
index 0000000..15ba2db
--- /dev/null
+++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/mq/message/LicencesMessage.java
@@ -0,0 +1,13 @@
+package com.win.module.eam.mq.message;
+
+import lombok.Data;
+import lombok.ToString;
+
+import java.util.List;
+
+@Data
+@ToString(callSuper = true)
+public class LicencesMessage {
+ private String secretKey;
+ private String data;
+}
diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesService.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesService.java
new file mode 100644
index 0000000..68f9eb2
--- /dev/null
+++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesService.java
@@ -0,0 +1,11 @@
+package com.win.module.eam.service.licences;
+
+import com.win.module.eam.controller.licences.vo.GenerateLicenceReqVO;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+
+public interface LicencesService {
+ void licencesDiscern(String encryptionStr);
+ void generateLicence(@Valid GenerateLicenceReqVO req, HttpServletResponse response) throws Exception;
+}
\ No newline at end of file
diff --git a/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesServiceImpl.java b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesServiceImpl.java
new file mode 100644
index 0000000..ebb1fd1
--- /dev/null
+++ b/win-module-eam/win-module-eam-biz/src/main/java/com/win/module/eam/service/licences/LicencesServiceImpl.java
@@ -0,0 +1,108 @@
+package com.win.module.eam.service.licences;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.crypto.digest.MD5;
+import cn.hutool.extra.qrcode.QrCodeUtil;
+import cn.hutool.extra.qrcode.QrConfig;
+import com.alibaba.excel.metadata.data.ImageData;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.win.module.eam.controller.licences.vo.GenerateLicenceReqVO;
+import com.win.module.eam.mq.message.LicencesMessage;
+import org.apache.calcite.util.Util;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.http.HttpServletResponse;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.win.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static com.win.module.eam.enums.ErrorCodeConstants.ENCRYPTION_STR_FORMAT_IS_ERROR;
+
+@Service
+public class LicencesServiceImpl implements LicencesService {
+ private static final String ALGORITHM = "AES";
+ private static final int KEY_SIZE = 128;
+ private static final String LICENCES_UPDATE = "LICENCES";
+ @Resource
+ private RedisTemplate redisTemplate;
+
+ private static String generateKey() throws Exception {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
+ keyGenerator.init(KEY_SIZE);
+ SecretKey secretKey = keyGenerator.generateKey();
+ return Base64.encode(secretKey.getEncoded());
+ }
+
+ private static String encrypt(String data, String key) throws Exception {
+ SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.decode(key), ALGORITHM);
+ Cipher cipher = Cipher.getInstance(ALGORITHM);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
+ byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
+ return Base64.encode(encryptedBytes);
+ }
+
+ private static String decrypt(String encryptedData, String key) throws Exception {
+ SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.decode(key), ALGORITHM);
+ Cipher cipher = Cipher.getInstance(ALGORITHM);
+ cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
+ byte[] decryptedBytes = cipher.doFinal(Base64.decode(encryptedData));
+ return new String(decryptedBytes, StandardCharsets.UTF_8);
+ }
+
+ @Override
+ public void licencesDiscern(String encryptionStr) {
+ if (Util.isNullOrEmpty(encryptionStr)) {
+ throw exception(ENCRYPTION_STR_FORMAT_IS_ERROR);
+ }
+ try {
+ //todo 数据校验
+ JSONObject codeJson = JSONObject.parseObject(encryptionStr);
+ String secretKey = codeJson.getString("secretKey");
+ if (Util.isNullOrEmpty(secretKey)) {
+ throw exception(ENCRYPTION_STR_FORMAT_IS_ERROR);
+ }
+ String dataStr = codeJson.getString("data");
+ if (Util.isNullOrEmpty(dataStr)) {
+ throw exception(ENCRYPTION_STR_FORMAT_IS_ERROR);
+ }
+ JSONArray dataJson = JSONArray.parseArray(decrypt(dataStr, secretKey));
+ if (dataJson.isEmpty()) {
+ throw exception(ENCRYPTION_STR_FORMAT_IS_ERROR);
+ }
+ //todo 更新到redis并使用发布订阅通知其他pods
+ redisTemplate.opsForValue().set(LICENCES_UPDATE, dataJson.toJSONString());
+ redisTemplate.convertAndSend(LICENCES_UPDATE, 1);
+ } catch (Exception e) {
+ throw exception(500, e);
+ }
+ }
+
+ @Override
+ public void generateLicence(GenerateLicenceReqVO req, HttpServletResponse response) throws Exception {
+ LicencesMessage licencesMessage = new LicencesMessage() {{
+ String secretKey = generateKey();
+ setSecretKey(secretKey);
+ List data = new ArrayList();
+ MD5 md5 = MD5.create();
+ data.add(new JSONObject(){{
+ put(md5.digestHex("/MES"),encrypt("2025-10-10 00:00:00",secretKey));
+ }}.toJSONString());
+ data.add(new JSONObject(){{
+ put(md5.digestHex("/WMS"),encrypt("2025-10-10 00:00:00",secretKey));
+ }}.toJSONString());
+ setData(encrypt(JSONObject.toJSONString(data),secretKey));
+ }};
+ QrConfig config = new QrConfig(300, 300);
+ config.setErrorCorrection(com.google.zxing.qrcode.decoder.ErrorCorrectionLevel.M); // 设置纠错级别
+ // 或者直接输出到流
+ QrCodeUtil.generate(JSONObject.toJSONString(licencesMessage), config, ImageData.ImageType.PICTURE_TYPE_DIB.name(), response.getOutputStream());
+ }
+}