From b852254d90e7d1955db31db154193ec8ee84d8b3 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 09 九月 2026 10:57:59 +0800
Subject: [PATCH] feat(hrm): 新增员工用工性质、班组归属字段及考勤异常处理优化
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeServiceImpl.java | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 163 insertions(+), 8 deletions(-)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeServiceImpl.java
index 2dea524..23bc7d5 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeServiceImpl.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.mes.service.wm.barcode;
+import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
@@ -11,11 +12,26 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.barcode.MesWmBarcodeConfigDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.barcode.MesWmBarcodeDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.barcode.MesWmBarcodeMapper;
+import cn.iocoder.yudao.module.mes.enums.wm.BarcodeFormatEnum;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.client.j2se.MatrixToImageWriter;
+import com.google.zxing.common.BitMatrix;
import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -27,7 +43,13 @@
*/
@Service
@Validated
+@Slf4j
public class MesWmBarcodeServiceImpl implements MesWmBarcodeService {
+
+ /**
+ * 鍐呭鏍煎紡妯℃澘涓殑鍗犱綅绗﹁瘑鍒鍒�
+ */
+ private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\{[A-Za-z0-9_]+\\}");
@Resource
private MesWmBarcodeMapper barcodeMapper;
@@ -43,7 +65,8 @@
// 2. 鐢熸垚鏉$爜鍐呭锛屽苟鏍¢獙鍞竴鎬�
String content = generateAndValidateContent(createReqVO.getId(),
- createReqVO.getContent(), config.getContentFormat(), createReqVO.getBizCode());
+ createReqVO.getContent(), config.getContentFormat(), createReqVO.getBizCode(),
+ createReqVO.getBizName());
// 3. 淇濆瓨鏉$爜璁板綍
MesWmBarcodeDO barcode = BeanUtils.toBean(createReqVO, MesWmBarcodeDO.class).setContent(content)
@@ -53,7 +76,7 @@
}
@Override
- public String generateBarcodeContent(Integer bizType, String bizCode) {
+ public String generateBarcodeContent(Integer bizType, String bizCode, String bizName) {
// 1.1 鏍¢獙鍙傛暟
if (bizType == null) {
throw exception(BARCODE_BIZ_TYPE_NOT_EXISTS);
@@ -65,7 +88,7 @@
MesWmBarcodeConfigDO config = barcodeConfigService.validateBarcodeConfigByBizType(bizType);
// 2. 鐢熸垚鏉$爜鍐呭
- return generateBarcodeContent(config.getContentFormat(), bizCode);
+ return generateBarcodeContent(config.getContentFormat(), bizCode, bizName);
}
@Override
@@ -78,7 +101,8 @@
// 2. 鐢熸垚鏉$爜鍐呭锛屽苟鏍¢獙鍞竴鎬�
String content = generateAndValidateContent(updateReqVO.getId(),
- updateReqVO.getContent(), config.getContentFormat(), updateReqVO.getBizCode());
+ updateReqVO.getContent(), config.getContentFormat(), updateReqVO.getBizCode(),
+ updateReqVO.getBizName());
// 3. 鏇存柊锛堝埛鏂� configId 鍜� format锛岀‘淇濅笌鏈�鏂伴厤缃竴鑷达級
MesWmBarcodeDO updateObj = BeanUtils.toBean(updateReqVO, MesWmBarcodeDO.class)
@@ -131,10 +155,10 @@
* @param bizCode 涓氬姟缂栫爜
* @return 鏈�缁堟潯鐮佸唴瀹�
*/
- private String generateAndValidateContent(Long id, String content, String contentFormat, String bizCode) {
+ private String generateAndValidateContent(Long id, String content, String contentFormat, String bizCode, String bizName) {
// 1. 濡傛灉鍓嶇鏈紶閫掑唴瀹癸紝鍒欒嚜鍔ㄧ敓鎴�
if (StrUtil.isBlank(content)) {
- content = generateBarcodeContent(contentFormat, bizCode);
+ content = generateBarcodeContent(contentFormat, bizCode, bizName);
}
// 2. 鏍¢獙鏉$爜鍐呭鍞竴鎬э紙鎺掗櫎鑷韩锛�
if (StrUtil.isNotBlank(content)) {
@@ -151,13 +175,144 @@
*
* @param contentFormat 鍐呭鏍煎紡妯℃澘
* @param bizCode 涓氬姟缂栫爜
+ * @param bizName 涓氬姟鍚嶇О
* @return 鏉$爜鍐呭
*/
- private String generateBarcodeContent(String contentFormat, String bizCode) {
+ private String generateBarcodeContent(String contentFormat, String bizCode, String bizName) {
if (StrUtil.isBlank(contentFormat)) {
return bizCode;
}
- return contentFormat.replace(MesWmBarcodeConfigDO.PLACEHOLDER_BUSINESS_CODE, bizCode);
+ // 1. 鏇挎崲宸叉敮鎸佺殑鍗犱綅绗�
+ String content = contentFormat
+ .replace(MesWmBarcodeConfigDO.PLACEHOLDER_BUSINESS_CODE, StrUtil.nullToEmpty(bizCode))
+ .replace(MesWmBarcodeConfigDO.PLACEHOLDER_BUSINESS_NAME, StrUtil.nullToEmpty(bizName));
+ // 2. 娓呯┖妯℃澘涓叾瀹冩湭濉厖鐨勬湭鐭ュ崰浣嶇锛岄伩鍏� {XXX} 娈嬬暀褰卞搷鎵爜
+ return PLACEHOLDER_PATTERN.matcher(content).replaceAll("");
+ }
+
+ @Override
+ public String renderBarcodeImage(String content, Integer format, Integer width, Integer height) {
+ if (StrUtil.isBlank(content)) {
+ throw exception(BARCODE_CONTENT_EMPTY);
+ }
+ int w = width != null && width > 0 ? width : 200;
+ int h = height != null && height > 0 ? height : 200;
+ try {
+ BitMatrix bitMatrix = new MultiFormatWriter().encode(content, toZxingFormat(format), w, h);
+ BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ImageIO.write(image, "png", out);
+ return "data:image/png;base64," + Base64.encode(out.toByteArray());
+ } catch (Exception e) {
+ log.error("[renderBarcodeImage] 鏉$爜娓叉煋澶辫触锛宑ontent={}, format={}", content, format, e);
+ throw new RuntimeException("鏉$爜娓叉煋澶辫触");
+ }
+ }
+
+ /**
+ * 灏嗛」鐩潯鐮佹牸寮忔灇涓惧�兼槧灏勪负 zxing 鏉$爜鏍煎紡
+ *
+ * @param format 椤圭洰鏉$爜鏍煎紡 {@link BarcodeFormatEnum}
+ * @return zxing 鏉$爜鏍煎紡
+ */
+ private BarcodeFormat toZxingFormat(Integer format) {
+ if (format == null) {
+ return BarcodeFormat.CODE_128;
+ }
+ switch (format) {
+ case 1: // BarcodeFormatEnum.QR_CODE
+ return BarcodeFormat.QR_CODE;
+ case 2: // BarcodeFormatEnum.EAN13
+ return BarcodeFormat.EAN_13;
+ case 3: // BarcodeFormatEnum.CODE39
+ return BarcodeFormat.CODE_39;
+ case 4: // BarcodeFormatEnum.UPC_A
+ return BarcodeFormat.UPC_A;
+ default:
+ throw exception(BARCODE_FORMAT_INVALID);
+ }
+ }
+
+ @Override
+ public Map<String, Object> parseBarcodeContent(String content) {
+ if (StrUtil.isBlank(content)) {
+ throw exception(BARCODE_CONTENT_EMPTY);
+ }
+ // 1. 浼樺厛鎸夋潯鐮佸唴瀹圭簿纭懡涓凡鏈夋潯鐮佽褰�
+ MesWmBarcodeDO barcode = barcodeMapper.selectByContent(content);
+ if (barcode != null) {
+ Map<String, Object> result = new LinkedHashMap<>();
+ result.put("matched", true);
+ result.put("barcodeId", barcode.getId());
+ result.put("configId", barcode.getConfigId());
+ result.put("format", barcode.getFormat());
+ result.put("bizType", barcode.getBizType());
+ result.put("bizId", barcode.getBizId());
+ result.put("bizCode", barcode.getBizCode());
+ result.put("bizName", barcode.getBizName());
+ result.put("content", barcode.getContent());
+ return result;
+ }
+ // 2. 鏈懡涓椂锛岄亶鍘嗗惎鐢ㄧ姸鎬佺殑閰嶇疆鎸夊唴瀹规牸寮忔ā鏉垮弽瑙�
+ List<MesWmBarcodeConfigDO> configs = barcodeConfigService.getEnableBarcodeConfigList();
+ for (MesWmBarcodeConfigDO config : configs) {
+ Map<String, Object> fields = matchByTemplate(config.getContentFormat(), content);
+ if (fields != null) {
+ Map<String, Object> result = new LinkedHashMap<>();
+ result.put("matched", false);
+ result.put("configId", config.getId());
+ result.put("format", config.getFormat());
+ result.put("bizType", config.getBizType());
+ result.put("bizCode", fields.get(MesWmBarcodeConfigDO.PLACEHOLDER_BUSINESS_CODE));
+ result.put("bizName", fields.get(MesWmBarcodeConfigDO.PLACEHOLDER_BUSINESS_NAME));
+ result.put("fields", fields);
+ return result;
+ }
+ }
+ // 3. 鍧囨湭鍛戒腑
+ Map<String, Object> result = new LinkedHashMap<>();
+ result.put("matched", false);
+ result.put("content", content);
+ return result;
+ }
+
+ /**
+ * 鎸夊唴瀹规牸寮忔ā鏉垮弽瑙f潯鐮佸唴瀹�
+ *
+ * @param contentFormat 鍐呭鏍煎紡妯℃澘
+ * @param content 寰呰В鏋愮殑鏉$爜鍐呭
+ * @return 鍗犱綅绗� -> 瀹為檯鍊肩殑鏄犲皠锛涗笉鍖归厤杩斿洖 null
+ */
+ private Map<String, Object> matchByTemplate(String contentFormat, String content) {
+ if (StrUtil.isBlank(contentFormat) || !contentFormat.contains("{")) {
+ return null;
+ }
+ // 1. 灏嗘ā鏉胯浆涓烘鍒欙細瀛楅潰閲忚浆涔夛紝鍗犱綅绗﹁浆涓烘崟鑾风粍
+ List<String> placeholders = new ArrayList<>();
+ StringBuilder regexSb = new StringBuilder();
+ Matcher matcher = PLACEHOLDER_PATTERN.matcher(contentFormat);
+ int lastEnd = 0;
+ while (matcher.find()) {
+ regexSb.append(Pattern.quote(contentFormat.substring(lastEnd, matcher.start())));
+ placeholders.add(matcher.group());
+ regexSb.append("(.+?)");
+ lastEnd = matcher.end();
+ }
+ if (placeholders.isEmpty()) {
+ return null;
+ }
+ regexSb.append(Pattern.quote(contentFormat.substring(lastEnd)));
+
+ // 2. 鍏ㄩ噺鍖归厤骞舵彁鍙栧悇鍗犱綅绗﹀��
+ Matcher contentMatcher = Pattern.compile(regexSb.toString()).matcher(content);
+ if (!contentMatcher.matches()) {
+ return null;
+ }
+ Map<String, Object> fields = new LinkedHashMap<>();
+ for (int i = 0; i < placeholders.size(); i++) {
+ fields.put(placeholders.get(i), contentMatcher.group(i + 1));
+ }
+ return fields;
}
@Override
--
Gitblit v1.9.3