package com.qianwen.smartman.common.cache.cps; import cn.hutool.core.date.DateTime; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.google.common.collect.Lists; import java.lang.invoke.SerializedLambda; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Comparator; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.qianwen.smartman.common.constant.ProductionTimeConstant; import com.qianwen.smartman.common.utils.CommonUtil; import com.qianwen.smartman.common.utils.LocalDateUtil; import com.qianwen.smartman.common.utils.MessageUtils; import com.qianwen.core.redis.cache.BladeRedis; import com.qianwen.core.secure.utils.AuthUtil; import com.qianwen.core.tool.support.Kv; import com.qianwen.core.tool.utils.DateUtil; import com.qianwen.core.tool.utils.Func; import com.qianwen.core.tool.utils.SpringUtil; import com.qianwen.smartman.modules.cps.dto.CacheBuildDTO; import com.qianwen.smartman.modules.cps.dto.CalendarShiftTimeSlicesDTO; import com.qianwen.smartman.modules.cps.dto.CurrentShiftInfoDTO; import com.qianwen.smartman.modules.cps.dto.TimestampToProductionTimeCacheDto; import com.qianwen.smartman.modules.cps.entity.ProductionCalendar; import com.qianwen.smartman.modules.cps.entity.ProductionCalendarDay; import com.qianwen.smartman.modules.cps.entity.ProductionCalendarDaytime; import com.qianwen.smartman.modules.cps.entity.ShiftDetail; import com.qianwen.smartman.modules.cps.service.ICalendarDayService; import com.qianwen.smartman.modules.cps.service.ICalendarDaytimeService; import com.qianwen.smartman.modules.cps.service.ICalendarService; import com.qianwen.smartman.modules.cps.service.IShiftDetailService; import org.springframework.data.redis.core.SetOperations; public class TimeSliceCache { private static final Logger log = LoggerFactory.getLogger(TimeSliceCache.class); public static final String CALENDAR_CACHE = "blade:cps::calendar"; public static final String CALENDAR = "calendar"; public static final String CODE = "code:"; public static final String SHIFT = "shift:"; public static final String CALENDARS_CODE = "calendars:code:"; public static final String MINUTE_POINT = "minute-point:"; private static final ICalendarService CALENDAR_SERVICE; private static final ICalendarDayService CALENDAR_DAY_SERVICE; private static final ICalendarDaytimeService DAYTIME_SERVICE = (ICalendarDaytimeService)SpringUtil.getBean(ICalendarDaytimeService.class); private static final IShiftDetailService SHIFT_DETAIL_SERVICE; private static final BladeRedis BLADE_REDIS = (BladeRedis)SpringUtil.getBean(BladeRedis.class); static { CALENDAR_SERVICE = (ICalendarService)SpringUtil.getBean(ICalendarService.class); CALENDAR_DAY_SERVICE = (ICalendarDayService)SpringUtil.getBean(ICalendarDayService.class); SHIFT_DETAIL_SERVICE = (IShiftDetailService)SpringUtil.getBean(IShiftDetailService.class); } public static List getTimeShiftDetail(String calendarCode, LocalDate date) { if (Func.isNull(calendarCode) || Func.isNull(date)) return Lists.newArrayList(); String redisKey = CommonUtil.getReallyCacheName("blade:cps::calendar", "code:" .concat(calendarCode).concat(":").concat("shift:"), DateUtil.format(date, "yyyy-MM-dd")); SetOperations setOps = BLADE_REDIS.getSetOps(); Set members = setOps.members(redisKey); if (Func.isEmpty(members)) { ProductionCalendar calendar = (ProductionCalendar)CALENDAR_SERVICE.getOne(Wrappers.lambdaQuery().eq(ProductionCalendar::getCode, calendarCode)); return Optional.ofNullable(calendar).map(cal -> { ProductionCalendarDay calendarDay = CALENDAR_DAY_SERVICE.getOne((Wrappers.lambdaQuery().eq((v0) -> { return v0.getCalendarId(); }, cal.getId())).eq((v0) -> { return v0.getCalendarDate(); }, date)); return Optional.ofNullable(calendarDay).map(day -> { Long modelId = day.getModelId(); List list = SHIFT_DETAIL_SERVICE.list(Wrappers.lambdaQuery().eq((v0) -> { return v0.getModelId(); }, modelId)); list.forEach(s -> { if (Func.isBlank(s.getIndexName())) { s.setIndexName(MessageUtils.message("calendar.page.shift.model.shift", new Object[0]) + s.getShiftIndex()); } setOps.add(redisKey, new Object[]{s}); }); BLADE_REDIS.expire(redisKey, 86400L); return list; }).orElse(Lists.newArrayList()); }).orElse(Lists.newArrayList()); } return (List)members.stream() .map(c -> (ShiftDetail)Func.convert(c, ShiftDetail.class)) .collect(Collectors.toList()); } public static CalendarShiftTimeSlicesDTO getTimeSliceShift(String calendarCode, LocalDate data, Integer shift) { String redisKey = CommonUtil.getReallyCacheName("blade:cps::calendar", "code:" .concat(calendarCode).concat(":"), DateUtil.format(data, "yyyy-MM-dd")); final CalendarShiftTimeSlicesDTO timeSliceShift = (CalendarShiftTimeSlicesDTO)TimeSliceCache.BLADE_REDIS.hGet(redisKey, (Object)shift); if (Func.isNotEmpty((Object)timeSliceShift)) { return timeSliceShift; } final ProductionCalendar calendar = (ProductionCalendar)TimeSliceCache.CALENDAR_SERVICE.getOne(Wrappers.lambdaQuery().eq(ProductionCalendar::getCode, (Object)calendarCode)); return (CalendarShiftTimeSlicesDTO) Optional.ofNullable(calendar).map(cal -> { Long id = cal.getId(); List daytimeList = DAYTIME_SERVICE.list(( Wrappers.lambdaQuery().eq((v0) -> { return v0.getCalendarId(); }, id).eq((v0) -> { return v0.getCalendarDate(); }, data)).ne((v0) -> { return v0.getShiftIndex(); }, ProductionTimeConstant.OUT_OF_SHIFT_TIME)); return (CalendarShiftTimeSlicesDTO) Optional.ofNullable(daytimeList).map(times -> { Map> map = times.stream().collect(Collectors.groupingBy((v0) -> { return v0.getShiftIndex(); })); Map timeSlicesDtoMap = Kv.newMap(); map.forEach((k, v) -> { ProductionCalendarDaytime daytime = (ProductionCalendarDaytime) v.stream().min(Comparator.comparing((v0) -> { return v0.getStartTime(); })).get(); ProductionCalendarDaytime endTimeDay = (ProductionCalendarDaytime) v.stream().max(Comparator.comparing((v0) -> { return v0.getEndTime(); })).get(); daytime.setEndTime(endTimeDay.getEndTime()); timeSlicesDtoMap.put(k, CalendarShiftTimeSlicesDTO.builder().endTime(DateUtil.toDate(daytime.getEndTime())).startTime(DateUtil.toDate(daytime.getStartTime())).shiftIndex(daytime.getShiftIndex()).factoryDate(DateUtil.formatDate(daytime.getCalendarDate())).factoryMonth(daytime.getMonth()).factoryWeek(daytime.getWeek()).factoryYear(daytime.getYear()).build()); }); BLADE_REDIS.getRedisTemplate().opsForHash().putAll(redisKey, timeSlicesDtoMap); BLADE_REDIS.expire(redisKey, 86400L); return timeSlicesDtoMap.get(shift); }).orElse(null); }).orElse(null); } public static CalendarShiftTimeSlicesDTO getTimeSliceShift(String calendarCode, Date date) { int minutes = DateTime.of(date).hour(true) * 60 + DateTime.of(date).minute(); String redisKey = CommonUtil.getReallyCacheName("blade:cps::calendar", "calendars:code:".concat(calendarCode).concat(":").concat("minute-point:"), DateTime.of(date).toDateStr()); CalendarShiftTimeSlicesDTO calendarShiftTimeSlicesDTO = (CalendarShiftTimeSlicesDTO)BLADE_REDIS.hGet(redisKey, Integer.valueOf(minutes)); if (Func.isEmpty(calendarShiftTimeSlicesDTO)) { HashSet tenantIdSet = new HashSet<>(); tenantIdSet.add(AuthUtil.getTenantId()); CacheBuildDTO cacheBuildDTO = CacheBuildDTO.builder().targetDate(LocalDateUtil.dateToLocalDate(date)).tenantIds(tenantIdSet).calendarCode(calendarCode).build(); build(cacheBuildDTO); calendarShiftTimeSlicesDTO = (CalendarShiftTimeSlicesDTO)BLADE_REDIS.hGet(redisKey, Integer.valueOf(minutes)); } return calendarShiftTimeSlicesDTO; } public static Map getCurrentShiftInfo(List calendarCodeList) { List currentShiftInfoDTOList = new ArrayList<>(); LocalDateTime now = LocalDateTime.now(); Integer minute = Integer.valueOf(now.getHour() * 60 + now.getMinute()); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String str = LocalDate.now().format(formatter); calendarCodeList.forEach(calendarCode -> { String redisKey = CommonUtil.getReallyCacheName("blade:cps::calendar", "calendars:code:".concat(calendarCode).concat(":").concat("minute-point:"), str); CalendarShiftTimeSlicesDTO calendarShiftTimeSlicesDTO = (CalendarShiftTimeSlicesDTO)BLADE_REDIS.hGet(redisKey, minute); if (Func.isNotEmpty(calendarShiftTimeSlicesDTO)) { String shiftIndexName = CALENDAR_SERVICE.getShiftIndexNameByCodeAndYear(calendarCode, calendarShiftTimeSlicesDTO); CurrentShiftInfoDTO currentShiftInfoDTO = CurrentShiftInfoDTO.builder().factoryDay(LocalDate.parse(calendarShiftTimeSlicesDTO.getFactoryDate(), formatter)).shiftIndex(calendarShiftTimeSlicesDTO.getShiftIndex()).startTime(DateUtil.fromDate(calendarShiftTimeSlicesDTO.getStartTime())).endTime(DateUtil.fromDate(calendarShiftTimeSlicesDTO.getEndTime())).calendarCode(calendarCode).shiftIndexName(shiftIndexName).build(); currentShiftInfoDTOList.add(currentShiftInfoDTO); } }); return (Map)currentShiftInfoDTOList.stream().distinct().collect(Collectors.toMap(CurrentShiftInfoDTO::getCalendarCode, v -> v)); } /** * 构建生产日历切片缓存,从CalendarCacheXxlJob中定时调用 * @param cacheBuildDTO */ public static void build(CacheBuildDTO cacheBuildDTO) { String key = cacheBuildDTO.getTargetDate().format(DateTimeFormatter.ISO_LOCAL_DATE); List data = CALENDAR_SERVICE.buildProductionTimeCache(cacheBuildDTO); if (Func.isNotEmpty(data)) data.forEach(t -> { String redisKey = CommonUtil.getReallyCacheName("blade:cps::calendar", "calendars:code:".concat(t.getCalendarCode()).concat(":").concat("minute-point:"), key);//key格式:yyyy-MM-dd Map timeSlicesDtoMap = t.getTimeSlicesDTOMap(); BLADE_REDIS.getRedisTemplate().opsForHash().putAll(redisKey, timeSlicesDtoMap); long oneDaySeconds = 86400L;//24小时的秒数 BLADE_REDIS.expire(redisKey, oneDaySeconds * 40L); }); } }