From d7cda8aec488caa2623547893d633063a09888e0 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期二, 16 六月 2026 09:39:47 +0800
Subject: [PATCH] ai数据自动生成
---
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java | 81 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 81 insertions(+), 0 deletions(-)
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
index 4f83c66..777438f 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -164,6 +164,9 @@
purchaseLedger.setApprovalStatus(1);
// 3. 鏂板鎴栨洿鏂颁富琛�
if (purchaseLedger.getId() == null) {
+ if (!StringUtils.hasText(purchaseLedger.getPurchaseContractNumber())) {
+ purchaseLedger.setPurchaseContractNumber(generatePurchaseContractNo(purchaseLedger.getEntryDate()));
+ }
purchaseLedgerMapper.insert(purchaseLedger);
} else {
// 鍒犻櫎閲囪喘瀹℃牳锛岄噸鏂版彁浜�
@@ -1073,4 +1076,82 @@
}
return sb.toString();
}
+
+ private static final String PURCHASE_LOCK_PREFIX = "purchase_contract_no:";
+ private static final long PURCHASE_LOCK_WAIT_TIMEOUT = 10;
+ private static final long PURCHASE_LOCK_EXPIRE_TIME = 30;
+
+ private String generatePurchaseContractNo(Date entryDate) {
+ LocalDate currentDate = entryDate != null ? DateUtils.toLocalDate(entryDate) : LocalDate.now();
+ String datePart = currentDate.format(DateTimeFormatter.BASIC_ISO_DATE);
+ String lockKey = PURCHASE_LOCK_PREFIX + datePart;
+ String lockValue = Thread.currentThread().getId() + "-" + System.nanoTime();
+
+ try {
+ long startWaitTime = System.currentTimeMillis();
+ while (System.currentTimeMillis() - startWaitTime < PURCHASE_LOCK_WAIT_TIMEOUT * 1000) {
+ Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, PURCHASE_LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
+ if (Boolean.TRUE.equals(locked)) {
+ break;
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new RuntimeException("鑾峰彇閿佹椂琚腑鏂�", e);
+ }
+ }
+
+ if (Boolean.FALSE.equals(redisTemplate.hasKey(lockKey))) {
+ throw new RuntimeException("鑾峰彇閲囪喘鍚堝悓缂栧彿鐢熸垚閿佸け璐ワ細瓒呮椂");
+ }
+
+ String prefix = "CG-" + datePart + "-";
+ List<PurchaseLedger> existingList = purchaseLedgerMapper.selectList(
+ new LambdaQueryWrapper<PurchaseLedger>()
+ .likeRight(PurchaseLedger::getPurchaseContractNumber, prefix)
+ .select(PurchaseLedger::getPurchaseContractNumber));
+ List<Integer> existingSequences = existingList.stream()
+ .map(PurchaseLedger::getPurchaseContractNumber)
+ .filter(Objects::nonNull)
+ .map(no -> {
+ int lastDash = no.lastIndexOf('-');
+ if (lastDash >= 0) {
+ try {
+ return Integer.parseInt(no.substring(lastDash + 1));
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+ return 0;
+ })
+ .collect(Collectors.toList());
+ int nextSequence = findFirstMissingSequence(existingSequences);
+
+ return prefix + String.format("%03d", nextSequence);
+ } finally {
+ String luaScript = "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end";
+ redisTemplate.execute(
+ new org.springframework.data.redis.core.script.DefaultRedisScript<>(luaScript, Long.class),
+ Collections.singletonList(lockKey),
+ lockValue
+ );
+ }
+ }
+
+ private int findFirstMissingSequence(List<Integer> sequences) {
+ if (sequences.isEmpty()) {
+ return 1;
+ }
+ sequences.sort(Integer::compareTo);
+ int next = 1;
+ for (int seq : sequences) {
+ if (seq == next) {
+ next++;
+ } else if (seq > next) {
+ break;
+ }
+ }
+ return next;
+ }
}
--
Gitblit v1.9.3