Просмотр исходного кода

新增镭雕客户编码生成接口
- 新增MesLaserService:21位客户编码生成规则(项目前缀+IS3031+年月日+当日流水号+01),
流水号用INSERT...ON DUPLICATE KEY UPDATE原子自增,避免工控机断电/本地计数丢失导致重复编码
- 新增MesLaserController:POST /mesLaser/genCustomerSn,供op40客户端调用
- 新表 mes_customer_sn_counter(当日流水号计数) mes_product_laser(钢印码与客户码绑定记录)

wangxichen 6 дней назад
Родитель
Сommit
5580681fd9

+ 141 - 0
src/main/java/com/jeesite/modules/mes/service/MesLaserService.java

@@ -0,0 +1,141 @@
+package com.jeesite.modules.mes.service;
+
+import com.jeesite.common.service.ServiceException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * 镭雕客户编码生成与绑定Service
+ * 客户编码规则(21位):
+ *   + 项目前缀(4位,T09=KB60/T68=KB87) + IS3031(6位固定)
+ *   + 年份字母(1位) + 月份代码(1位) + 日期(2位)
+ *   + 当日流水号(4位,从0001开始每日归零) + 01(2位固定原材料追溯码)
+ * @author hzd
+ * @version 2026-07-08
+ */
+@Service
+public class MesLaserService {
+
+	@Autowired
+	private JdbcTemplate jdbcTemplate;
+
+	// 项目前缀映射:prodCode -> 客户码前缀
+	private static final Map<String, String> PROD_PREFIX = new HashMap<>();
+	static {
+		PROD_PREFIX.put("T09", "KB60");
+		PROD_PREFIX.put("T68", "KB87");
+	}
+
+	// 月份代码:1-9月=数字1-9,10/11/12月=A/B/C
+	private static final String[] MONTH_CODE = {
+			"1","2","3","4","5","6","7","8","9","A","B","C"
+	};
+
+	// 年份字母锚点:2026年=T,按字母顺序连续递增/递减(未跳过易混淆字母,待与朱经理确认)
+	private static final int ANCHOR_YEAR = 2026;
+	private static final char ANCHOR_LETTER = 'T';
+
+	/**
+	 * 生成客户编码并与钢印码绑定,整个过程在一个事务里完成,原子性保证不会出现
+	 * 客户码生成了但绑定失败、或者钢印码被重复绑定的情况。
+	 * @param prodCode 产品标识 T09/T68
+	 * @param steelSn 钢印码(镭雕软件生成并回传)
+	 * @param oprno 工位号
+	 * @param lineSn 产线编号
+	 * @param userCode 操作员
+	 * @return 生成的21位客户编码
+	 */
+	@Transactional
+	public String genAndBindCustomerSn(String prodCode, String steelSn, String oprno, String lineSn, String userCode) {
+		String prefix = PROD_PREFIX.get(prodCode);
+		if (prefix == null) {
+			throw new ServiceException("产品标识不正确,未识别的prodCode:" + prodCode);
+		}
+
+		// 钢印码不能重复绑定
+		Integer existCount = jdbcTemplate.queryForObject(
+				"SELECT COUNT(1) FROM mes_product_laser WHERE steel_sn = ?",
+				Integer.class, steelSn);
+		if (existCount != null && existCount > 0) {
+			throw new ServiceException("该钢印码已绑定过客户编码,不能重复绑定");
+		}
+
+		String customerSn = genCustomerSn(prodCode, prefix);
+
+		// 绑定保存
+		jdbcTemplate.update(
+				"INSERT INTO mes_product_laser(id,prod_code,customer_sn,steel_sn,oprno,line_sn,create_by,create_date,update_by,update_date) " +
+						"VALUES (?,?,?,?,?,?,?,now(),?,now())",
+				UUID.randomUUID().toString().replace("-", ""), prodCode, customerSn, steelSn, oprno, lineSn, userCode, userCode);
+
+		return customerSn;
+	}
+
+	/**
+	 * 只生成客户编码,不做绑定(预留,正常流程走 genAndBindCustomerSn)
+	 */
+	@Transactional
+	public String genCustomerSn(String prodCode, String prefix) {
+		if (prefix == null) {
+			prefix = PROD_PREFIX.get(prodCode);
+		}
+		if (prefix == null) {
+			throw new ServiceException("产品标识不正确,未识别的prodCode:" + prodCode);
+		}
+
+		Date now = new Date();
+		String seqDate = new SimpleDateFormat("yyyyMMdd").format(now);
+
+		// 原子自增当日流水号:INSERT...ON DUPLICATE KEY UPDATE 一步完成新增/累加并取回新值
+		jdbcTemplate.update(
+				"INSERT INTO mes_customer_sn_counter(prod_code,seq_date,cur_num,update_date) VALUES (?,?,1,now()) " +
+						"ON DUPLICATE KEY UPDATE cur_num = LAST_INSERT_ID(cur_num + 1), update_date = now()",
+				prodCode, seqDate);
+		Long curNum = jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
+		if (curNum == null || curNum < 1) {
+			throw new ServiceException("生成流水号失败");
+		}
+		if (curNum > 9999) {
+			throw new ServiceException("当日流水号已超过9999,无法继续生成客户编码");
+		}
+
+		String dateCode = getYearLetter(now) + getMonthCode(now) + getDayStr(now);
+		String serialStr = String.format("%04d", curNum);
+
+		return "+" + prefix + "IS3031" + dateCode + serialStr + "01";
+	}
+
+	// 年份字母:以2026=T为锚点,按字母顺序连续推算(不跳过易混淆字母,仅为当前实现假设)
+	private String getYearLetter(Date date) {
+		Calendar c = Calendar.getInstance();
+		c.setTime(date);
+		int year = c.get(Calendar.YEAR);
+		int diff = year - ANCHOR_YEAR;
+		char letter = (char) (ANCHOR_LETTER + diff);
+		return String.valueOf(letter);
+	}
+
+	private String getMonthCode(Date date) {
+		Calendar c = Calendar.getInstance();
+		c.setTime(date);
+		int month = c.get(Calendar.MONTH); // 0-11
+		return MONTH_CODE[month];
+	}
+
+	private String getDayStr(Date date) {
+		Calendar c = Calendar.getInstance();
+		c.setTime(date);
+		int day = c.get(Calendar.DAY_OF_MONTH);
+		return String.format("%02d", day);
+	}
+
+}

