ltkj-admin/src/main/java/com/ltkj/web/controller/lis/LisApiMethod.java
@@ -2,8 +2,6 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.pinyin.PinyinUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; @@ -11,9 +9,9 @@ import com.ltkj.common.core.domain.AjaxResult; import com.ltkj.common.utils.AgeResult; import com.ltkj.common.utils.DateUtils; import com.ltkj.common.utils.IdUtils; import com.ltkj.hosp.domain.*; import com.ltkj.hosp.hisDto.OutpintestapplyDetailsDto; import com.ltkj.hosp.idutil.IdUtils; import com.ltkj.hosp.lisDto.LisSaveSqdxxDto; import com.ltkj.hosp.lisDto.LisSaveSqdxxJyxmlistDto; import com.ltkj.hosp.mapper.TbTransitionMapper; ltkj-admin/src/main/java/com/ltkj/web/controller/service/TjSysAsyncServiceImpl.java
@@ -1,6 +1,5 @@ package com.ltkj.web.controller.service; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.IdUtil; @@ -8,19 +7,17 @@ import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.alibaba.druid.sql.visitor.functions.If; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.ltkj.common.core.domain.AjaxResult; import com.ltkj.common.core.domain.entity.SysDept; import com.ltkj.common.core.domain.entity.SysUser; import com.ltkj.common.core.redis.RedisCache; import com.ltkj.common.utils.IdUtils; import com.ltkj.common.utils.StringUtils; import com.ltkj.framework.config.MatchUtils; import com.ltkj.framework.datasource.DynamicDataSourceContextHolder; import com.ltkj.hosp.domain.*; import com.ltkj.hosp.hisDto.*; import com.ltkj.hosp.idutil.IdUtils; import com.ltkj.hosp.mapper.TjSamplingMapper; import com.ltkj.hosp.pacsDto.SavePacsApply; import com.ltkj.hosp.service.*; @@ -38,10 +35,8 @@ import com.ltkj.web.controller.lis.LisApiMethod; import com.ltkj.web.controller.pacs.PacsApiMethodService; import com.ltkj.web.controller.system.SamplingServiceApi; import jodd.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -49,8 +44,6 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; ltkj-admin/src/main/java/com/ltkj/web/controller/system/TjOrderController.java
@@ -56,6 +56,7 @@ import com.ltkj.hosp.dto.UpdateTransitionnewPriceDto; import com.ltkj.hosp.hisDto.OutpinimpapplyDto; import com.ltkj.hosp.hisDto.OutpinmedicapplyDto; import com.ltkj.hosp.idutil.IdUtils; import com.ltkj.hosp.mapper.TbTransitionMapper; import com.ltkj.hosp.mapper.TestMapper; import com.ltkj.hosp.mapper.TjSamplingMapper; @@ -1107,10 +1108,36 @@ // String tjNumber = (SecurityUtils.getUsername() + idUtils.getTjNumber()); String tjNumber = idUtils.getTjNumber(); if (StringUtil.isNotBlank(makeLisTmhPrefix)) tjNumber = makeLisTmhPrefix + tjNumber; tjOrder.setTjNumber(tjNumber); // String tjNumber = idUtils.getTjNumber(); String tjNumber = null; int a =0; while (tjNumber ==null){ if(a>3){ throw new RuntimeException("前方拥挤,请稍等!!!"); } try { String newTjNumberRedisLockAndMysql = idUtils.getNewTjNumberRedisLockAndMysql(); if (StringUtil.isNotBlank(makeLisTmhPrefix)){ String tjh= makeLisTmhPrefix + newTjNumberRedisLockAndMysql; int countByTjNum = tjOrderService.getOrderCountByTjNum(tjh); if(countByTjNum==0){ tjNumber=tjh; } }else { int countByTjNum = tjOrderService.getOrderCountByTjNum(newTjNumberRedisLockAndMysql); if(countByTjNum==0){ tjNumber=newTjNumberRedisLockAndMysql; } } } catch (Exception e) { log.error(e.getMessage()); }finally { a++; } } tjOrder.setTjNumber(tjNumber); BigDecimal discount = BigDecimal.valueOf(Double.parseDouble(tjOrder.getTjFlowingWater().getDiscount())); tjOrder.setDiscount(discount.toString()); ltkj-admin/src/main/java/com/ltkj/web/controller/system/TjSamplingController.java
@@ -4,20 +4,13 @@ import java.util.*; import java.util.stream.Collectors; import javax.annotation.Resource; import javax.servlet.ServletSecurityElement; import javax.servlet.http.HttpServletResponse; import javax.swing.plaf.basic.BasicScrollPaneUI; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.pinyin.PinyinUtil; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ltkj.common.core.redis.RedisCache; import com.ltkj.common.utils.IdUtils; import com.ltkj.framework.config.MatchUtils; import com.ltkj.hosp.domain.*; import com.ltkj.hosp.service.*; @@ -28,12 +21,8 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.aspectj.weaver.AjAttribute; import org.springframework.beans.BeanUtils; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; import org.springframework.web.bind.annotation.*; import com.ltkj.common.annotation.Log; import com.ltkj.common.core.controller.BaseController; ltkj-admin/src/test/java/zjhTest.java
@@ -2,6 +2,7 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.extra.pinyin.PinyinUtil; import cn.hutool.json.JSONUtil; import com.ltkj.LtkjApplication; import com.ltkj.hosp.domain.TjProject; import com.ltkj.hosp.service.*; @@ -31,6 +32,7 @@ import java.net.URL; import java.time.LocalTime; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.List; import java.io.BufferedReader; import java.io.InputStreamReader; @@ -130,20 +132,11 @@ // BigDecimal multiply = ordPrice.multiply((new BigDecimal("6.5").divide(BigDecimal.valueOf(10)))); // System.out.println(multiply); String a="主动脉硬化;\n" + "左心舒张功能减低、收缩功能正常;\n" + "彩色血流示:各瓣膜未见病理性返流。"; // String s = a.replaceAll("[((][^))]*[\u4e00-\u9fa5]+[^))]*[))]", "") // .replaceAll("[ 测定检测]", ""); String input = "胆囊结石 胆囊壁内结石"; // 输入字符串 String[] split = a.replaceAll("\n", "").split("。|;|;"); for (String jg : split) { if (StringUtil.isNotBlank(jg) && !jg.contains("未见异常") && !jg.contains("未见明显异常") && !jg.contains("未见占位") && !jg.contains("未见") && !jg.contains("未见明显")&& !jg.contains("正常")&& !jg.contains("双侧椎间孔无狭窄")&& !jg.contains("无殊")) { System.out.println(jg); } } // 使用正则替换最后一个斜杠 String[] split = input.replaceAll("\n", "").split("。|;|;"); System.out.println(JSONUtil.parse(split)); // 输出结果 // System.out.println(s); } ltkj-common/src/main/java/com/ltkj/common/utils/IdUtils.java
File was deleted ltkj-hosp/src/main/java/com/ltkj/hosp/idutil/IdUtils.java
New file @@ -0,0 +1,240 @@ package com.ltkj.hosp.idutil; import cn.hutool.core.util.StrUtil; import com.ltkj.hosp.mapper.OrderNumberMapper; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.core.StringRedisTemplate; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * @Company: 西安路泰科技有限公司 * @Author: zhaowenxuan * @Date: 2024/10/10 14:55 */ @Configuration @Slf4j public class IdUtils { private static final String LIS_LAST_ID_KEY = "id:generate:lis:id"; private static final String TJH_LAST_ID_KEY = "id:generate:tjhs:tjh"; private static final String LIS_LAST_ID_INCR_KEY = "id:generate:lis:id:incr"; private static final String LIS_CURRENT_DATE_KEY = "id:generate:lis:currentDate"; @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private OrderNumberMapper orderNumberMapper; @Autowired private RedissonClient redissonClient; public synchronized String yuangenerateLisID(String prefix) { String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date()); String storedDate = stringRedisTemplate.opsForValue().get(LIS_CURRENT_DATE_KEY); String lastIdStr = stringRedisTemplate.opsForValue().get(LIS_LAST_ID_KEY); int lastId; if (storedDate == null || !storedDate.equals(currentDate)) { lastId = 1; stringRedisTemplate.opsForValue().set(LIS_LAST_ID_KEY, String.valueOf(lastId)); stringRedisTemplate.opsForValue().set(LIS_CURRENT_DATE_KEY, currentDate); } else { lastId = Integer.parseInt(lastIdStr) + 1; stringRedisTemplate.opsForValue().set(LIS_LAST_ID_KEY, String.valueOf(lastId)); } String yyMMdd = currentDate.substring(2); return String.format(prefix+"%s%05d", yyMMdd, lastId); } //redis分布式锁和MySQL公用 public String generateLisID(String prefix) { String lockKey = "lock:tmh:tj_tmh_lock"; RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(3, 5, TimeUnit.SECONDS)) { String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date()); String storedDate = stringRedisTemplate.opsForValue().get(LIS_CURRENT_DATE_KEY); String lastIdStr = stringRedisTemplate.opsForValue().get(LIS_LAST_ID_KEY); // 2. 如果 Redis 中没有或者编号丢失,查询数据库并同步到 Redis if (storedDate == null || !storedDate.equals(currentDate) || lastIdStr == null) { Integer lastIdFromDb = orderNumberMapper.getLastId(currentDate,lockKey); lastIdFromDb = (lastIdFromDb == null) ? 0 : lastIdFromDb; // 同步到 Redis stringRedisTemplate.opsForValue().set(LIS_LAST_ID_KEY, String.valueOf(lastIdFromDb), 1, TimeUnit.DAYS); stringRedisTemplate.opsForValue().set(LIS_CURRENT_DATE_KEY, currentDate, 1, TimeUnit.DAYS); } // 3. 使用 Redis 的 INCR 保证流水号唯一 long lastId = stringRedisTemplate.opsForValue().increment(LIS_LAST_ID_KEY); // 4. 同时更新数据库,确保一致性 orderNumberMapper.updateLastId(currentDate, (int) lastId,lockKey); return String.format(prefix+"%s%05d", currentDate.substring(2), lastId); } else { throw new RuntimeException("获取条码号失败,请重试"); } } catch (InterruptedException e) { throw new RuntimeException(e); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } /** * 生成无限递增条码号 * @param prefix * @return */ public synchronized String generateLisNextId(String prefix){ String lastIdStr = stringRedisTemplate.opsForValue().get(LIS_LAST_ID_INCR_KEY); int current; if (StrUtil.isBlank(lastIdStr)) { current = 1; }else { current = Integer.parseInt(lastIdStr); } int numberLength = String.valueOf(99999).length(); String result = prefix + String.format("%0" + numberLength + "d", current); current++; stringRedisTemplate.opsForValue().set(LIS_LAST_ID_INCR_KEY,String.valueOf(current)); return result; } //生成体检号用 private static long lastTimestamp = -1; private static final Random random = new Random(); // public static synchronized String getTjNumber() { // long timestamp = System.currentTimeMillis(); // 获取当前时间戳(毫秒) // // // 如果时间戳和上次生成的时间戳相同,生成一个新的随机数 // if (timestamp == lastTimestamp) { // return String.format("%09d", (timestamp % 1000000000) + random.nextInt(900) + 100); // } else { // lastTimestamp = timestamp; // 更新最后生成时间戳 // return String.format("%09d", (timestamp % 1000000000) + random.nextInt(900) + 100); // } // } public synchronized String getTjNumber() { String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date()); String storedDate = stringRedisTemplate.opsForValue().get(LIS_CURRENT_DATE_KEY); String lastIdStr = stringRedisTemplate.opsForValue().get(TJH_LAST_ID_KEY); if (StrUtil.isBlank(lastIdStr))lastIdStr = "0"; int lastId; if (storedDate == null || !storedDate.equals(currentDate)) { lastId = 1; stringRedisTemplate.opsForValue().set(TJH_LAST_ID_KEY, String.valueOf(lastId)); stringRedisTemplate.opsForValue().set(LIS_CURRENT_DATE_KEY, currentDate); } else { lastId = Integer.parseInt(lastIdStr) + 1; stringRedisTemplate.opsForValue().set(TJH_LAST_ID_KEY, String.valueOf(lastId)); } String yyMMdd = currentDate.substring(2); return String.format("%s%05d", yyMMdd, lastId); } // 使用分布式ID生成器(如Snowflake) public static String generateExamNumber() { // long id = uidGenerator.getUID(); // 获取生成的唯一ID // return String.format("%09d", Math.abs(id) % 1000000000); // 格式化为9位 return null; } // redis分布式锁 public String getNewTjNumberRedisLock() { String lockKey = "lock:tjh:tj_number_lock"; String lockValue = UUID.randomUUID().toString(); Boolean locked = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 5, TimeUnit.SECONDS); if (Boolean.TRUE.equals(locked)) { try { String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date()); String storedDate = stringRedisTemplate.opsForValue().get(LIS_CURRENT_DATE_KEY); if (storedDate == null || !storedDate.equals(currentDate)) { // 日期变更,重置 Redis 计数器 stringRedisTemplate.opsForValue().set(TJH_LAST_ID_KEY, "1", 1, TimeUnit.DAYS); stringRedisTemplate.opsForValue().set(LIS_CURRENT_DATE_KEY, currentDate, 1, TimeUnit.DAYS); return String.format("%s%05d", currentDate.substring(2), 1); } // 使用 Redis INCR 确保唯一性 long lastId = stringRedisTemplate.opsForValue().increment(TJH_LAST_ID_KEY); return String.format("%s%05d", currentDate.substring(2), lastId); } finally { // 释放锁(确保是当前线程持有的锁才删除) String currentLockValue = stringRedisTemplate.opsForValue().get(lockKey); if (lockValue.equals(currentLockValue)) { stringRedisTemplate.delete(lockKey); } } } else { throw new RuntimeException("获取流水号失败,请重试"); } } //redis分布式锁和MySQL公用 public String getNewTjNumberRedisLockAndMysql() { String lockKey = "lock:tjh:tj_number_lock"; RLock lock = redissonClient.getLock(lockKey); try { if (lock.tryLock(5, 10, TimeUnit.SECONDS)) { String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date()); // 1. 先从 Redis 获取编号 String storedDate = stringRedisTemplate.opsForValue().get(LIS_CURRENT_DATE_KEY); String lastIdStr = stringRedisTemplate.opsForValue().get(TJH_LAST_ID_KEY); // 2. 如果 Redis 中没有或者编号丢失,查询数据库并同步到 Redis if (storedDate == null || !storedDate.equals(currentDate) || lastIdStr == null) { Integer lastIdFromDb = orderNumberMapper.getLastId(currentDate,lockKey); lastIdFromDb = (lastIdFromDb == null) ? 0 : lastIdFromDb; // 同步到 Redis stringRedisTemplate.opsForValue().set(TJH_LAST_ID_KEY, String.valueOf(lastIdFromDb), 1, TimeUnit.DAYS); stringRedisTemplate.opsForValue().set(LIS_CURRENT_DATE_KEY, currentDate, 1, TimeUnit.DAYS); } // 3. 使用 Redis 的 INCR 保证流水号唯一 long lastId = stringRedisTemplate.opsForValue().increment(TJH_LAST_ID_KEY); // 4. 同时更新数据库,确保一致性 orderNumberMapper.updateLastId(currentDate, (int) lastId,lockKey); return String.format("%s%05d", currentDate.substring(2), lastId); } else { throw new RuntimeException("获取体检号失败,请重试"); } } catch (InterruptedException e) { throw new RuntimeException(e); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } } ltkj-hosp/src/main/java/com/ltkj/hosp/mapper/OrderNumberMapper.java
New file @@ -0,0 +1,17 @@ package com.ltkj.hosp.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.poi.ss.formula.functions.T; @Mapper public interface OrderNumberMapper extends BaseMapper<T> { @Select("SELECT max(last_id) FROM order_number WHERE date_key = #{dateKey} and fl=#{fl}") Integer getLastId(@Param("dateKey") String dateKey,@Param("fl") String fl); @Insert("INSERT INTO order_number(date_key, last_id,fl) VALUES(#{dateKey}, #{lastId},#{fl}) ON DUPLICATE KEY UPDATE last_id = #{lastId}") void updateLastId(@Param("dateKey") String dateKey, @Param("lastId") int lastId,@Param("fl") String fl); } ltkj-hosp/src/main/java/com/ltkj/hosp/mapper/TjOrderMapper.java
@@ -386,4 +386,8 @@ " a.deleted = 0 \n" + " AND b.org_type = 2 \n") List<String> getJianChaTjNum(); @Select("SELECT count(*) FROM tj_order WHERE tj_number = #{tjNum}") int getOrderCountByTjNum(String tjNum); } ltkj-hosp/src/main/java/com/ltkj/hosp/service/ITjOrderService.java
@@ -188,4 +188,6 @@ void tjLispacstongbujianyi(String tjNumber, Long deptId,String nickName, Long userId); Map<String, Object> getTjBgdyList(Integer pageNum, Integer pageSize, Integer dyzt, String tjNum, String name, String dw, String djbeginTime, String djendTime); int getOrderCountByTjNum(String tjh); } ltkj-hosp/src/main/java/com/ltkj/hosp/service/impl/TjOrderServiceImpl.java
@@ -449,4 +449,8 @@ map1.put("total",map.get("total")); return map1; } @Override public int getOrderCountByTjNum(String tjNum) { return tjOrderMapper.getOrderCountByTjNum(tjNum); } } ltkj-hosp/src/main/java/com/ltkj/hosp/service/impl/TjSamplingServiceImpl.java
@@ -1,19 +1,14 @@ package com.ltkj.hosp.service.impl; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ltkj.common.core.domain.AjaxResult; import com.ltkj.common.utils.DateUtils; import com.ltkj.common.utils.IdUtils; import com.ltkj.hosp.domain.TjCustomer; import com.ltkj.hosp.domain.TjOrder; import com.ltkj.hosp.idutil.IdUtils; import com.ltkj.hosp.service.ITjCustomerService; import com.ltkj.hosp.service.ITjOrderService; import lombok.extern.slf4j.Slf4j;