package com.mixsmart.utils; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateTime; import cn.hutool.log.StaticLog; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.annotation.JSONField; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.parser.*; import com.jfireel.expression.Expression; import org.apache.commons.lang.math.NumberUtils; import org.apache.http.*; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.apache.poi.hssf.usermodel.HSSFDataFormatter; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.ss.usermodel.*; import java.awt.Color; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.ChartUtils; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.*; import org.jfree.chart.plot.*; import org.jfree.chart.renderer.category.BarRenderer; import org.jfree.chart.renderer.category.LineAndShapeRenderer; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.chart.renderer.xy.XYSplineRenderer; import org.jfree.chart.title.TextTitle; import org.jfree.chart.ui.RectangleEdge; import org.jfree.chart.ui.RectangleInsets; import org.jfree.chart.ui.TextAnchor; import org.jfree.data.category.CategoryDataset; import org.jfree.data.category.DefaultCategoryDataset; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import org.springblade.common.constant.CommonConstant; import org.springblade.common.utils.BaseUtils; import org.springblade.common.utils.SnowFlakeUtil; import org.springblade.common.utils.SystemUtils; import org.springblade.core.tool.utils.*; import org.springblade.manager.bean.TableInfo; import org.springblade.manager.dto.*; import org.springblade.manager.entity.Formula; import org.springblade.manager.entity.WbsTreeContract; import org.springblade.manager.formula.NodeTable; import org.springblade.manager.formula.impl.CompositeDataAccess; import org.springblade.manager.formula.impl.TableElementConverter; import org.springblade.manager.utils.FileUtils; import org.springblade.manager.vo.*; import org.springblade.system.cache.ParamCache; import org.springframework.core.annotation.AnnotationUtils; import reactor.core.publisher.Mono; import javax.imageio.ImageIO; import java.awt.*; import java.awt.Font; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.*; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; import static java.util.regex.Pattern.*; /** * @author yangyj * @Date 2022/7/14 15:55 * @description 公式工具类 */ public class FormulaUtils { public static final String ELE_CODE_REG= "(?<=E\\[)[^]]+(?=])"; public static final Pattern P = Pattern.compile(ELE_CODE_REG); /**元素标识*/ public final static String E="E"; /*确定各个元素在计算时的步长,算法:step=最长单元格数/当前元素单元格数*/ public static LinkedHashMap step(List ele){ LinkedHashMap fdMap =new LinkedHashMap<>(); FormData maxFormData = Collections.max(ele, Comparator.comparingInt((FormData ef)->ef.getValues().size())); FormData minFormData = Collections.min(ele, Comparator.comparingInt((FormData ef)->ef.getValues().size())); if (maxFormData.getValues().size() != minFormData.getValues().size()) { int baseLength = maxFormData.getValues().size(); for (FormData formData : ele) { formData.setStep(baseLength / formData.getValues().size()); } } ele.forEach(e->{ fdMap.put(e.getCode(),e); }); return fdMap; } /*确定公式执行环境变量*/ public static List slice2Local(String f, LinkedHashMap fdMap, TableElementConverter tec){ CompositeDataAccess cda = new CompositeDataAccess(fdMap); List local= new ArrayList<>(); while (cda.hasNext()){ LinkedHashMap tip= cda.next(); Map variable = new HashMap<>(tec.constantMap); @SuppressWarnings("unchecked") Map em= (Map) variable.computeIfAbsent(E, k->new HashMap<>()); Integer index= new ArrayList<>(tip.values()).get(0).getIndex(); for(Map.Entry se:tip.entrySet()){ Object value=se.getValue().getValue(); if(CustomFunction.isNumber(value)){ if(StringUtils.isDouble(value)||f.contains("/")){ em.put(se.getKey(),Double.parseDouble(value.toString())); }else{ em.put(se.getKey(),StringUtils.handleObj2Integer(value)); } }else{ em.put(se.getKey(),StringUtils.handleNull(value).replaceAll("[ ]+","").trim()); } } local.add(new LocalVariable(index,f,variable)); } return local; } public static void putEle(String f,List ele,Map currentMap,FormData fd){ @SuppressWarnings("unchecked") Map em = (Map) currentMap.computeIfAbsent(E,(k)-> new HashMap<>()); /*如果输入输出元素都是1对1*/ if(f.split("[/+\\-*]").length>1&&!f.contains("{}")&&ele.stream().map(e->e.getCoordsList().size()).max(Comparator.comparingInt(e->e)).orElse(1)==1&&fd.getCoordsList().size()==1){ ele.forEach(e->{ Object value=e.getValues().get(0).getValue(); if(CustomFunction.isNumber(value)){ if(StringUtils.isDouble(value)||f.contains("/")){ em.put(e.getCode(), Double.parseDouble(value.toString())); }else{ em.put(e.getCode(),StringUtils.handleObj2Integer(value)); } }else{ em.put(e.getCode(),value); } }); }else{ ele.forEach(e-> em.put(e.getCode(),e.getRawValue())); } } public static final Random RD = new Random(); public static Map triangleSquare(Object ranges){ Map map =new HashMap<>(); if(StringUtils.isEmpty(ranges)){ //z的默认取值范围 ranges="(0,15)"; } Matcher m = RegexUtils.matcher("(\\-?\\d+)(\\D)(\\+?\\d+)",ranges.toString()); if(m.find()) { int min = StringUtils.handObj2Integer(m.group(1)); int max = StringUtils.handObj2Integer(m.group(3)); Integer[] r = pythagorean(min, max); map.put("X", String.valueOf(r[0])); map.put("Y", String.valueOf(r[1])); map.put("Z", String.valueOf(r[2])); } return map; } /* public static void main(String[] args) { IntStream.range(0,10).boxed().forEach(i->{ System.out.println(triangleSquare("-5,5")); }); }*/ /** * @Description 字符串相似度 * @Param [s1, s2] * @return double * @Author yangyj * @Date 2023.04.12 18:01 **/ public static double getJaccardSimilarity(String s1, String s2) { Set set1 = new HashSet<>(); Set set2 = new HashSet<>(); for (char c : s1.toCharArray()) { set1.add(c); } for (char c : s2.toCharArray()) { set2.add(c); } Set intersection = new HashSet<>(set1); intersection.retainAll(set2); Set union = new HashSet<>(set1); union.addAll(set2); return (double) intersection.size() / union.size(); } public static Double similarity(String s1,String s2){ return getJaccardSimilarity(parseItemName(s1),parseItemName(s2)); } /* public static void main(String[] args) { similarity("分项工程名称:","分项工程名称:"); }*/ /** * result[0]^2+result[1]^2=result[2]^2 result[] 元素均为正整数 */ public static Integer[] pythagorean(Integer min,Integer max){ Integer[] result = null; List list = new ArrayList<>(); for(int i=1;i<=max;i++){ for(int j=1;j<=max;j++){ double tmp = Math.sqrt(Math.pow(i,2)+Math.pow(j,2)); int z= (int) Math.round(tmp); if(min list = new ArrayList<>(); list.add(new ElementData(1,1,1)); test(fd); System.out.println(fd.getEName()); }*/ /**写人元素数据,每个元素都是一个集合,每页的单元格数量乘以页数就是总长度*/ public static void write(FormData fd, Object data){ write(fd,data,false); } public static void write(FormData fd, Object data,Boolean retainEmpty ){ if(Func.isEmpty(fd.getValues())){ /*无定位信息不写入*/ return; } try { /*一个单元格且存在多张,全部设置为自动拓展 20230816*/ if(fd.getCoordsList().size()==1&&fd.getValues().size()>1&&fd.getFormula()!=null){ fd.getFormula().setOutm(Formula.FULL); } /*写入前清空内容*/ fd.getValues().forEach(t->t.setValue(null)); if(data instanceof List){ List values = (List) data; if(!retainEmpty){ /*不包含空白内容*/ values=values.stream().filter(StringUtils::isNotEmpty).collect(Collectors.toList()); } if(values.size()>fd.getValues().size()){ if(fd.getCoordsList().size()==1){ /*元素只绑定了一个单元格的情况*/ if(values.stream().filter(CustomFunction::containsZH).anyMatch(e->e.toString().contains("\n"))){ fd.getValues().get(0).setValue(values.stream().filter(Objects::nonNull).map(Object::toString).collect(Collectors.joining())); }else{ /*日期类型的元素只获取最后一个非空*/ if(StringUtils.isEquals(4,fd.getEType())){ fd.getValues().get(0).setValue(values.stream().filter(StringUtils::isNotEmpty).reduce((first, second) -> second).orElse(null)); }else if(values.stream().filter(StringUtils::isNotEmpty).distinct().count()==1L&&!fd.getEName().contains("实测")){ /*如果输入元素全是是一样的内容,则输入出元素则每个单元格也写入一样的内容*/ values.stream().filter(StringUtils::isNotEmpty).findFirst().ifPresent(t->{ for(int n=0;n overList=values.stream().skip(fd.getValues().size()).collect(Collectors.toList()); List coordsList = fd.getCoordsList(); int addPage=(int)Math.ceil((double)overList.size()/(double)coordsList.size()); fd.setAddPages(addPage); ElementData last =fd.getValues().get(fd.getValues().size()-1); int indexBase=last.getIndex()+1; List addList= new ArrayList<>(); for(int i=0;ie.setValue(data)); }else{ fd.getValues().get(0).setValue(data); } } fd.setUpdate(1); }catch (Exception e){ e.printStackTrace(); } } public static final String TBN_FN="TBN"; /*把模型类转换成共识配置选项*/ public static List toElementVos(Class clazz) { return DataModel.toElementVos(clazz); } public static String getEleKey(Class clazz, String fieldName){ try { Field field = clazz.getDeclaredField(fieldName); String TBN = (String) clazz.getField(TBN_FN).get(null); JSONField jf = AnnotationUtils.findAnnotation(field, JSONField.class); if (jf != null) { return TBN+StringPool.COLON+jf.name(); } } catch (Exception e) { e.printStackTrace(); } return StringPool.EMPTY; } public static JSONField getJSONField(Class clazz, String fieldName){ try { Field field = clazz.getDeclaredField(fieldName); String TBN = (String) clazz.getField(TBN_FN).get(null); JSONField jf = AnnotationUtils.findAnnotation(field, JSONField.class); if (jf != null) { return jf; } } catch (Exception e) { e.printStackTrace(); } return null; } /*获取指定模型的页码元素*/ public static String getPageCode(Class clazz){ return getEleKey(clazz,"pageCount"); } public static String getPageTotal(Class clazz){ return getEleKey(clazz,"pageTotal"); } public static String getPageIndex(Class clazz){ return getEleKey(clazz,"pageIndex"); } public static JSONField getPageFormat(Class clazz){ return getJSONField(clazz,"pageCount"); } /*根据数据模型实例生成带数据的元素,用于修改*/ public static LinkedHashMap toFormDataMap(T bean){ LinkedHashMap result = new LinkedHashMap<>(); if(bean!=null){ try { @SuppressWarnings("unchecked") Map map= JSON.parseObject(JSON.toJSONString(bean),Map.class); Class clazz=bean.getClass(); String TBN = (String) clazz.getField(TBN_FN).get(null); for (Field field : clazz.getDeclaredFields()) { JSONField jf = field.getAnnotation(JSONField.class); if (jf != null) { FormData fd = new FormData(); fd.setCode(TBN+ StringPool.COLON +jf.name()); fd.setEName(jf.label()); fd.getValues().add(new ElementData(0,0,map.get(fd.getKey()),0,0)); fd.getCoordsList().add(new Coords("0","0")); result.put(fd.getCode(),fd); } } }catch (Exception e){ e.printStackTrace(); } } return result; } /*根据数据模型建立空元素,待写入数据*/ public static LinkedHashMap toFormDataMap(Class clazz){ LinkedHashMap result = new LinkedHashMap<>(); try { String TBN = (String) clazz.getField(TBN_FN).get(null); for (Field field : clazz.getDeclaredFields()) { JSONField jf = field.getAnnotation(JSONField.class); if (jf != null) { FormData fd = new FormData(); fd.setCode(TBN+ StringPool.COLON +jf.name()); fd.setEName(jf.label()); fd.getCoordsList().add(new Coords("0","0")); result.put(fd.getCode(),fd); } } }catch (Exception e){ e.printStackTrace(); } return result; } /*把结果数据回写到元素*/ public staticvoid put2FormData( LinkedHashMap fdm,Map,List>> functionMap,List dataList){ fdm.values().stream() .filter(fd -> functionMap.containsKey(fd.getCode())) .forEach(fd -> { List raw = functionMap.get(fd.getCode()).apply(dataList); raw.stream().map(ElementData::new).forEach(fd.getValues()::add); }); } /*根据数据模型对象,生成数据集合按字段获取数据的函数*/ public static Map, List>> fieldDataFcMap(Class clazz) { Map> fieldMap = functionMapBuilder(clazz); Map, List>> functionMap = new HashMap<>(); for (Map.Entry> functionEntry : fieldMap.entrySet()) { Function, List> mapper = list -> list.stream().map(functionEntry.getValue()).collect(Collectors.toList()); functionMap.put(functionEntry.getKey(), mapper); } return functionMap; } /*数据模型按字段生成内容获取函数*/ public static Map> functionMapBuilder(Class clazz){ Map> functionMap = new HashMap<>(); try { String tbn=clazz.getField(TBN_FN).get(null).toString(); for (Field field : clazz.getDeclaredFields()) { JSONField jf = field.getAnnotation(JSONField.class); if(jf!=null) { /*ordinal<=100的情况下才会生成动态行字段输出函数*/ if(jf.ordinal()<=100) { String key = tbn + StringPool.COLON + jf.name(); String fieldName = field.getName(); Function function = getFunction(clazz, fieldName); functionMap.put(key, function); } } } }catch (Exception e){ e.printStackTrace(); } return functionMap; } private static Function getFunction(Class clazz, String fieldName) { return certificate -> { try { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); return field.get(certificate); } catch (Exception e) { e.printStackTrace(); return null; } }; } /*list转TreeNode*/ public static Map> list2TreeNode(Function,K> keyMapper,List list,Function> fc,Function,K> classifier){ Map> mTreeMap = new HashMap<>(); if (Func.isNotEmpty(list)) { for (T mt : list) { try { TreeNode treeNode = fc.apply(mt); mTreeMap.put(keyMapper.apply(treeNode), treeNode); }catch (Exception e){ e.printStackTrace(); } } Map>> group = mTreeMap.values().stream().collect(Collectors.groupingBy(classifier)); group.forEach((k, v) -> { TreeNode parent = mTreeMap.get(k); if (parent != null) { v = v.stream().sorted(Comparator.comparingInt(TreeNode::getSort)).collect(Collectors.toList()); parent.setChildren(v); v.forEach(e -> e.setParent(parent)); } }); } return mTreeMap; } /*TreeNode 排序*/ public static void treeNodeSort(int base,TreeNode top){ top.setSort(base); if(top.hasChildren()){ for(TreeNode child:top.getChildren()){ child.setSort(base++); } } } /*回溯标记*/ public static void treeNodeChecked( TreeNode tmp){ int loop = 10; do{ if(tmp.isChecked()) { /*已经检出则停止循环*/ loop=0; }else{ tmp.setChecked(true); tmp=tmp.getParent(); } }while (tmp!=null&&loop-->0); } /*获取层级链*/ public static List treeNodeChains( TreeNode tmp){ List result = new ArrayList<>(); int loop = 10; do{ /*不包括顶层*/ if(tmp.getParentId()!=0L) { result.add(tmp.getValue()); } tmp=tmp.getParent(); }while (tmp!=null&&loop-->0); Collections.reverse(result); return result; } /**从元素名称中解析项目名称,细化项目匹配用*/ public static String parseItemName(String eName){ if (StringUtils.isEmpty(eName)) { return eName; } String str = eName.replaceAll("\\s", ""); Pattern pattern = compile("[((][^\\u4e00-\\u9fa5]+[))]|_+"); String[] candidate = pattern.split(str); /*非中文非罗马数字1到10*/ String regex = "[^\\u4e00-\\u9fa5\\u2160-\\u2169))((]+"; Pattern p = compile(regex); return Arrays.stream(candidate) .filter(s -> !isContainKeywords(s)) .map(s -> filterString(s, p)) .collect(Collectors.joining()); } /*A15检查内容专用*/ public static String checkItemName(String eName){ if (StringUtils.isEmpty(eName)) { return eName; } /*分割字符串,选取第一个匹配的子串*/ String str = eName.replaceAll("\\s", ""); Pattern pattern = compile("[((][^\\u4e00-\\u9fa5]+[))]|_+"); String[] candidate = pattern.split(str); String regex = "[^\\u4e00-\\u9fa5]+"; return Arrays.stream(candidate).map(s->s.replaceAll(regex,"")).distinct().filter(StringUtils::isNotEmpty).filter(s->!isContainKeywords2(s)).findFirst().orElse(""); } private static String filterString(String s, Pattern p) { s=s.replaceAll("【[^【】]+】",""); Matcher matcher = p.matcher(s); return matcher.replaceAll("").replaceAll(getRegex(), "").replaceAll("(设计|合格).*",""); } private static String getRegex() { return "(在合格标准内|满足设计要求|质量评定|评定|判定|项目|总数|抽测|实测|偏差|尺量|关键|一般)"; } private static boolean isContainKeywords(String s) { List keywords = Arrays.asList( ":", "个","附录","抽查","测","求","小于","大于","检查","仪","按","不","各","记录","检验","且","规定","值或实","≤","≥","平均"); return keywords.stream().anyMatch(s::contains); } private static boolean isContainKeywords2(String s) { List keywords = Arrays.asList( "项目","检查","附录","记录","检验结果","结果"); return keywords.stream().anyMatch(s::contains); } /**回归·测试变量*/ public static List itemNames =Arrays.asList( "" ,"压 实 度 (%)下路床 特重、极重交通荷载等级 设计值" ,"1△_压 实 度 (%)_下路床_轻、中及重交通 荷载等级_0.3m~0.8m_≧96_≧95_≧94_实测值或实测偏差值" ,"1△_压 实 度 (%)_下路提_轻、中及重交通 荷载等级_>1.5m_≧93_≧92_≧90_实测值或实测偏差值" ,"1△_压 实 度 (%)_上路提_轻、中及重交通 荷载等级_0.8m~1.5m_≧94_≧94_≧93_实测值或实测偏差值" ,"压 实 度 (%)下路提 轻、中及重交通荷载等级 设计值" ,"压 实 度 (%)下路床 特重、极重交通荷载等级 合格率" ,"压 实 度 (%)下路提 轻、中及重交通荷载等级\t合格率" ,"5△_保护层 厚度 (mm)_基础、锚碇、墩台身、墩柱_±10_实测值或实测偏差值" ,"钢筋骨架尺寸宽、高或直径 (mm)_尺量:按骨架总数30%抽测_±5_实测值或实测偏差值" ,"钢筋骨架尺寸长 (mm)_±10_尺量:按骨架总数30%抽测_实测值或实测偏差值" , "受力钢筋间距 (mm)同排 梁、板、拱肋及拱上建筑 设计值" ,"受力钢筋间距 (mm)同排 梁、板、拱肋及拱上建筑 合格率" ," 箍筋、构造钢筋、螺旋筋间距(mm) 设计值" ,"箍筋、构造钢筋、螺旋筋间距(mm) 合格率" ,"实测项目_桩位 (mm)_群桩_≤100_质量评定_合格判定" ,"实测项目_桩位 (mm)_群桩_≤100_实测值或实测偏差值" ,"实测项目_桩位 (mm)_排架桩_实测值或实测偏差值" ,"实测项目_桩位 (mm)_排架桩_质量评定_合格判定" ,"实测项目_桩位 (mm)_群桩_≤100_质量评定_合格率(%)" ,"实测项目_桩位 (mm)_排架桩_质量评定_合格率(%)" ,"3△_支座高程(mm)_满足设计要求;设 计未要求时±5_水准仪:测每支座中心线_实测值或实测偏差值" ,"基底承载力(KPa)_不小于设计_直观或动力触探试验_实测值或实测偏差值" ,"实 测 项 目_花卉数量_满足设计要求_实测值或实测偏差值" ,"实 测 项 目_2△_草坪、草本地被覆盖率(%)_取弃土场绿 地_≥90_实测值或实测偏差值" ,"轴线偏位(mm)_全站仪:20m检查3点_实测值或实测偏差值" ,"1△_基材混合物喷射厚度(mm)_设计厚度±10_实测值或实测偏差值" ,"1△_混凝土强度 (MPA)_在合格标准内_按附录D检查_实测值或实测偏差值" ,"边坡坡度_不陡于设计值_水准仪:每200m测2点,且不少于5点_实测值或实测偏差值" ,"几何尺寸(mm)_±50_尺量:长、宽、高、壁厚各2点_实测值或实测偏差值" ,"4△_桩长(mm)_不小于设计_查施工记录_实测值或偏差值" ,"单桩每延米喷粉 (浆)量_不小于设计_查施工记录_实测值或偏差值" ,"搭接宽度(mm)_≥150【纵向】_尺量:抽查2%_实测值或实测偏差值", "搭接宽度(mm)_≥50(横向)_尺量:抽查2%_实测值或实测偏差值" ,"竖直度(mm)_挖孔桩_0.5%桩长,且≤200_铅锤线:每桩检测_实测值或实测偏差值" , "2△_压浆压力值 (Mpa)_满足施工技术 规范规定_查油压表读书;每管道检查_实测值或实测偏差值" , "基底承载力(KPa)_不小于设计_实测值或实测偏差值" ,"1△_受力钢筋间距 (mm)_两排以上间距_±5_实测值或实测偏差值" ,"1△梁(板)长度 (mm)_±5_实测值或实测偏差值" ,"墙面平整度(mm)_施工缝、变形缝处≤20_实测值或实测偏差值" ,"基底承载力(KPa)_不小于设计_实测值或实测偏差值" ,"1△_拱部超挖(mm)_Ⅱ、Ⅲ、Ⅳ级围岩(中硬岩 、软岩)_平均150,最大250_实测值或实测偏差值" ,"实 测 项 目_关键项目_压实度(%)_上路堤_轻、中及重交通荷载等级_0.8~1.5m_≥94_≥94_≥93_检查情况 (实测值)" ,"表面平整度(mm)_片石_≤35_检验结果" ); /* public static void main(String[] args) { // itemNames.stream().map(FormulaUtils::parseItemName).forEach(System.out::println); itemNames.stream().map(FormulaUtils::checkItemName).forEach(System.out::println); }*/ public static Object getValue(Cell cell) { if (cell != null) { switch (cell.getCellTypeEnum()) { case STRING: return cell.getStringCellValue() == null ? null : cell.getStringCellValue().trim(); case NUMERIC: HSSFDataFormatter dataFormatter = new HSSFDataFormatter(); return dataFormatter.formatCellValue(cell); case BOOLEAN: return cell.getBooleanCellValue(); case ERROR: return cell.getErrorCellValue(); case FORMULA: try { return cell.getStringCellValue(); } catch (IllegalStateException e) { return ""; } default: cell.setCellType(CellType.STRING); return cell.getStringCellValue() == null ? null : cell.getStringCellValue().trim(); } } return null; } public static List getElementDataList(String coords,String values){ if(StringUtils.isNotEmpty(coords,values)){ List coordsList = Stream.of(coords).flatMap(s -> Arrays.stream(s.split(";"))).map(s -> { String[] xy = s.split("_"); return new Coords(xy[1], xy[0]); }).collect(Collectors.toList()); return str2ElementData(values,coordsList,null,null); } return Collections.emptyList(); } public static List str2ElementData(String pg, List coordsList ,String code,Integer index){ List eds = new ArrayList<>(); if(StringUtils.isNotEmpty(pg)&&ListUtils.isNotEmpty(coordsList)) { if(code==null){ code="code"; } if(index==null){ index=1; } String[] val = pg.split("☆"); Map tmpMap = new LinkedHashMap<>(); for (String s : val) { String[] t = s.split("_\\^_"); String[] c = t[1].split("_"); tmpMap.put(StringUtils.join(code, 0, index, Func.toInt(c[1]), Func.toInt(c[0]), StringPool.AT), t[0]); } for (Coords c : coordsList) { Object data = null; String key = StringUtils.join(code, 0, index, c.getX(), c.getY(), StringPool.AT); if (tmpMap.containsKey(key)) { data = tmpMap.get(key); } eds.add(new ElementData(index, 0, data, c.getX(), c.getY())); } } return eds; } /** * @Description Poi 动态执行公式 测试 * @Param [url] * @Author yangyj * @Date 2023.05.05 14:28 **/ public static void evaluateFormulaCell(String url) { try { url="C:/Users/yangyj/Desktop/test.xlsx"; Workbook workbook = WorkbookFactory.create(new File(url)); Sheet sheet = workbook.getSheetAt(0); Cell cell = sheet.getRow(0).getCell(0); FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator(); CellType cellType = evaluator.evaluateFormulaCellEnum(cell); if (cellType == CellType.NUMERIC) { double value = cell.getNumericCellValue(); System.out.println("公式计算结果:" + value); } else if (cellType == CellType.STRING) { String value = cell.getStringCellValue(); System.out.println("公式计算结果:" + value); } cell.setCellFormula("B1+C1+D1"); evaluator.clearAllCachedResultValues(); cellType = evaluator.evaluateFormulaCellEnum(cell); if (cellType == CellType.NUMERIC) { double value = cell.getNumericCellValue(); System.out.println("公式计算结果:" + value); } else if (cellType == CellType.STRING) { String value = cell.getStringCellValue(); System.out.println("公式计算结果:" + value); } }catch (IOException | InvalidFormatException e){ e.printStackTrace(); } } public static Map getElementCell(String uri){ return getElementCell(uri,null,null); } public static Map getElementCell(String uri,String key) { return getElementCell(uri,key,null); } public static Map getElementCell(String uri,String key,Document document) { try { String filter=" [keyname]"; if(Func.isNotBlank(key)){ filter="[keyname^="+key+"__]"; } if(document==null){ InputStream inputStreamByUrl = FileUtils.getInputStreamByUrl(uri); document=Jsoup.parse(IoUtil.readToString(inputStreamByUrl)); } Map result= document .select("table").first() .select(filter).stream() .map(d -> d.attr("keyname")).filter(StringUtils::isNotEmpty).map(e -> e.split("__")) .collect( Collectors.toMap( b -> b[0], b -> b[1], (v1, v2) -> v1 + ";" + v2 ) ); if(result.size()>0){ for(Map.Entry entry:result.entrySet()){ entry.setValue(FormulaUtils.coordsSorted(entry.getValue())); } } return result; }catch (Exception e){ e.printStackTrace(); return new HashMap<>(); } } public static Map getElementExcelCoords(String uri){ return getElementExcelCoords(uri,null,null); } public static Map getElementExcelCoords(Document document){ return getElementExcelCoords(null,null,document); } public static Map getElementExcelCoords(String uri,String key,Document document){ try { String filter=" [keyname]"; if(Func.isNotBlank(key)){ filter="[keyname^="+key+"__]"; } if(document==null){ InputStream inputStreamByUrl = FileUtils.getInputStreamByUrl(uri); document=Jsoup.parse(IoUtil.readToString(inputStreamByUrl)); } Map result= document .select("table").first() .select(filter).stream() .filter(d -> Func.isNotEmpty(d.attr("keyname"))).filter(StringUtils::isNotEmpty).map(e ->new String[]{e.attr("keyname").split("__")[0],e.attr("y1")+"_"+e.attr("x1")}) .collect( Collectors.toMap( b -> b[0], b -> b[1], (v1, v2) -> v1 + ";" + v2 ) ); if(result.size()>0){ for(Map.Entry entry:result.entrySet()){ entry.setValue(FormulaUtils.coordsSorted(entry.getValue())); } } return result; }catch (Exception e){ e.printStackTrace(); return new HashMap<>(); } } public static LinkedHashMap analyzeHtml(String uri,String key,Document document){ try { String filter=" [keyname]"; if(Func.isNotBlank(key)){ filter="[keyname^="+key+"__]"; } if(document==null){ InputStream inputStreamByUrl = FileUtils.getInputStreamByUrl(uri); document=Jsoup.parse(IoUtil.readToString(inputStreamByUrl)); } LinkedHashMap map= document.select("table").first() .select(filter).stream() .filter(d -> Func.isNotEmpty(d.attr("keyname"))&&d.attr("keyname").split("__")[0].length()>3) .sorted(Comparator.comparingInt(e->Integer.parseInt(e.attr("keyname").split("__")[0].split("_")[1]))) .collect(Collectors.toMap(e->e.attr("placeholder"),e->e.attr("keyname"),(v1,v2)-> v1+","+v2,LinkedHashMap::new)); return map; }catch (Exception e){ e.printStackTrace(); } return new LinkedHashMap<>(); } /* public static void main(String[] args) { String uri="C:\\www\\wwwroot\\Users\\hongchuangyanfa\\Desktop\\privateUrl\\1661661730033369088.html"; analyzeHtml(uri,"",null); }*/ /*解析html里的电签关键字*/ public static Map getESignMap(Document document){ Map result = new HashMap<>(); if(document!=null) { Elements list = document.getElementsByAttribute("dqid"); if (list != null && !list.isEmpty()) { list.stream().forEach(e -> { String dqid = e.attr("dqid"); int y1=0; int x1=0; if (!e.hasAttr("y1") && !e.hasAttr("x1")&&e.children().size()>0) { Element element = e.children().get(0); y1 = Func.toInt(element.attr("y1")); x1 = Func.toInt(element.attr("x1")); }else { y1 = Func.toInt(e.attr("y1")); x1 = Func.toInt(e.attr("x1")); } result.put(y1+"_"+x1,dqid); }); } } return result; } /*保留小数缺失的情况会自动识别小数位*/ public static List setScale(Integer scale, List data){ if(scale==null){ scale=StringUtils.getScale(data.stream().map(ElementData::getValue).filter(StringUtils::isDouble).collect(Collectors.toList())); } Integer finalScale = scale; return data.stream().peek(e->{if(StringUtils.isDouble(e.getValue())){e.setValue(StringUtils.number2StringZero(e.getValue(),finalScale));}}).collect(Collectors.toList()); } /*不会自动识别小数位*/ public static List setScaleMeter(Integer scale, List data){ if(scale!=null){ return data.stream().peek(e->{if(StringUtils.isDouble(e.getValue())){e.setValue(StringUtils.number2StringZero(e.getValue(),scale));}}).collect(Collectors.toList()); } return data; } /** * @Description 定位信息排序 * @Param [coords] * @return java.lang.String * @Author yangyj * @Date 2023.07.11 15:39 **/ public static String coordsSorted(String coords){ if(StringUtils.isNotEmpty(coords)){ List dataList=Arrays.asList(coords.split(";")); if(dataList.size()>2){ LinkedList list=dataList.stream().map(e->e.split("_")[1]).distinct().map(Integer::parseInt).sorted(Comparator.comparingInt(e->e)).collect(Collectors.toCollection(LinkedList::new)); if(list.getLast()-list.getFirst()>list.size()-1){ coords=dataList.stream() .sorted(Comparator.comparingInt((String str) -> Integer.parseInt(str.split("_")[1])) .thenComparingInt(str -> Integer.parseInt(str.split("_")[0]))) .collect(Collectors.joining(";")); } } } return coords; } public static String coordsSorted2(String coords){ if(StringUtils.isNotEmpty(coords)){ List dataList=Arrays.asList(coords.split(";")); if(dataList.size()>2){ /*判断分区:根据行列长度*/ List row =dataList.stream().map(e->e.split("_")[0]).distinct().map(Integer::parseInt).collect(Collectors.toList()); List column=dataList.stream().map(e->e.split("_")[1]).distinct().map(Integer::parseInt).collect(Collectors.toList()); if(row.size()>=column.size()){ /*纵向*/ if(column.size()>1){ List> consecutiveGroups = IntStream.range(0, column.size()) .boxed() .collect(Collectors.collectingAndThen( Collectors.groupingBy( i -> i - column.get(i), LinkedHashMap::new, Collectors.mapping(column::get, Collectors.toList()) ), map -> new ArrayList<>(map.values()) )); } } /* 确定区内方向:*/ } } return coords; } /* public static void main(String[] args) { List column = Arrays.asList(1, 2, 3, 5, 6, 7, 9, 11, 17); List> consecutiveGroups = IntStream.range(0, column.size()) .boxed() .collect(Collectors.collectingAndThen( Collectors.groupingBy( i -> i - column.get(i), LinkedHashMap::new, Collectors.mapping(column::get, Collectors.toList()) ), map -> new ArrayList<>(map.values()) )); AtomicInteger i = new AtomicInteger(column.get(0)); List> consecutiveGroups2= new ArrayList<>(column.stream().collect(Collectors.groupingBy(e -> e - i.getAndSet(e) > 1, LinkedHashMap::new, Collectors.toList())).values()); System.out.println(); }*/ public static List slice(List local, String formula){ int min =0; List result = new ArrayList<>(); try { pretreatment(local,formula); List r= local.stream().map(e-> { /*所有依赖元素的内容必须非空才进行计算,否则返回空值*/ return e.hasEmptyElementValue()?"": Expression.parse(e.getFormula()).calculate(e.getCurrentMap()).toString(); }).collect(Collectors.toList()); if(CollectionUtil.isNotEmpty(r)&&r.stream().anyMatch(StringUtils::isNotEmpty)){ result.addAll(r); } }catch (Exception e){ StaticLog.error("公式:{},执行出错",formula); } return result; } public static void pretreatment(List local,String formula){ formula=StringUtils.removeMultiSpace(formula); if(formula.contains("LIST")){ Matcher m=RegexUtils.matcher("\\(([^)]*)\\)/LIST",formula); while (m.find()){ List codes=getCodeList(m.group(1).replaceAll("[+-]",",")); local=local.stream().peek(e->{ @SuppressWarnings("unckecked") Map map = (Map) e.getCurrentMap().getOrDefault("E",new HashMap<>()); int listSize=(int)codes.stream().filter(c->StringUtils.isNotEmpty(map.get(c))).count(); if(listSize<=0||listSize>codes.size()){ listSize=codes.size(); } map.put("LIST",listSize); }).collect(Collectors.toList()); } } } /**从方法参数中获取全部code*/ public static List getCodeList(String param){ List list = new ArrayList<>(); if(StringUtils.isNotEmpty(param)){ Arrays.stream(param.split(",")).forEach(s->{ list.add(s.replaceAll("[E\\[\\]']","")); }); } return list; } /**从时间段中获取最后一个日期*/ static final String RANGE_DATE_REG="^\\[(\\d{4}[年.\\-]\\d{2}[月.\\-]\\d{2}[日]?),\\s+(\\d{4}[年.\\-]\\d{2}[月.\\-]\\d{2}[日]?)]$"; public static String range2end(String t){ if(t!=null&&Pattern.matches(RANGE_DATE_REG,t)){ t=t.replaceAll("^\\[|]$","").split(",")[1].trim(); } return t; } public static List duration2date(String duration){ try { if (duration != null && Pattern.matches(RANGE_DATE_REG, duration)) { return Arrays.stream(duration.replaceAll("^\\[|]$", "").split(",")).map(String::trim).map(s -> new DateTime(s).toString(DatePattern.NORM_DATE_PATTERN)).collect(Collectors.toList()); } return Collections.singletonList(new DateTime(duration).toString(DatePattern.NORM_DATE_PATTERN)); }catch (Exception e){ return Collections.singletonList(new DateTime().toString(DatePattern.NORM_DATE_PATTERN)); } } public static FormData createFormDataFast(String name,String code,String values,String coords){ if(StringUtils.isNotEmpty(code,name)){ if(StringUtils.isNotEmpty(coords)) { /*定位信息存在才合法*/ List coordsList = Stream.of(coords).flatMap(s -> Arrays.stream(s.split(";"))).map(s -> { String[] xy = s.split("_"); return new Coords(xy[1], xy[0]); }).collect(Collectors.toList()); List eds = new ArrayList<>(); if (StringUtils.isNotEmpty(values)) { String[] pages = values.split(";;"); for (int index = 0; index < pages.length; index++) { String pg = pages[index]; if (Func.isNotBlank(pg)) { String[] val = pg.split("☆"); Map tmpMap = new LinkedHashMap<>(); for (String s : val) { String[] t = s.split("_\\^_"); String[] c = t[1].split("_"); tmpMap.put(StringUtils.join(code, 0, index, Func.toInt(c[1]), Func.toInt(c[0]), StringPool.AT), t[0]); } for (Coords c : coordsList) { Object data = null; String key = StringUtils.join(code, 0, index, c.getX(), c.getY(), StringPool.AT); if (tmpMap.containsKey(key)) { data = tmpMap.get(key); } eds.add(new ElementData(index, 0, data, c.getX(), c.getY())); } } } } else { eds = coordsList.stream().map(c -> new ElementData(0, 0, null, c.getX(), c.getY())).collect(Collectors.toList()); } FormData one = new FormData(code, eds, null, coords); one.setEName(name); /*备份原始数据,用于更新比较*/ one.init(); return one; } } return null; } public static void mainT2(String[] args) throws IOException { XYSeries series = new XYSeries("每月实际完成"); series.add(10.2, 1.82); series.add(11.9, 1.86); series.add(15.9, 1.87); series.add(19.3, 1.85); series.add(20.3, 1.80); XYSeriesCollection dataset = new XYSeriesCollection(); dataset.addSeries(series); JFreeChart chart = ChartFactory.createXYLineChart( "按月进度", // 标题 "X", // 横轴标题 "Y", // 纵轴标题 dataset, // 数据集 PlotOrientation.VERTICAL, // 图表方向 true, // 是否显示图例 false, // 是否生成工具提示 false // 是否生成URL链接 ); // 设置字体 Font titleFont = new Font("SimSun", Font.PLAIN, 18); // 指定使用宋体字体 Font axisFont = new Font("SimSun", Font.PLAIN, 12); // 指定使用宋体字体 // 设置标题字体 TextTitle title = chart.getTitle(); title.setFont(titleFont); XYPlot plot = (XYPlot) chart.getPlot(); XYSplineRenderer renderer = new XYSplineRenderer(); plot.setRenderer(renderer); plot.setBackgroundPaint(Color.WHITE); // Set the line stroke and shape for the renderer renderer.setSeriesStroke(0, new BasicStroke(2.0f)); Shape circle = new Ellipse2D.Double(-3, -3, 6, 6); renderer.setSeriesShape(0, circle); renderer.setSeriesPaint(0, Color.BLUE); // 自定义 X 轴刻度 NumberAxis domainAxis = (NumberAxis) plot.getDomainAxis(); domainAxis.setTickUnit(new NumberTickUnit(5)); // 设置刻度间隔 domainAxis.setRange(0.0, 25); // 设置轴的范围 // 自定义 Y 轴刻度 NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis(); rangeAxis.setTickUnit(new NumberTickUnit(0.01)); // 设置刻度间隔 rangeAxis.setRange(1.79, 1.90); // 设置轴的范围 // 添加横杠 for(int i=175;i<190;i++){ ValueMarker marker = new ValueMarker((double) i /100); marker.setPaint(Color.BLUE); // 横杠的颜色 plot.addRangeMarker(marker); } ChartPanel chartPanel = new ChartPanel(chart); chartPanel.setPreferredSize(new Dimension(500, 400)); // 保存图表为图片 int width = 800; int height = 600; ChartUtils.saveChartAsPNG(new File("C:/Users/yangyj/Desktop/Swap_space/poi_statistics.png"), chart, width, height); } private static CategoryDataset createDataset( double[] actualProgress, double[] plannedProgress) { String[] months = {"一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"}; /* int[] actualProgress = {10, 15, 18, 27, 35, 48}; int[] plannedProgress = {10, 15, 20, 25, 30, 35};*/ DefaultCategoryDataset dataset = new DefaultCategoryDataset(); for (int i = 0; i < actualProgress.length; i++) { dataset.addValue(actualProgress[i], "实际进度", months[i]); } for (int i = 0; i < plannedProgress.length; i++) { dataset.addValue(plannedProgress[i], "计划进度", months[i]); } return dataset; } private static JFreeChart createChart(CategoryDataset dataset) { JFreeChart chart = ChartFactory.createBarChart( "施工进度对比图", "月份", "进度 (%)", dataset, PlotOrientation.VERTICAL, true, true, false ); CategoryPlot plot = (CategoryPlot) chart.getPlot(); // 设置中文字体以避免乱码 Font font = new Font("宋体", Font.PLAIN, 12); chart.getTitle().setFont(font); plot.getDomainAxis().setTickLabelFont(font); plot.getDomainAxis().setLabelFont(font); plot.getRangeAxis().setTickLabelFont(font); plot.getRangeAxis().setLabelFont(font); chart.getLegend().setItemFont(font); plot.setDomainAxis(new CategoryAxis("月份")); plot.setRangeAxis(new NumberAxis("进度 (%)")); BarRenderer barRenderer = new BarRenderer(); barRenderer.setSeriesPaint(0, new Color(0, 0, 255)); barRenderer.setSeriesPaint(1, new Color(0, 255, 0)); plot.setRenderer(barRenderer); // 添加第二个数据集,绘制为曲线 DefaultCategoryDataset lineDataset = new DefaultCategoryDataset(); String[] months = {"一月", "二月", "三月", "四月", "五月", "六月"}; int[] actualProgress = {10, 15, 18, 27, 35, 48}; int[] plannedProgress = {10, 15, 20, 25, 30, 35}; for (int i = 0; i < actualProgress.length; i++) { lineDataset.addValue(actualProgress[i], "实际进度", months[i]); } for (int i = 0; i < plannedProgress.length; i++) { lineDataset.addValue(plannedProgress[i], "计划进度", months[i]); } plot.setDataset(1, lineDataset); plot.mapDatasetToRangeAxis(1, 0); LineAndShapeRenderer lineRenderer = new LineAndShapeRenderer(); lineRenderer.setSeriesPaint(0, new Color(255, 0, 0)); lineRenderer.setSeriesPaint(1, new Color(255, 165, 0)); plot.setRenderer(1, lineRenderer); // 设置 X 轴标签 CategoryAxis domainAxis = plot.getDomainAxis(); domainAxis.setCategoryLabelPositions( org.jfree.chart.axis.CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 4.0) ); // 设置 Y 轴范围 ValueAxis rangeAxis = plot.getRangeAxis(); rangeAxis.setRange(0, 100); return chart; } public static String getSysLocalFileUrl() { String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL); if (org.springblade.common.utils.SystemUtils.isMacOs()) { file_path = "/Users/hongchuangyanfa/Desktop/"; } else if (SystemUtils.isWindows()) { file_path = "C://upload//"; } return file_path; } public static byte[] chapterScheduleChart( double[] actualProgress ,double[] plannedProgress){ CategoryDataset dataset = createDataset(actualProgress,plannedProgress); JFreeChart chart = createChart(dataset); try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { ChartUtils.writeChartAsPNG(out, chart, 800, 600); return out.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return null; } public static String chapterScheduleChartUrl( LinkedHashMap actualMap, LinkedHashMap plannedMap,int startYear,int endYear){ try { JFreeChart chart =chartTest(actualMap,plannedMap, startYear, endYear); String path= getSysLocalFileUrl() + "/pdf//"+SnowFlakeUtil.getId()+".png"; ChartUtils.saveChartAsPNG(new File(path), chart, 1200, 900); return path; } catch (Exception e) { e.printStackTrace(); } return null; } public static JFreeChart chartTest2(double[] actualProgressData ,double[] plannedProgressData) throws IOException { // 创建数据集 XYSeries actualProgress = new XYSeries("实际进度"); XYSeries plannedProgress = new XYSeries("计划进度"); // 填充数据集 for (int i = 0; i < actualProgressData.length; i++) { actualProgress.add(i, actualProgressData[i]); plannedProgress.add(i, plannedProgressData[i]); } XYSeriesCollection dataset = new XYSeriesCollection(); dataset.addSeries(actualProgress); dataset.addSeries(plannedProgress); // 创建图表 JFreeChart chart = ChartFactory.createXYLineChart( "施工进度对比图", // 标题 "日期进度 (%)", // X轴标签 "完成量 (%)", // Y轴标签 dataset, // 数据集 org.jfree.chart.plot.PlotOrientation.VERTICAL, // 方向 true, // 显示图例 true, // 生成工具 false // 生成URL ); // 设置中文字体以避免乱码 Font font = new Font("宋体", Font.PLAIN, 12); chart.getTitle().setFont(font); chart.getLegend().setItemFont(font); XYPlot plot = chart.getXYPlot(); plot.setDomainGridlinesVisible(true); plot.setRangeGridlinesVisible(true); plot.setDomainGridlinePaint(Color.LIGHT_GRAY); plot.setRangeGridlinePaint(Color.LIGHT_GRAY); plot.setBackgroundPaint(Color.WHITE); XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(); renderer.setSeriesPaint(0, Color.BLUE); renderer.setSeriesPaint(1, Color.GREEN); plot.setRenderer(renderer); // 设置顶部的月份轴 /* String[] months = {"一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"}; String[] years = {"2023年", "2024年", "2025年", "2026年"};*/ String[] months =new String[4 * 12]; for(int i=2023;i<=2026;i++){ for(int n=1;n<=12;n++){ int index=(i-2023)*12+n-1; months[index]=i+"年"+n+"月"; } } // 设置顶部的月份轴 SymbolAxis monthAxis = new SymbolAxis("月份", months) ; monthAxis.setTickLabelFont(font); monthAxis.setLabelFont(font); monthAxis.setVerticalTickLabels(true); monthAxis.setRange(0, 47); // 设置范围来适应月份标签 plot.setDomainAxis(monthAxis); // 设置Y轴的范围 NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis(); rangeAxis.setRange(0, 100); // Y轴从0到100 rangeAxis.setTickUnit(new NumberTickUnit(10)); rangeAxis.setLabelFont(font); rangeAxis.setTickLabelFont(font); /* // 添加月份轴 plot.setRangeAxis(2, monthAxis); plot.mapDatasetToDomainAxis(0, 1); // 将数据映射到月份轴*/ return chart; } public static JFreeChart chartTest(LinkedHashMap actualMap, LinkedHashMap plannedMap,int startYear,int endYear) { // 创建完整的数据集 XYSeriesCollection dataset = new XYSeriesCollection(); // 创建日期范围 long startDate=BaseUtils.getTimeMs(startYear,4); long endDate = BaseUtils.getTimeMs(endYear,12); // 初始化数据系列 XYSeries actualSeries = new XYSeries("实际进度"); XYSeries plannedSeries = new XYSeries("计划进度"); // 填充数据系列 actualMap.forEach((yearMonth,ratio)->{ actualSeries.add(BaseUtils.getTimeMs(yearMonth/100,yearMonth%100),ratio); }); plannedMap.forEach((yearMonth,ratio)->{ plannedSeries.add(BaseUtils.getTimeMs(yearMonth/100,yearMonth%100),ratio); }); dataset.addSeries(actualSeries); dataset.addSeries(plannedSeries); // 创建图表 JFreeChart chart = ChartFactory.createTimeSeriesChart( "", "", "", dataset, true, true, false); // 设置中文字体以避免乱码 Font font = new Font("宋体", Font.PLAIN, 12); chart.getTitle().setFont(font); chart.getLegend().setItemFont(font); chart.getLegend().setVisible(false); XYPlot plot = (XYPlot) chart.getPlot(); plot.setDomainGridlinesVisible(false); plot.setRangeGridlinesVisible(false); plot.setDomainGridlinePaint(Color.LIGHT_GRAY); plot.setRangeGridlinePaint(Color.LIGHT_GRAY); plot.setBackgroundPaint(Color.WHITE); XYItemRenderer renderer = new XYSplineRenderer(); // 设置第一个系列为实线 renderer.setSeriesPaint(0, Color.GREEN); // 设置颜色 renderer.setSeriesStroke(0, new BasicStroke(2.0f)); // 设置实线 // 设置第二个系列为虚线 renderer.setSeriesPaint(1, Color.BLUE); // 设置颜色 renderer.setSeriesStroke(1, new BasicStroke( 0.3f, // 线宽 BasicStroke.CAP_SQUARE, // 端点样式 BasicStroke.JOIN_BEVEL, // 连接点样式 0.0f, // 斜接长度 new float[]{10.0f, 10f}, // 虚线模式:10像素线,6像素空白 0.0f // 偏移量 )); plot.setRenderer(renderer); plot.setInsets(new RectangleInsets(0, 0, 0, 0)); // 设置 DateAxis DateAxis monthAxis = (DateAxis) plot.getDomainAxis(); monthAxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE); monthAxis.setDateFormatOverride(new SimpleDateFormat("yyyy年MM月")); monthAxis.setTickLabelsVisible(true); // 禁用标签 monthAxis.setTickLabelFont(font); monthAxis.setLabelFont(font); monthAxis.setLowerBound(startDate); monthAxis.setUpperBound(endDate); // 确保每个月都有一个标签 monthAxis.setTickUnit(new DateTickUnit(DateTickUnitType.MONTH,1)); monthAxis.setVerticalTickLabels(true); // 设置Y轴的范围 NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis(); rangeAxis.setRange(0, 100); rangeAxis.setTickUnit(new NumberTickUnit(10)); rangeAxis.setLabelFont(font); rangeAxis.setTickLabelFont(font); rangeAxis.setVisible(false); rangeAxis.setLabelInsets(new RectangleInsets(0, 0, 0, 0)); chart.setPadding(new RectangleInsets(0, 0, 0, 0)); return chart; } public static void mainT(String[] args) throws IOException { LinkedHashMap actualProgress = new LinkedHashMap<>(); actualProgress.put(202311,5.0); actualProgress.put(202312,10.2); actualProgress.put(202401,14.99); actualProgress.put(202402,19.7); actualProgress.put(202403,23.6); LinkedHashMap plannedProgress = new LinkedHashMap<>(); plannedProgress.put(202311,3.0); plannedProgress.put(202312,6.0); plannedProgress.put(202401,8.0); plannedProgress.put(202402,9.0); plannedProgress.put(202403,12.0); JFreeChart chart = chartTest(actualProgress,plannedProgress,2023,2025); /* try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { BufferedImage bufferedImage = chart.createBufferedImage(800, 600); ImageIO.write(bufferedImage, "png", out); FileOutputStream fos = new FileOutputStream("C:/Users/yangyj/Desktop/Swap_space/poi_statistics.png"); fos.write(out.toByteArray()); } catch (IOException e) { e.printStackTrace(); }*/ try { ChartUtils.saveChartAsPNG(new File("C:/Users/yangyj/Desktop/Swap_space/poi_statistics.png"), chart, 1200, 900); // 保存图表到内存 } catch (Exception e) { e.printStackTrace(); } } /**字符串sha256映射*/ public static String sha256(String input) { try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] encodedHash = digest.digest(input.getBytes(StandardCharsets.UTF_8)); StringBuilder hexString = new StringBuilder(); for (byte b : encodedHash) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); } return hexString.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return ""; } /**根据步长获取字符*/ public static String getEveryNthChar(String input, int step) { StringBuilder result = new StringBuilder(); for (int i = 0; i < input.length(); i += step) { result.append(input.charAt(i)); } return result.toString(); } /**最大循环次数*/ public static int MAX_LOOP=20; /** * @Description 当前提交表单数据公式执行最小影响元素范围 * @Param [curTableNames:当前提交页面对应表编号, processFds:当前工序包含的所有元素] * @Author yangyj * @Date 2023.10.09 15:26 **/ public static List registerFd(List curTableNames, List processFds){ Map> group = processFds.stream().collect(Collectors.partitioningBy(e->curTableNames.contains(e.getTableName()))); List curFormDatas =group.get(true); /*提交叶包含元素*/ List initiator= new ArrayList<>(curFormDatas); List other=group.get(false); /*当前提交页元素影响到的元素都要重新执行公式*/ pick(curFormDatas,other,curFormDatas,fds->fds.stream().map(FormData::getCode).collect(Collectors.toSet())); /*当前提交页的元素公式依赖加载*/ pick(initiator,other,curFormDatas,fds->fds.stream().filter(f->f.executable()&&f.getFormula().getRely()!=null).flatMap(f->f.getFormula().getRelyList().stream()).collect(Collectors.toSet())); return curFormDatas; } /** * @Description 调训符合条件的元素 * @Param [initiator 初始集合, other 待选集合, curFormDatas 结果集, function:挑选方法] * @Author yangyj * @Date 2023.10.12 14:53 **/ public static void pick(List initiator,List other,List curFormDatas ,Function,Set> function){ List curFormDatasAdd=new ArrayList<>(initiator); int loop=0; do{ loop++; Set codeSet= function.apply(curFormDatasAdd); Map> groupTmp = other.stream().collect(Collectors.partitioningBy(e->codeSet.contains(e.getCode()))); curFormDatasAdd=groupTmp.get(true); if(curFormDatasAdd.isEmpty()){ loop=MAX_LOOP; }else{ curFormDatas.addAll(curFormDatasAdd); } other=groupTmp.get(false); }while (!other.isEmpty()&&loop> relatedPages(List curFormDatas ,List tableAll){ Set initTableNames= curFormDatas.stream().map(FormData::getTableName).collect(Collectors.toSet()); return tableAll.stream().filter(e->initTableNames.contains(e.getInitTableName())).collect(Collectors.groupingBy(NodeTable::getInitTableName,Collectors.mapping(NodeTable::getPKeyId,Collectors.toList()))); } /*比较两组单元格内容是否一样*/ public static boolean compareElementDataList(List before ,List cur){ if(Func.isNotEmpty(before)&&Func.isNotEmpty(cur)&&before.size()==cur.size()){ String sa= before.stream().map(ElementData::stringValue).collect(Collectors.joining()); String sc= cur.stream().map(ElementData::stringValue).collect(Collectors.joining()); return sa.equals(sc); } return false; } /**分割treeCode*/ public static List treeCodeSplit(String treeCode){ List result = new ArrayList<>(); if(Func.isNotBlank(treeCode)){ /*字符总长度*/ int max =treeCode.length()-3, /*累计字符长度字符*/ sum=0, /*第几次循环*/ count=0; do{ result.add(treeCode.substring(0, sum+=Math.min(3,++count))); }while (sum list,int n){ /*System.out.println("剩余计算次数:"+n+"次");*/ if(move(list)&&n>0){ sort(list,--n); } } public static Boolean move( List list){ for(int i=0;i cp = new ArrayList<>(); while (m.find()){ cp.add(m.group()); } Map> map= list.stream().skip(i+1).collect(Collectors.partitioningBy(e->cp.contains(e.getCode()))); List match =map.get(true); if(CollectionUtil.isNotEmpty(match)){ for(FormData r:match){ list.remove(r); } list.addAll(0,match); return true; } } return false; } public static void relyParse(Formula f){ if(Func.isNotBlank(f.getFormula())){ List l = new ArrayList<>(); Matcher m = P.matcher(f.getFormula()); while (m.find()){ String tmp =m.group().replaceAll("'",""); String cp=tmp; if(tmp.indexOf(StringPool.COLON)!=tmp.lastIndexOf(StringPool.COLON)){ tmp=tmp.substring(tmp.indexOf(":")+1); /*移除跨节点标识*/ f.setFormula(f.getFormula().replace(cp,tmp)); } l.add(tmp); } if(l.size()>0){ f.setRely(String.join(",", l)); }else{ f.setRely(""); } } } /*复制表页*/ public static WbsTreeContract copyPage(WbsTreeContract origin){ WbsTreeContract target = new WbsTreeContract(); BeanUtil.copy(origin, target); target.setPKeyId(SnowFlakeUtil.getId()); target.setCreateTime(new Date()); String nodeName = origin.getNodeName(); String[] oldName = nodeName.split("__"); if (oldName.length>1) { nodeName = oldName[0] + "__" + (Integer.parseInt(oldName[1]) + 1); } else { nodeName = nodeName + "__" + 1; } target.setNodeName(nodeName); target.setIsCopeTab(2); target.setIsTabPdf(1); // pdf 不能预览 target.setIsBussShow(1); // 是否隐藏表 target.setTabFileType(1);//没有上传附件 target.setPdfUrl(""); return target; } public static String recovery(List dataList) { if (Func.isNotEmpty(dataList)) { return dataList.stream().filter(e -> !e.isEmpty()).map(e -> e.stringValue() + "_^_" + e.getY() + "_" + e.getX()).collect(Collectors.joining("☆")); } return ""; } private static final Map CHINESE_TO_ARABIC = new HashMap<>(); static { CHINESE_TO_ARABIC.put('零', 0); CHINESE_TO_ARABIC.put('一', 1); CHINESE_TO_ARABIC.put('二', 2); CHINESE_TO_ARABIC.put('三', 3); CHINESE_TO_ARABIC.put('四', 4); CHINESE_TO_ARABIC.put('五', 5); CHINESE_TO_ARABIC.put('六', 6); CHINESE_TO_ARABIC.put('七', 7); CHINESE_TO_ARABIC.put('八', 8); CHINESE_TO_ARABIC.put('九', 9); CHINESE_TO_ARABIC.put('十', 10); CHINESE_TO_ARABIC.put('百', 100); CHINESE_TO_ARABIC.put('千', 1000); CHINESE_TO_ARABIC.put('万', 10000); } public static int chineseToArabic(String chineseNumber) { int result = 0; int multiplier = 1; for (int i = chineseNumber.length() - 1; i >= 0; i--) { char c = chineseNumber.charAt(i); if (CHINESE_TO_ARABIC.containsKey(c)) { int value = CHINESE_TO_ARABIC.get(c); if(value!=0&&value%10==0&&i!=0){ multiplier=value; }else{ result=result+value*multiplier; } } else { throw new IllegalArgumentException("Invalid Chinese numeral: " + c); } } return result; } /*public static void main(String[] args) { *//* System.out.println(chineseToArabic("二十九")); System.out.println(chineseToArabic("一")); System.out.println(chineseToArabic("十一"));*//* System.out.println(chineseToArabic("十")); *//* System.out.println(chineseToArabic("一百二十")); System.out.println(chineseToArabic("一百二十二")); System.out.println(chineseToArabic("一百零二"));*//* }*/ /*获取引用code的元素*/ public static Stream beRelyFrom( Map formDataMap ,String code){ return formDataMap.values().stream().filter(e->e.executable()&& code.equals(e.getFormula().getRely())); } public static Stream beRelyFrom( Map formDataMap ,String tableNumber ,String keys){ Set keySet = Arrays.stream(keys.split(",")).map(s->tableNumber+":"+s.trim()).collect(Collectors.toSet()); return formDataMap.values().stream().filter(e->e.executable()&& keySet.contains(e.getFormula().getRely())); } /*根据code查找元素 */ public static Optional elementFindByCode( Map formDataMap ,String code){ return formDataMap.values().stream().filter(e->code.equals(e.getCode())).findAny(); } /*根据key查找元素 ,用于元素范围在同一张表情况*/ public static Optional elementFindByKey( Map fdm ,String key){ return fdm.values().stream().filter(e->key.equals(e.getCode().split(":")[1])).findAny(); } /*创建T集合的指定字段fb的合计方法*/ public static Function, String> createSumFunction(Function fb) { return (pl) -> pl.stream() .map(fb) .reduce(BigDecimal.ZERO, BigDecimal::add) .toPlainString(); } public static Optional getScale(String unit){ if(StringUtils.isNotEmpty(unit)) { unit=unit.toLowerCase(Locale.ROOT); if (unit.contains("吨")||unit.contains("t")){ return Optional.of(3); }else if (unit.contains("米")||unit.contains("m")){ return Optional.of(2); }else if (RegexUtil.find("个|项|台|套|棵|块|处|座|kg",unit)){ return Optional.of(0); } } return Optional.empty(); } public static List getTableInfoList(JSONArray dataArray) { if (dataArray != null && !dataArray.isEmpty()) { List result = new ArrayList<>(); for (int m = 0; m < dataArray.size(); m++) { TableInfo tableInfo = new TableInfo(); com.alibaba.fastjson.JSONObject dataInfo2 = dataArray.getJSONObject(m); // tableInfo.setContractId(dataInfo2.getString("contractId")); tableInfo.setPkeyId(dataInfo2.getString("pkeyId")); tableInfo.setProjectId(dataInfo2.getString("projectId")); //huangjn 填报的类型,施工或监理 tableInfo.setClassify(dataInfo2.getString("classify")); //设置首件信息 setFirstData(dataInfo2, tableInfo); //设置日志信息 setTheLogData(dataInfo2, tableInfo); dataInfo2.fluentRemove("contractId") .fluentRemove("pkeyId") .fluentRemove("p_key_id") .fluentRemove("projectId") .fluentRemove("classify") .fluentRemove("pickerKey") .fluentRemove("id") .fluentRemove("isFirst") .fluentRemove("firstNodeId") .fluentRemove("isTheLog") .fluentRemove("theLogId") .fluentRemove("linkTabIds") .fluentRemove("recordTime") .fluentRemove("businessId") .fluentRemove("sourceUrl") .fluentRemove("pdfUrl") .fluentRemove("firstFileName") .fluentRemove(""); // 计算数据 LinkedHashMap> dataMap = dataInfo2.keySet().stream().filter(e -> e.contains("__")).collect(Collectors.groupingBy(e -> e.split("__")[0], LinkedHashMap>::new, Collectors.toList())); LinkedHashMap dataMap2 = new LinkedHashMap<>(); // 字段组合 for (String k : dataMap.keySet()) { if (dataMap.get(k).size() > 1 && !dataMap.get(k).contains("000Z")) { String[] ziduan = dataMap.get(k).toArray(new String[]{}); String temp = ""; for (int i = 0; i < ziduan.length - 1; i++) { for (int j = 0; j < ziduan.length - i - 1; j++) { Integer tr = Integer.parseInt((ziduan[j].split("__")[1]).split("_")[0]); Integer td = Integer.parseInt(ziduan[j].split("__")[1].split("_")[1]); Integer tr_1 = Integer.parseInt(ziduan[j + 1].split("__")[1].split("_")[0]); Integer td_1 = Integer.parseInt(ziduan[j + 1].split("__")[1].split("_")[1]); if (tr > tr_1 && td.equals(td_1)) { //纵向排序 temp = ziduan[j]; ziduan[j] = ziduan[j + 1]; ziduan[j + 1] = temp; } } } String lastStr = dataInfo2.getString(ziduan[0]) + "_^_" + ziduan[0].split("__")[1]; for (int i = 1; i < ziduan.length; i++) { String keyData = dataInfo2.getString(ziduan[i]); if (org.apache.commons.lang.StringUtils.isNotEmpty(keyData) && !keyData.equals("")) { lastStr += "☆" + dataInfo2.getString(ziduan[i]) + "_^_" + ziduan[i].split("__")[1]; } } dataMap2.put(k, lastStr); } else { String dataVal = dataInfo2.getString(dataMap.get(k).get(0)); if (org.apache.commons.lang.StringUtils.isNotEmpty(dataVal)) { if (dataVal.contains("Ljava")) { Object o = dataInfo2.get(dataMap.get(k).get(0)); dataVal = JSON.toJSONString(o).replace("\"", ""); } dataMap2.put(k, dataVal + "_^_" + dataMap.get(k).get(0).split("__")[1]); } } } dataInfo2.put("p_key_id", tableInfo.getPkeyId()); dataInfo2.put("classify",tableInfo.getClassify()); dataInfo2.put("contractId",tableInfo.getContractId()); dataInfo2.put("projectId",tableInfo.getProjectId()); tableInfo.setDataMap(dataMap2); result.add(tableInfo); } return result; } return null; } public static void setFirstData(com.alibaba.fastjson.JSONObject dataInfo2, TableInfo tableInfo) { //huangjn 判断是否是首件 if (dataInfo2.containsKey("isFirst")) { tableInfo.setIsFirst(dataInfo2.getString("isFirst")); } //huangjn 判断是否是首件 //首件资料绑定的节点 if (dataInfo2.containsKey("firstNodeId")) { tableInfo.setFirstNodeId(dataInfo2.getString("firstNodeId")); } //首件ID(编辑时有值,新增时为空) if (dataInfo2.containsKey("firstId")) { tableInfo.setFirstId(dataInfo2.getString("firstId")); } //源文件 if (dataInfo2.containsKey("sourceUrl")) { tableInfo.setSourceUrl(dataInfo2.getString("sourceUrl")); } //pdfUrl if (dataInfo2.containsKey("pdfUrl")) { tableInfo.setPdfUrl(dataInfo2.getString("pdfUrl")); } //文件名称 if (dataInfo2.containsKey("firstFileName")) { tableInfo.setFirstFileName(dataInfo2.getString("firstFileName")); } //关联的信息 if (dataInfo2.containsKey("linkProcessList")) { tableInfo.setLinkProcessList(dataInfo2.getJSONArray("linkProcessList")); } } public static void setTheLogData(JSONObject dataInfo2, TableInfo tableInfo) { //huangjn 判断是否是日志 if (dataInfo2.containsKey("isTheLog")) { tableInfo.setIsTheLog(dataInfo2.getString("isTheLog")); } //huangjn 判断是否是日志 //huangjn 日志ID if (dataInfo2.containsKey("theLogId")) { tableInfo.setTheLogId(dataInfo2.getString("theLogId")); } //huangjn 日志ID //huangjn 日志勾选的工序 if (dataInfo2.containsKey("linkTabIds")) { tableInfo.setLinkTabIds(dataInfo2.getJSONArray("linkTabIds")); } //huangjn 日志勾选的工序 //huangjn 日志所选时间 if (dataInfo2.containsKey("recordTime")) { tableInfo.setRecordTime(dataInfo2.getString("recordTime")); } //huangjn 日志所选时间 //huangjn 每份填报数据的id,目前日志专用 if (dataInfo2.containsKey("id")) { tableInfo.setBusinessId(dataInfo2.getString("id")); } //huangjn 每份填报数据的id,目前日志专用 } }