package com.boco.nbd.wios.flow.util; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.Week; import cn.hutool.core.lang.TypeReference; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.bestvike.linq.Linq; import com.boco.nbd.cams.core.constant.CamsConstant; import com.boco.nbd.cams.core.util.LambdaUtils; import com.boco.nbd.framework.common.util.SpringContextUtil; import com.boco.nbd.framework.workflow.annotation.AnnotationUtils; import com.boco.nbd.framework.workflow.entity.constant.FlowConstants; import com.boco.nbd.framework.workflow.entity.exception.FlowException; import com.boco.nbd.framework.workflow.flow.AbstractFlow; import com.boco.nbd.wios.export.bo.UploadPic; import com.boco.nbd.wios.flow.entity.FlowConstant; import com.boco.nbd.wios.flow.entity.bo.ColumnBO; import com.boco.nbd.wios.flow.entity.bo.FilterFieldsBO; import com.boco.nbd.wios.flow.entity.bo.TransferRightBO; import com.boco.nbd.wios.flow.entity.po.MenuFieldPO; import com.boco.nbd.wios.flow.entity.po.OrderPO; import com.boco.nbd.wios.flow.entity.po.PmUserPO; import com.boco.nbd.wios.flow.entity.qo.CamsOrderQo; import com.boco.nbd.wios.flow.entity.react.SelectBO; import com.boco.nbd.wios.flow.entity.react.TreeSelectBO; import com.boco.nbd.wios.flow.enums.FiledTypeEnum; import com.boco.nbd.wios.flow.enums.FlowNodeEnum; import com.boco.nbd.wios.flow.enums.ValueTypeEnum; import com.boco.nbd.wios.manage.entity.bo.OemBo; import com.boco.nbd.wios.manage.entity.bo.OemVo; import com.boco.nbd.wios.manage.entity.bo.RegionVo; import com.boco.nbd.wios.manage.entity.cams.enums.IOperator; import com.boco.nbd.wios.manage.entity.cams.enums.OrderStatus; import com.boco.nbd.wios.manage.entity.cams.enums.OverTimeType; import com.boco.nbd.wios.manage.entity.common.bo.UploadFile; import com.boco.nbd.wios.manage.service.impl.OemService; import com.boco.nbd.wios.manage.service.impl.RegionService; import com.boco.nbd.wios.manage.service.impl.TokenService; import com.deepoove.poi.data.HyperLinkTextRenderData; import com.deepoove.poi.data.NumbericRenderData; import com.deepoove.poi.data.PictureRenderData; import com.deepoove.poi.data.RenderData; import com.deepoove.poi.util.BytePictureUtils; import com.ihidea.core.support.exception.ServiceException; import com.ihidea.core.support.session.SessionInfo; import lombok.extern.slf4j.Slf4j; import org.apache.poi.sl.usermodel.PictureData; import org.springframework.util.StringUtils; import java.lang.reflect.Field; import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Collectors; /** * @author:cao hai * @date:2022/6/30 17:07 * @version:V1.0 * @description:ProcessUtil * @modify: */ @Slf4j public class ProcessUtil { /** * 服务名 */ private static String OEM_SERVICE = "oemService"; private static String REGION_SERVICE = "regionService"; public static final String RE_LOGIN = "请重新登录"; private static final String TOKEN_SERVICE_BEAN = "tokenService"; public static final String HOLIDAY_TYPE = "节假日"; public static final String WORK_TYPE = "调休工作日"; /** * 勘测转派节点 */ private static final Integer[] SURVEY_TRANSFER_NODE = {104, 105, 106, 115}; /** * 安装转派节点 */ private static final Integer[] INSTALL_TRANSFER_NODE = {108, 109, 110, 111}; /** * 一期操蛋逻辑,导入时候 各种日期不为空添加一个_1,空加_0后缀,因为涉及前端部分逻辑调整,所以这部分逻辑还沿用 */ public static final String EMPTY_ADD = "_0"; public static final String NOT_EMPTY_ADD = "_1"; /** * 空对象正则 */ public final static Pattern EMPTY_PATTERN = Pattern.compile("^(\\[)?(\\{\\})?(])?$"); /** * 转派对象处理 * * @param po * @param userId * @return */ public static TransferRightBO getTransferRightBO(OrderPO po, String userId) { TransferRightBO bo = new TransferRightBO(); bo.setTransferRight(false); if (StrUtil.isEmpty(po.getTransferUser()) || StrUtil.isEmpty(userId)) { return bo; } List<String> user = Arrays.asList(po.getTransferUser().split(CamsConstant.COMMA)); if (areSurveyTransfer(po.getNodeFlag()) && user.contains(userId)) { bo.setTransferRight(true); bo.setCurrentSupplierId(po.getSurveySupplierId()); bo.setCurrentSupplierName(po.getSurveySupplierName()); bo.setCurrentStaffId(po.getSurveyStaffId()); bo.setCurrentStaffName(po.getSurveyStaffName()); } else if (areInstallTransfer(po.getNodeFlag()) && user.contains(userId)) { bo.setTransferRight(true); bo.setCurrentSupplierId(po.getInstallSupplierId()); bo.setCurrentSupplierName(po.getInstallSupplierName()); bo.setCurrentStaffId(po.getInstallStaffId()); bo.setCurrentStaffName(po.getInstallStaffName()); } return bo; } /** * 是否勘测转派节点 * * @param currentNode * @return */ public static boolean areSurveyTransfer(Integer currentNode) { return Arrays.asList(SURVEY_TRANSFER_NODE).contains(currentNode); } /** * 是否安装转派节点 * * @param currentNode * @return */ public static boolean areInstallTransfer(Integer currentNode) { return Arrays.asList(INSTALL_TRANSFER_NODE).contains(currentNode); } /** * 获取当前工单的区域 * * @param users * @param po * @return */ public static List<String> getTransferUser(List<PmUserPO> users, OrderPO po) { if (CollUtil.isEmpty(users)) { throw new FlowException("请配置区域PM账号!"); } List<String> user = new ArrayList<>(8); String areaId = po.findAreaId(); for (PmUserPO pm : users) { if (StrUtil.isEmpty(pm.getRegionId())) { continue; } List<String> regionIdList = Arrays.asList(pm.getRegionId().split(CamsConstant.COMMA)); if (regionIdList.contains(areaId)) { user.add(pm.getAccountId()); } } if (CollUtil.isEmpty(user)) { String areaName = po.findAreaName(); throw new FlowException(areaName + "未配置区域PM账号!"); } return user; } /** * 图片数据处理 * * @param url * @return */ public static PictureRenderData pictureRenderData(String url) { try { return new PictureRenderData(50, 50, PictureData.PictureType.PNG.extension, BytePictureUtils.getUrlBufferedImage(url)); } catch (Exception e) { log.error("{} PictureRenderData error:{}", url, e); } return null; } /** * 获取文件后缀 * * @param fileName * @return */ public static String getFileSuffix(String fileName) { if (StrUtil.isEmpty(fileName)) { return ""; } return fileName.substring(fileName.lastIndexOf(CamsConstant.CIRCLE_FLAG)); } /** * 超链接文本处理 * * @param fileName * @param url * @return */ public static HyperLinkTextRenderData hyperLinkTextRenderData(String fileName, String url) { try { return new HyperLinkTextRenderData(fileName, url); } catch (Exception e) { log.error("{} PictureRenderData error:{}", url, e); } return null; } /** * 附件数据处理 * * @param files * @return */ public static Map<String, Object> handleFiles(List<UploadFile> files) { Map<String, Object> data = new HashMap<>(2); data.put(FlowConstant.PIC_FILES, null); data.put(FlowConstant.ATTACH_FILES, null); if (CollUtil.isEmpty(files)) { return data; } List<RenderData> attachFileList = new ArrayList<>(); List<UploadPic> picList = new ArrayList<>(); files.stream().forEach(pic -> { if (pic.getName().endsWith(PictureData.PictureType.JPEG.extension) || pic.getName().endsWith(PictureData.PictureType.PNG.extension)) { PictureRenderData pictureRenderData = pictureRenderData(pic.getUrl()); if (pictureRenderData != null) { UploadPic up = new UploadPic(); up.setPrd(pictureRenderData); up.setName(pic.getName()); up.setTime(DateUtil.format(pic.getCreateTime(), DatePattern.NORM_DATETIME_PATTERN)); picList.add(up); } } else { HyperLinkTextRenderData row = hyperLinkTextRenderData(pic.getName(), pic.getUrl()); if (row != null) { attachFileList.add(row); } } }); data.put(FlowConstant.PIC_FILES, picList); data.put(FlowConstant.ATTACH_FILES, new NumbericRenderData(attachFileList)); return data; } /** * json 处理==>如果存在json转换个性处理的,在相应的实现类中个性化实现 * 异常:JSONObject cannot be cast to com.boco.nbd.wios.manage.entity.settlement.po.Invoice * 说明 转换后对象 并没有转换成T 而是 JSONObject对象,如果使用需要进一步处理 * * @param json * @return */ public static List<JSONObject> jsonHandle(String json) { if (StringUtils.isEmpty(json)) { return new ArrayList<>(1); } try { return JSONUtil.toBean(JSONUtil.parse(json), new TypeReference<List<JSONObject>>() { }, true); } catch (Exception ex) { log.error(json + "数据转换异常:", ex); throw new ServiceException("数据转换异常"); } } /** * 一期操蛋逻辑 日期处理 * * @param date * @return */ public static String dayHandle(String date) { String addStr = StrUtil.isNotBlank(date) ? NOT_EMPTY_ADD : EMPTY_ADD; return date + addStr; } /** * 获取用户信息 * * @return */ public static SessionInfo getUserInfo() { TokenService tokenService = (TokenService) SpringContextUtil.getBean(TOKEN_SERVICE_BEAN); return tokenService.getUser(); } /** * 转换处理实体中特定字段:目前主要处理时间类型、枚举类型转换 * * @param entry * @param filterFieldsBO * @param enumMap * @param <T> * @return */ public static <T> Map<String, Object> getFilterFields(T entry, FilterFieldsBO filterFieldsBO, Map<String, Map<Object, String>> enumMap) { return getFilterFields(entry, filterFieldsBO.getFilterFields(), filterFieldsBO.getMatchField(), filterFieldsBO.getRepeatField(), enumMap); } /** * 转换处理实体中特定字段:目前主要处理时间类型、枚举类型转换 * * @param entry * @param filterFields:过滤字段 * @param matchField:转意处理字段 * @param matchField:特殊字符转义处理字段如果是原先就存在的删除 有问题 * @param <T> * @return */ public static <T> Map<String, Object> getFilterFields(T entry, List<String> filterFields, Map<String, String> matchField, List<String> repeatField, Map<String, Map<Object, String>> enumMap) { if (filterFields == null) { return new HashMap<>(1); } Map<String, Object> result = AnnotationUtils.convert(entry, filterFields, enumMap); if (matchField.size() > 0) { matchField.entrySet().stream().forEach(s -> { if (result.containsKey(s.getKey())) { result.put(s.getValue(), result.get(s.getKey())); //转义字段非存在字段删除 boolean keep = (CollUtil.isNotEmpty(repeatField) && repeatField.contains(s.getKey())); if (!keep) { result.remove(s.getKey()); } } }); } return result; } /** * 字符串类型时间转换 * * @param dateStr * @param dateFormat * @return */ public static Date dateParse(CharSequence dateStr, String dateFormat) { return DateUtil.parse(dateStr, dateFormat); } /** * 对比 * * @param source * @param compare * @return */ public static boolean compare(Integer source, int compare) { log.info("compare data:" + source); if (source == null) { return false; } return source == compare; } /** * 天粒度处理==》过滤非工作日 * * @param time * @param limit * @return */ public static Date offsetDay(Date time, int limit, Map<String, List<String>> map) { Date dueDate = ProcessUtil.getDueStartDate(time); //没带节假日数据结算的dueDate可能是假日 dueDate = getWorkDate(dueDate, map); for (int i = 0; i < limit; i++) { dueDate = DateUtil.offsetDay(dueDate, 1); dueDate = getWorkDate(dueDate, map); } return dueDate; } /** * 时间粒度处理==》过滤非工作日 * * @param time * @param limit * @return */ public static Date offsetHour(Date time, int limit, Map<String, List<String>> map) { Date dueDate = ProcessUtil.getDueStartDate(time); //没有过滤节假日的dueDate可能是假日 dueDate = getWorkDate(dueDate, map); for (int i = 0; i < limit; i++) { dueDate = DateUtil.offsetHour(dueDate, 1); dueDate = getWorkDate(dueDate, map); } return dueDate; } /** * 获取工作日时间 * * @param time * @param map * @return */ private static Date getWorkDate(Date time, Map<String, List<String>> map) { if (areHoliday(time, map)) { time = DateUtil.offsetDay(time, 1); return getWorkDate(time, map); } return time; } /** * 判断是否节假日 * * @param time * @param map * @return */ private static boolean areHoliday(Date time, Map<String, List<String>> map) { String dayTime = DateUtil.format(time, DatePattern.NORM_DATE_PATTERN); if (map.get(HOLIDAY_TYPE).contains(dayTime)) { return true; } if (map.get(WORK_TYPE).contains(dayTime)) { return false; } Week week = DateUtil.dayOfWeekEnum(time); return (Week.SUNDAY.equals(week) || Week.SATURDAY.equals(week)); } /** * 获取起始计算时间 * 如果接到单子的时间为当天0点-8点59分59秒之间则从当天的9点开始计算24小时 * 如果接到单子的时间为9点-17点59分59秒之间则直接开始计算24小时, * 如果接到单子的时间为18点-23点59分59秒之间则从第二天的9点开始计算24小时, * * @param startTime * @return */ public static Date getDueStartDate(Date startTime) { Calendar calendar = Calendar.getInstance(); calendar.setTime(startTime); int hour = calendar.get(Calendar.HOUR_OF_DAY); int firstFlag = 9; int secondFlag = 18; if (hour < firstFlag) { calendar.set(Calendar.HOUR_OF_DAY, firstFlag); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); return calendar.getTime(); } if (hour < secondFlag) { return calendar.getTime(); } int day = calendar.get(Calendar.DAY_OF_MONTH); calendar.set(Calendar.DAY_OF_MONTH, day + 1); calendar.set(Calendar.HOUR_OF_DAY, firstFlag); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); return calendar.getTime(); } /** * 获取节点的执行类 * * @param currentNode * @return */ public static AbstractFlow getBaseProcess(Integer currentNode) { try { if (currentNode == -1) { return null; } if (Boolean.TRUE.equals(FlowNodeEnum.contains(currentNode))) { //modify 2022-11-23 SpringContextLoader.getBean 调度模块无法读取Bean对象 return (AbstractFlow) SpringContextUtil.getBean("Process" + currentNode); } return null; } catch (Exception e) { log.error(currentNode + "find Process error:", e); return null; } } /** * 生成字段 * nodeName 是react的关键字(定义的方法吧) 添加matchField存在做二次隐射 * * @param fields * @return */ public static List<ColumnBO> creatListField(List<MenuFieldPO> fields) { Map<String, ColumnBO> map = listFieldHandle(fields); createQoField(map); List<ColumnBO> result = map.values().stream().sorted(Comparator.comparing(ColumnBO::getOrderBy)).collect(Collectors.toList()); return result; } /** * 合并from字段 * * @param fields * @return */ private static Map<String, ColumnBO> listFieldHandle(List<MenuFieldPO> fields) { Map<String, ColumnBO> map = new HashMap<>(10); if (fields == null || fields.isEmpty()) { return map; } List<MenuFieldPO> tableFields = Linq.of(fields).where(s -> FiledTypeEnum.TABLE_FIELD.getKey().equals(s.getFiledType())).toList(); if (tableFields == null || tableFields.isEmpty()) { return map; } map = tableFields.stream().map(s -> s.toTableBo()).collect(Collectors.toMap(ColumnBO::getDataIndex, Function.identity())); List<MenuFieldPO> fromFields = Linq.of(fields).where(s -> FiledTypeEnum.FROM_FIELD.getKey().equals(s.getFiledType())).toList(); for (MenuFieldPO po : fromFields) { ColumnBO bo; if (map.containsKey(po.getDataIndex())) { bo = map.get(po.getDataIndex()); if (!bo.getTitle().equals(po.getTitle())) { bo.setFormTitle(po.getTitle()); } bo.setValueType(po.getValueType()); bo.setHideInForm(false); bo.setOrder(-po.getOrder()); } else { bo = po.toFormBo(); } map.put(po.getDataIndex(), bo); } return map; } /** * map to bean,如果maps中不包含bean字段赋值不成功 * * @param maps * @param clazz * @return */ public static <T> T fillBeanWithMap(Map<String, Object> maps, Class<?> clazz) { try { if (CollUtil.isEmpty(maps)) { log.info("表单数据为空."); return null; } Field[] fields = clazz.getDeclaredFields(); Field field = Linq.of(fields).where(s -> maps.containsKey(s.getName())).firstOrDefault(); if (field == null) { return null; } //兼容处理实体类字段是String,前端传递的为非字符串对象类型 //兼容处理空对象转换成{},[{}]字符串 List<Field> handleField = Linq.of(fields).where(s -> s.getType().equals(String.class)).toList(); handleField.forEach(s -> { if (maps.containsKey(s.getName())) { if (maps.get(s.getName()) != null) { Class<?> mapClazz = maps.get(s.getName()).getClass(); if (mapClazz.equals(HashMap.class) || mapClazz.equals(ArrayList.class)) { String jsonStr = JSONUtil.toJsonStr(maps.get(s.getName())); if (EMPTY_PATTERN.matcher(jsonStr).matches()) { jsonStr = null; } maps.put(s.getName(), jsonStr); } } } }); return (T) BeanUtil.fillBeanWithMap(maps, clazz.newInstance(), true); } catch ( Exception ex) { log.error(clazz.getName() + " fillBeanWithMap error:", ex); return null; } } /** * 根据查询条件返回字段 */ private static void createQoField(Map<String, ColumnBO> map) { //个性赋值 String regionId = LambdaUtils.getFieldName(CamsOrderQo::getRegionId); if (map.containsKey(regionId)) { if (ValueTypeEnum.CASCADER.getKey().equals(map.get(regionId).getValueType())) { map.get(regionId).setValueEnum(getRegionData()); } } String omeId = LambdaUtils.getFieldName(CamsOrderQo::getOemId); if (map.containsKey(omeId)) { if (ValueTypeEnum.SELECT.getKey().equals(map.get(omeId).getValueType())) { map.get(omeId).setValueEnum(getOemData()); } } String status = LambdaUtils.getFieldName(CamsOrderQo::getStatus); if (map.containsKey(status)) { if (ValueTypeEnum.SELECT.getKey().equals(map.get(status).getValueType())) { map.get(status).setValueEnum(getSelectBO(OrderStatus.values())); } } String overtimeType = LambdaUtils.getFieldName(CamsOrderQo::getOvertimeType); if (map.containsKey(overtimeType)) { if (ValueTypeEnum.SELECT.getKey().equals(map.get(overtimeType).getValueType())) { map.get(overtimeType).setValueEnum(getSelectBO(OverTimeType.values())); } } } /** * 车企品牌 * * @return */ private static List getOemData() { try { OemService oemService = (OemService) SpringContextUtil.getBean(OEM_SERVICE); OemBo condition = new OemBo(); condition.setType(1); List<OemVo> oemVos = oemService.getList(condition); return SelectBO.createOem(oemVos); } catch (Exception ex) { log.error("find RegionService error:", ex); return new ArrayList(1); } } /** * 枚举 * * @return */ public static List getSelectBO(IOperator[] statuses) { List<SelectBO> list = new ArrayList<>(10); list.add(SelectBO.crateBase()); for (IOperator status : statuses) { SelectBO bo = SelectBO.crate(status.getValue(), status.getType()); list.add(bo); } return list; } /** * 生成区域TreeSelect数据 * * @return */ private static List getRegionData() { try { RegionService regionService = (RegionService) SpringContextUtil.getBean(REGION_SERVICE); List<RegionVo> regionVos = regionService.selectAll(1); return TreeSelectBO.createRegion(regionVos); } catch (Exception ex) { log.error("find RegionService error:", ex); return new ArrayList(1); } } /** * 获取指定时间区间的所有数据(包含日期和月份) * * @param dBegin * @param dEnd * @param rule 日历规则 如:Calendar.DAY_OF_MONTH * @return */ public static List<Date> findDates(Date dBegin, Date dEnd, int rule) { List lDate = new ArrayList(); if (dEnd.before(dBegin)) { return lDate; } lDate.add(dBegin); Calendar calBegin = Calendar.getInstance(); // 使用给定的 Date 设置此 Calendar 的时间 calBegin.setTime(dBegin); Calendar calEnd = Calendar.getInstance(); // 使用给定的 Date 设置此 Calendar 的时间 calEnd.setTime(dEnd); // 测试此日期是否在指定日期之后 while (dEnd.after(calBegin.getTime())) { // 根据日历的规则,为给定的日历字段添加或减去指定的时间量 calBegin.add(rule, 1); lDate.add(calBegin.getTime()); } return lDate; } /** * 天 */ private static Integer d = 24; /** * 分钟、秒 */ private static Integer m = 60; /** * 毫秒 */ private static Integer s = 1000; /** * 时间戳转换 天 小时 分钟 * * @param time 时间戳 */ public static StringBuffer timeFormat(long time) { long day = 0; long hour = 0; long min = 0; StringBuffer sBuffer = new StringBuffer(); if (time >= m * m * s) { if (time >= d * m * m * s) { day = time / (d * m * m * s); hour = time / (m * m * s) - day * d; sBuffer.append(day + "天"); } else { hour = time / (m * m * s); } min = time - (hour * m * m * s) - (day * d * m * m * s); sBuffer.append(hour + "小时"); min = min / (m * s); sBuffer.append(min + "分钟"); } else { sBuffer.append(time / (m * s) + "分钟"); } return sBuffer; } /** * 处理List集合数据进行分页 * * @param currentPage * @param pageSize * @param list * @param <T> * @return */ public static <T> List<T> getPageInfo(int currentPage, int pageSize, List<T> list) { List<T> newList = new ArrayList<>(); if (list != null && list.size() > 0) { int currIdx = (currentPage > 1 ? (currentPage - 1) * pageSize : 0); for (int i = 0; i < pageSize && i < list.size() - currIdx; i++) { newList.add(list.get(currIdx + i)); } } return newList; } /** * 根据尾号判断是否存在操作权限 * * @param id * @param endNumber * @return */ public static boolean hasOrderRight(String id, String endNumber) { if (StrUtil.isEmpty(endNumber)) { return false; } List<String> items = Arrays.asList(endNumber.split(FlowConstants.COMMA)); String find = Linq.of(items).where(s -> id.endsWith(s)).firstOrDefault(); return StrUtil.isNotEmpty(find); } }