+ 69 - 0
src/main/java/com/jeesite/modules/mes/web/MesLaserController.java

@@ -0,0 +1,69 @@
+package com.jeesite.modules.mes.web;
+
+import javax.servlet.http.HttpServletRequest;
+
+import com.jeesite.common.lang.StringUtils;
+import com.jeesite.common.service.ServiceException;
+import com.jeesite.modules.mes.resp.CommonResp;
+import com.jeesite.modules.mes.service.MesLaserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.jeesite.common.config.Global;
+import com.jeesite.common.web.BaseController;
+
+/**
+ * 镭雕对接Controller(OP040)
+ * MES客户端拿到镭雕软件回传的钢印码后,调用本接口生成并绑定21位客户编码。
+ * @author hzd
+ * @version 2026-07-08
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/mes/mesLaser")
+public class MesLaserController extends BaseController {
+
+	@Autowired
+	private MesLaserService mesLaserService;
+
+	/**
+	 * 生成客户编码并与钢印码绑定
+	 * 请求参数(form):prodCode(T09/T68) steelSn(钢印码) oprno lineSn user
+	 * 返回 data:客户编码(21位)
+	 */
+	@PostMapping(value = "genCustomerSn")
+	@ResponseBody
+	public CommonResp genCustomerSn(HttpServletRequest request) {
+		CommonResp<String> resp = new CommonResp<>();
+		String prodCode = request.getParameter("prodCode");
+		String steelSn = request.getParameter("steelSn");
+		String oprno = request.getParameter("oprno");
+		String lineSn = request.getParameter("lineSn");
+		String user = request.getParameter("user");
+
+		if (StringUtils.isEmpty(prodCode) || StringUtils.isEmpty(steelSn)) {
+			resp.setResult(Global.FALSE);
+			resp.setMessage("参数错误:prodCode和steelSn不能为空");
+			return resp;
+		}
+
+		try {
+			String customerSn = mesLaserService.genAndBindCustomerSn(prodCode, steelSn, oprno, lineSn, user);
+			resp.setData(customerSn);
+			resp.setResult(Global.TRUE);
+			resp.setMessage("生成成功");
+		} catch (ServiceException e) {
+			resp.setResult(Global.FALSE);
+			resp.setMessage(e.getMessage());
+		} catch (Exception e) {
+			logger.error("生成客户编码失败:prodCode=" + prodCode + ", steelSn=" + steelSn, e);
+			resp.setResult(Global.FALSE);
+			resp.setMessage("生成失败:" + e.getMessage());
+		}
+
+		return resp;
+	}
+
+}