FormulaUtils.java 85 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968
  1. package com.mixsmart.utils;
  2. import cn.hutool.core.date.DatePattern;
  3. import cn.hutool.core.date.DateTime;
  4. import cn.hutool.log.StaticLog;
  5. import com.alibaba.fastjson.JSON;
  6. import com.alibaba.fastjson.JSONArray;
  7. import com.alibaba.fastjson.JSONObject;
  8. import com.alibaba.fastjson.annotation.JSONField;
  9. import com.itextpdf.text.pdf.PdfReader;
  10. import com.itextpdf.text.pdf.parser.*;
  11. import com.jfireel.expression.Expression;
  12. import org.apache.commons.lang.math.NumberUtils;
  13. import org.apache.http.*;
  14. import org.apache.http.client.HttpClient;
  15. import org.apache.http.client.entity.UrlEncodedFormEntity;
  16. import org.apache.http.client.methods.HttpGet;
  17. import org.apache.http.client.methods.HttpPost;
  18. import org.apache.http.entity.StringEntity;
  19. import org.apache.http.impl.client.HttpClientBuilder;
  20. import org.apache.http.impl.client.HttpClients;
  21. import org.apache.http.message.BasicNameValuePair;
  22. import org.apache.http.util.EntityUtils;
  23. import org.apache.poi.hssf.usermodel.HSSFDataFormatter;
  24. import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
  25. import org.apache.poi.ss.usermodel.*;
  26. import java.awt.Color;
  27. import org.jfree.chart.ChartFactory;
  28. import org.jfree.chart.ChartPanel;
  29. import org.jfree.chart.ChartUtils;
  30. import org.jfree.chart.JFreeChart;
  31. import org.jfree.chart.axis.*;
  32. import org.jfree.chart.plot.*;
  33. import org.jfree.chart.renderer.category.BarRenderer;
  34. import org.jfree.chart.renderer.category.LineAndShapeRenderer;
  35. import org.jfree.chart.renderer.xy.XYItemRenderer;
  36. import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
  37. import org.jfree.chart.renderer.xy.XYSplineRenderer;
  38. import org.jfree.chart.title.TextTitle;
  39. import org.jfree.chart.ui.RectangleEdge;
  40. import org.jfree.chart.ui.RectangleInsets;
  41. import org.jfree.chart.ui.TextAnchor;
  42. import org.jfree.data.category.CategoryDataset;
  43. import org.jfree.data.category.DefaultCategoryDataset;
  44. import org.jfree.data.xy.XYSeries;
  45. import org.jfree.data.xy.XYSeriesCollection;
  46. import org.jsoup.Jsoup;
  47. import org.jsoup.nodes.Document;
  48. import org.jsoup.nodes.Element;
  49. import org.jsoup.select.Elements;
  50. import org.springblade.common.constant.CommonConstant;
  51. import org.springblade.common.utils.BaseUtils;
  52. import org.springblade.common.utils.SnowFlakeUtil;
  53. import org.springblade.common.utils.SystemUtils;
  54. import org.springblade.core.tool.utils.*;
  55. import org.springblade.manager.bean.TableInfo;
  56. import org.springblade.manager.dto.*;
  57. import org.springblade.manager.entity.Formula;
  58. import org.springblade.manager.entity.WbsTreeContract;
  59. import org.springblade.manager.formula.NodeTable;
  60. import org.springblade.manager.formula.impl.CompositeDataAccess;
  61. import org.springblade.manager.formula.impl.TableElementConverter;
  62. import org.springblade.manager.utils.FileUtils;
  63. import org.springblade.manager.vo.*;
  64. import org.springblade.system.cache.ParamCache;
  65. import org.springframework.core.annotation.AnnotationUtils;
  66. import reactor.core.publisher.Mono;
  67. import javax.imageio.ImageIO;
  68. import java.awt.*;
  69. import java.awt.Font;
  70. import java.awt.Shape;
  71. import java.awt.geom.AffineTransform;
  72. import java.awt.geom.Ellipse2D;
  73. import java.awt.geom.Rectangle2D;
  74. import java.awt.image.BufferedImage;
  75. import java.io.*;
  76. import java.lang.annotation.Annotation;
  77. import java.lang.reflect.Field;
  78. import java.math.BigDecimal;
  79. import java.nio.charset.StandardCharsets;
  80. import java.security.MessageDigest;
  81. import java.security.NoSuchAlgorithmException;
  82. import java.text.SimpleDateFormat;
  83. import java.time.LocalDate;
  84. import java.time.LocalDateTime;
  85. import java.util.*;
  86. import java.util.List;
  87. import java.util.concurrent.ThreadLocalRandom;
  88. import java.util.concurrent.atomic.AtomicInteger;
  89. import java.util.function.BiFunction;
  90. import java.util.function.Function;
  91. import java.util.regex.Matcher;
  92. import java.util.regex.Pattern;
  93. import java.util.stream.Collectors;
  94. import java.util.stream.IntStream;
  95. import java.util.stream.Stream;
  96. import static java.util.regex.Pattern.*;
  97. /**
  98. * @author yangyj
  99. * @Date 2022/7/14 15:55
  100. * @description 公式工具类
  101. */
  102. public class FormulaUtils {
  103. public static final String ELE_CODE_REG= "(?<=E\\[)[^]]+(?=])";
  104. public static final Pattern P = Pattern.compile(ELE_CODE_REG);
  105. /**元素标识*/
  106. public final static String E="E";
  107. /*确定各个元素在计算时的步长,算法:step=最长单元格数/当前元素单元格数*/
  108. public static LinkedHashMap<String,FormData> step(List<FormData> ele){
  109. LinkedHashMap<String,FormData> fdMap =new LinkedHashMap<>();
  110. FormData maxFormData = Collections.max(ele, Comparator.comparingInt((FormData ef)->ef.getValues().size()));
  111. FormData minFormData = Collections.min(ele, Comparator.comparingInt((FormData ef)->ef.getValues().size()));
  112. if (maxFormData.getValues().size() != minFormData.getValues().size()) {
  113. int baseLength = maxFormData.getValues().size();
  114. for (FormData formData : ele) {
  115. formData.setStep(baseLength / formData.getValues().size());
  116. }
  117. }
  118. ele.forEach(e->{
  119. fdMap.put(e.getCode(),e);
  120. });
  121. return fdMap;
  122. }
  123. /*确定公式执行环境变量*/
  124. public static List<LocalVariable> slice2Local(String f, LinkedHashMap<String,FormData> fdMap, TableElementConverter tec){
  125. CompositeDataAccess cda = new CompositeDataAccess(fdMap);
  126. List<LocalVariable> local= new ArrayList<>();
  127. while (cda.hasNext()){
  128. LinkedHashMap<String,ElementData> tip= cda.next();
  129. Map<String, Object> variable = new HashMap<>(tec.constantMap);
  130. @SuppressWarnings("unchecked")
  131. Map<String,Object> em= (Map<String, Object>) variable.computeIfAbsent(E, k->new HashMap<>());
  132. Integer index= new ArrayList<>(tip.values()).get(0).getIndex();
  133. for(Map.Entry<String,ElementData> se:tip.entrySet()){
  134. Object value=se.getValue().getValue();
  135. if(CustomFunction.isNumber(value)){
  136. if(StringUtils.isDouble(value)||f.contains("/")){
  137. em.put(se.getKey(),Double.parseDouble(value.toString()));
  138. }else{
  139. em.put(se.getKey(),StringUtils.handleObj2Integer(value));
  140. }
  141. }else{
  142. em.put(se.getKey(),StringUtils.handleNull(value).replaceAll("[ ]+","").trim());
  143. }
  144. }
  145. local.add(new LocalVariable(index,f,variable));
  146. }
  147. return local;
  148. }
  149. public static void putEle(String f,List<FormData> ele,Map<String, Object> currentMap,FormData fd){
  150. @SuppressWarnings("unchecked")
  151. Map<String,Object> em = (Map<String, Object>) currentMap.computeIfAbsent(E,(k)-> new HashMap<>());
  152. /*如果输入输出元素都是1对1*/
  153. 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){
  154. ele.forEach(e->{
  155. Object value=e.getValues().get(0).getValue();
  156. if(CustomFunction.isNumber(value)){
  157. if(StringUtils.isDouble(value)||f.contains("/")){
  158. em.put(e.getCode(), Double.parseDouble(value.toString()));
  159. }else{
  160. em.put(e.getCode(),StringUtils.handleObj2Integer(value));
  161. }
  162. }else{
  163. em.put(e.getCode(),value);
  164. }
  165. });
  166. }else{
  167. ele.forEach(e-> em.put(e.getCode(),e.getRawValue()));
  168. }
  169. }
  170. public static final Random RD = new Random();
  171. public static Map<String,Object> triangleSquare(Object ranges){
  172. Map<String,Object> map =new HashMap<>();
  173. if(StringUtils.isEmpty(ranges)){
  174. //z的默认取值范围
  175. ranges="(0,15)";
  176. }
  177. Matcher m = RegexUtils.matcher("(\\-?\\d+)(\\D)(\\+?\\d+)",ranges.toString());
  178. if(m.find()) {
  179. int min = StringUtils.handObj2Integer(m.group(1));
  180. int max = StringUtils.handObj2Integer(m.group(3));
  181. Integer[] r = pythagorean(min, max);
  182. map.put("X", String.valueOf(r[0]));
  183. map.put("Y", String.valueOf(r[1]));
  184. map.put("Z", String.valueOf(r[2]));
  185. }
  186. return map;
  187. }
  188. /* public static void main(String[] args) {
  189. IntStream.range(0,10).boxed().forEach(i->{
  190. System.out.println(triangleSquare("-5,5"));
  191. });
  192. }*/
  193. /**
  194. * @Description 字符串相似度
  195. * @Param [s1, s2]
  196. * @return double
  197. * @Author yangyj
  198. * @Date 2023.04.12 18:01
  199. **/
  200. public static double getJaccardSimilarity(String s1, String s2) {
  201. Set<Character> set1 = new HashSet<>();
  202. Set<Character> set2 = new HashSet<>();
  203. for (char c : s1.toCharArray()) {
  204. set1.add(c);
  205. }
  206. for (char c : s2.toCharArray()) {
  207. set2.add(c);
  208. }
  209. Set<Character> intersection = new HashSet<>(set1);
  210. intersection.retainAll(set2);
  211. Set<Character> union = new HashSet<>(set1);
  212. union.addAll(set2);
  213. return (double) intersection.size() / union.size();
  214. }
  215. public static Double similarity(String s1,String s2){
  216. return getJaccardSimilarity(parseItemName(s1),parseItemName(s2));
  217. }
  218. /* public static void main(String[] args) {
  219. similarity("分项工程名称:","分项工程名称:");
  220. }*/
  221. /**
  222. * result[0]^2+result[1]^2=result[2]^2 result[] 元素均为正整数
  223. */
  224. public static Integer[] pythagorean(Integer min,Integer max){
  225. Integer[] result = null;
  226. List<Integer[]> list = new ArrayList<>();
  227. for(int i=1;i<=max;i++){
  228. for(int j=1;j<=max;j++){
  229. double tmp = Math.sqrt(Math.pow(i,2)+Math.pow(j,2));
  230. int z= (int) Math.round(tmp);
  231. if(min<z&&z<=max){
  232. Integer[] arr = new Integer[]{RD.nextBoolean()?i:-i,RD.nextBoolean()?j:-j,z};
  233. list.add(arr);
  234. }
  235. }
  236. }
  237. if(ListUtils.isNotEmpty(list)){
  238. Random rm = new Random();
  239. result = list.get(rm.nextInt(list.size()));
  240. }
  241. return result;
  242. }
  243. /*public static void main(String[] args) {
  244. FormData fd = new FormData();
  245. fd.setEName("1111");
  246. List<ElementData> list = new ArrayList<>();
  247. list.add(new ElementData(1,1,1));
  248. test(fd);
  249. System.out.println(fd.getEName());
  250. }*/
  251. /**写人元素数据,每个元素都是一个集合,每页的单元格数量乘以页数就是总长度*/
  252. public static void write(FormData fd, Object data){
  253. write(fd,data,false);
  254. }
  255. public static void write(FormData fd, Object data,Boolean retainEmpty){
  256. if(Func.isEmpty(fd.getValues())){
  257. /*无定位信息不写入*/
  258. return;
  259. }
  260. try {
  261. /*一个单元格且存在多张,全部设置为自动拓展 20230816*/
  262. if(fd.getCoordsList().size()==1&&fd.getValues().size()>1&&fd.getFormula()!=null){
  263. fd.getFormula().setOutm(Formula.FULL);
  264. }
  265. /*写入前清空内容*/
  266. fd.getValues().forEach(t->t.setValue(null));
  267. if(data instanceof List){
  268. List<Object> values = (List<Object>) data;
  269. //中间元素根据数据动态扩容
  270. ElementData elementData = fd.getValues().get(0);
  271. //中间元素初始坐标
  272. if(elementData.getX() == 0 && elementData.getY() == 0){
  273. for (int i = 1; i < values.size(); i++) {
  274. ElementData elementData1 = new ElementData();
  275. elementData1.setIndex(0);
  276. elementData1.setX(-i);
  277. elementData1.setY(0);
  278. elementData1.setGroupId(0);
  279. fd.getValues().add(elementData1);
  280. }
  281. }
  282. if(!retainEmpty){
  283. /*不包含空白内容*/
  284. values=values.stream().filter(StringUtils::isNotEmpty).collect(Collectors.toList());
  285. }
  286. if(values.size()>fd.getValues().size()){
  287. if(fd.getCoordsList().size()==1){
  288. /*元素只绑定了一个单元格的情况*/
  289. if(values.stream().filter(CustomFunction::containsZH).anyMatch(e->e.toString().contains("\n"))){
  290. fd.getValues().get(0).setValue(values.stream().filter(Objects::nonNull).map(Object::toString).collect(Collectors.joining()));
  291. }else{
  292. /*日期类型的元素只获取最后一个非空*/
  293. if(StringUtils.isEquals(4,fd.getEType())){
  294. fd.getValues().get(0).setValue(values.stream().filter(StringUtils::isNotEmpty).reduce((first, second) -> second).orElse(null));
  295. }else if(values.stream().filter(StringUtils::isNotEmpty).distinct().count()==1L&&!fd.getEName().contains("实测")){
  296. /*如果输入元素全是是一样的内容,则输入出元素则每个单元格也写入一样的内容*/
  297. values.stream().filter(StringUtils::isNotEmpty).findFirst().ifPresent(t->{
  298. for(int n=0;n<fd.getValues().size();n++){
  299. fd.getValues().get(n).setValue(t);
  300. }
  301. });
  302. }else{
  303. fd.getValues().get(0).setValue(values.stream().filter(StringUtils::isNotEmpty).map(StringUtils::handleNull).collect(Collectors.joining("、")));
  304. }
  305. }
  306. }else{
  307. for(int n=0;n<fd.getValues().size();n++){
  308. fd.getValues().get(n).setValue(values.get(n));
  309. }
  310. List<Object> overList=values.stream().skip(fd.getValues().size()).collect(Collectors.toList());
  311. List<Coords> coordsList = fd.getCoordsList();
  312. int addPage=(int)Math.ceil((double)overList.size()/(double)coordsList.size());
  313. fd.setAddPages(addPage);
  314. ElementData last =fd.getValues().get(fd.getValues().size()-1);
  315. int indexBase=last.getIndex()+1;
  316. List<ElementData> addList= new ArrayList<>();
  317. for(int i=0;i<addPage;i++){
  318. for(int j=0;j<coordsList.size();j++){
  319. /*超页就尽管写进去,格式化阶段再加表*/
  320. Coords coords = coordsList.get(j);
  321. Object v=null;
  322. int st=i*coordsList.size()+j;
  323. if(st<overList.size()){
  324. v= overList.get(st);
  325. }
  326. addList.add(new ElementData(indexBase+i,last.getGroupId(),v,coords.getX(),coords.getY()));
  327. }
  328. }
  329. fd.getValues().addAll(addList);
  330. }
  331. }else{
  332. for (int n = 0; n < values.size(); n++) {
  333. fd.getValues().get(n).setValue(values.get(n));
  334. }
  335. }
  336. }else{
  337. if(fd.getFormula()!=null&&Formula.FULL.equals(fd.getFormula().getOutm())){
  338. /*填充策略*/
  339. fd.getValues().forEach(e->e.setValue(data));
  340. }else{
  341. fd.getValues().get(0).setValue(data);
  342. }
  343. }
  344. fd.setUpdate(1);
  345. }catch (Exception e){
  346. e.printStackTrace();
  347. }
  348. }
  349. public static final String TBN_FN="TBN";
  350. /*把模型类转换成共识配置选项*/
  351. public static List<WbsFormElementVO> toElementVos(Class<?> clazz) {
  352. return DataModel.toElementVos(clazz);
  353. }
  354. public static String getEleKey(Class<?> clazz, String fieldName){
  355. try {
  356. Field field = clazz.getDeclaredField(fieldName);
  357. String TBN = (String) clazz.getField(TBN_FN).get(null);
  358. JSONField jf = AnnotationUtils.findAnnotation(field, JSONField.class);
  359. if (jf != null) {
  360. return TBN+StringPool.COLON+jf.name();
  361. }
  362. } catch (Exception e) {
  363. e.printStackTrace();
  364. }
  365. return StringPool.EMPTY;
  366. }
  367. public static JSONField getJSONField(Class<?> clazz, String fieldName){
  368. try {
  369. Field field = clazz.getDeclaredField(fieldName);
  370. String TBN = (String) clazz.getField(TBN_FN).get(null);
  371. JSONField jf = AnnotationUtils.findAnnotation(field, JSONField.class);
  372. if (jf != null) {
  373. return jf;
  374. }
  375. } catch (Exception e) {
  376. e.printStackTrace();
  377. }
  378. return null;
  379. }
  380. /*获取指定模型的页码元素*/
  381. public static String getPageCode(Class<?> clazz){
  382. return getEleKey(clazz,"pageCount");
  383. }
  384. public static String getPageTotal(Class<?> clazz){
  385. return getEleKey(clazz,"pageTotal");
  386. }
  387. public static String getPageIndex(Class<?> clazz){
  388. return getEleKey(clazz,"pageIndex");
  389. }
  390. public static JSONField getPageFormat(Class<?> clazz){
  391. return getJSONField(clazz,"pageCount");
  392. }
  393. /*根据数据模型实例生成带数据的元素,用于修改*/
  394. public static <T> LinkedHashMap<String,FormData> toFormDataMap(T bean){
  395. LinkedHashMap<String,FormData> result = new LinkedHashMap<>();
  396. if(bean!=null){
  397. try {
  398. @SuppressWarnings("unchecked")
  399. Map<String,String> map= JSON.parseObject(JSON.toJSONString(bean),Map.class);
  400. Class<?> clazz=bean.getClass();
  401. String TBN = (String) clazz.getField(TBN_FN).get(null);
  402. for (Field field : clazz.getDeclaredFields()) {
  403. JSONField jf = field.getAnnotation(JSONField.class);
  404. if (jf != null) {
  405. FormData fd = new FormData();
  406. fd.setCode(TBN+ StringPool.COLON +jf.name());
  407. fd.setEName(jf.label());
  408. fd.getValues().add(new ElementData(0,0,map.get(fd.getKey()),0,0));
  409. fd.getCoordsList().add(new Coords("0","0"));
  410. result.put(fd.getCode(),fd);
  411. }
  412. }
  413. }catch (Exception e){
  414. e.printStackTrace();
  415. }
  416. }
  417. return result;
  418. }
  419. /*根据数据模型建立空元素,待写入数据*/
  420. public static <T> LinkedHashMap<String,FormData> toFormDataMap(Class<T> clazz){
  421. LinkedHashMap<String,FormData> result = new LinkedHashMap<>();
  422. try {
  423. String TBN = (String) clazz.getField(TBN_FN).get(null);
  424. for (Field field : clazz.getDeclaredFields()) {
  425. JSONField jf = field.getAnnotation(JSONField.class);
  426. if (jf != null) {
  427. FormData fd = new FormData();
  428. fd.setCode(TBN+ StringPool.COLON +jf.name());
  429. fd.setEName(jf.label());
  430. fd.getCoordsList().add(new Coords("0","0"));
  431. result.put(fd.getCode(),fd);
  432. }
  433. }
  434. }catch (Exception e){
  435. e.printStackTrace();
  436. }
  437. return result;
  438. }
  439. /*把结果数据回写到元素*/
  440. public static<T>void put2FormData( LinkedHashMap<String,FormData> fdm,Map<String,Function<List<T>,List<Object>>> functionMap,List<T> dataList){
  441. fdm.values().stream()
  442. .filter(fd -> functionMap.containsKey(fd.getCode()))
  443. .forEach(fd -> {
  444. List<Object> raw = functionMap.get(fd.getCode()).apply(dataList);
  445. raw.stream().map(ElementData::new).forEach(fd.getValues()::add);
  446. });
  447. }
  448. /*根据数据模型对象,生成数据集合按字段获取数据的函数*/
  449. public static <T> Map<String, Function<List<T>, List<Object>>> fieldDataFcMap(Class<?> clazz) {
  450. Map<String, Function<T, Object>> fieldMap = functionMapBuilder(clazz);
  451. Map<String, Function<List<T>, List<Object>>> functionMap = new HashMap<>();
  452. for (Map.Entry<String, Function<T, Object>> functionEntry : fieldMap.entrySet()) {
  453. Function<List<T>, List<Object>> mapper = list -> list.stream().map(functionEntry.getValue()).collect(Collectors.toList());
  454. functionMap.put(functionEntry.getKey(), mapper);
  455. }
  456. return functionMap;
  457. }
  458. /*数据模型按字段生成内容获取函数*/
  459. public static <T> Map<String,Function<T,Object>> functionMapBuilder(Class<?> clazz){
  460. Map<String, Function<T, Object>> functionMap = new HashMap<>();
  461. try {
  462. String tbn=clazz.getField(TBN_FN).get(null).toString();
  463. for (Field field : clazz.getDeclaredFields()) {
  464. JSONField jf = field.getAnnotation(JSONField.class);
  465. if(jf!=null) {
  466. /*ordinal<=100的情况下才会生成动态行字段输出函数*/
  467. if(jf.ordinal()<=100) {
  468. String key = tbn + StringPool.COLON + jf.name();
  469. String fieldName = field.getName();
  470. Function<T, Object> function = getFunction(clazz, fieldName);
  471. functionMap.put(key, function);
  472. }
  473. }
  474. }
  475. }catch (Exception e){
  476. e.printStackTrace();
  477. }
  478. return functionMap;
  479. }
  480. private static <T> Function<T, Object> getFunction(Class<?> clazz, String fieldName) {
  481. return certificate -> {
  482. try {
  483. Field field = clazz.getDeclaredField(fieldName);
  484. field.setAccessible(true);
  485. return field.get(certificate);
  486. } catch (Exception e) {
  487. e.printStackTrace();
  488. return null;
  489. }
  490. };
  491. }
  492. /*list转TreeNode*/
  493. public static <K,T> Map<K, TreeNode<T>> list2TreeNode(Function<TreeNode<T>,K> keyMapper,List<T> list,Function<T,TreeNode<T>> fc,Function<TreeNode<T>,K> classifier){
  494. Map<K, TreeNode<T>> mTreeMap = new HashMap<>();
  495. if (Func.isNotEmpty(list)) {
  496. for (T mt : list) {
  497. try {
  498. TreeNode<T> treeNode = fc.apply(mt);
  499. mTreeMap.put(keyMapper.apply(treeNode), treeNode);
  500. }catch (Exception e){
  501. e.printStackTrace();
  502. }
  503. }
  504. Map<K, List<TreeNode<T>>> group = mTreeMap.values().stream().collect(Collectors.groupingBy(classifier));
  505. group.forEach((k, v) -> {
  506. TreeNode<T> parent = mTreeMap.get(k);
  507. if (parent != null) {
  508. v = v.stream().sorted(Comparator.comparingInt(TreeNode::getSort)).collect(Collectors.toList());
  509. parent.setChildren(v);
  510. v.forEach(e -> e.setParent(parent));
  511. }
  512. });
  513. }
  514. return mTreeMap;
  515. }
  516. /*TreeNode 排序*/
  517. public static <T> void treeNodeSort(int base,TreeNode<T> top){
  518. top.setSort(base);
  519. if(top.hasChildren()){
  520. for(TreeNode<T> child:top.getChildren()){
  521. child.setSort(base++);
  522. }
  523. }
  524. }
  525. /*回溯标记*/
  526. public static <T> void treeNodeChecked( TreeNode<T> tmp){
  527. int loop = 10;
  528. do{
  529. if(tmp.isChecked()) {
  530. /*已经检出则停止循环*/
  531. loop=0;
  532. }else{
  533. tmp.setChecked(true);
  534. tmp=tmp.getParent();
  535. }
  536. }while (tmp!=null&&loop-->0);
  537. }
  538. /*获取层级链*/
  539. public static <T> List<T> treeNodeChains( TreeNode<T> tmp){
  540. List<T> result = new ArrayList<>();
  541. int loop = 10;
  542. do{
  543. /*不包括顶层*/
  544. if(tmp.getParentId()!=0L) {
  545. result.add(tmp.getValue());
  546. }
  547. tmp=tmp.getParent();
  548. }while (tmp!=null&&loop-->0);
  549. Collections.reverse(result);
  550. return result;
  551. }
  552. /**从元素名称中解析项目名称,细化项目匹配用*/
  553. public static String parseItemName(String eName){
  554. if (StringUtils.isEmpty(eName)) {
  555. return eName;
  556. }
  557. String str = eName.replaceAll("\\s", "");
  558. Pattern pattern = compile("[((][^\\u4e00-\\u9fa5]+[))]|_+");
  559. String[] candidate = pattern.split(str);
  560. /*非中文非罗马数字1到10*/
  561. String regex = "[^\\u4e00-\\u9fa5\\u2160-\\u2169))((]+";
  562. Pattern p = compile(regex);
  563. return Arrays.stream(candidate)
  564. .filter(s -> !isContainKeywords(s))
  565. .map(s -> filterString(s, p))
  566. .collect(Collectors.joining());
  567. }
  568. /*A15检查内容专用*/
  569. public static String checkItemName(String eName){
  570. if (StringUtils.isEmpty(eName)) {
  571. return eName;
  572. }
  573. /*分割字符串,选取第一个匹配的子串*/
  574. String str = eName.replaceAll("\\s", "");
  575. Pattern pattern = compile("[((][^\\u4e00-\\u9fa5]+[))]|_+");
  576. String[] candidate = pattern.split(str);
  577. String regex = "[^\\u4e00-\\u9fa5]+";
  578. return Arrays.stream(candidate).map(s->s.replaceAll(regex,"")).distinct().filter(StringUtils::isNotEmpty).filter(s->!isContainKeywords2(s)).findFirst().orElse("");
  579. }
  580. private static String filterString(String s, Pattern p) {
  581. s=s.replaceAll("【[^【】]+】","");
  582. Matcher matcher = p.matcher(s);
  583. return matcher.replaceAll("").replaceAll(getRegex(), "").replaceAll("(设计|合格).*","");
  584. }
  585. private static String getRegex() {
  586. return "(在合格标准内|满足设计要求|质量评定|评定|判定|项目|总数|抽测|实测|偏差|尺量|关键|一般)";
  587. }
  588. private static boolean isContainKeywords(String s) {
  589. List<String> keywords = Arrays.asList( ":", "个","附录","抽查","测","求","小于","大于","检查","仪","按","不","各","记录","检验","且","规定","值或实","≤","≥","平均");
  590. return keywords.stream().anyMatch(s::contains);
  591. }
  592. private static boolean isContainKeywords2(String s) {
  593. List<String> keywords = Arrays.asList( "项目","检查","附录","记录","检验结果","结果");
  594. return keywords.stream().anyMatch(s::contains);
  595. }
  596. /**回归·测试变量*/
  597. public static List<String> itemNames =Arrays.asList(
  598. ""
  599. ,"压 实 度 (%)下路床 特重、极重交通荷载等级 设计值"
  600. ,"1△_压 实 度 (%)_下路床_轻、中及重交通 荷载等级_0.3m~0.8m_≧96_≧95_≧94_实测值或实测偏差值"
  601. ,"1△_压 实 度 (%)_下路提_轻、中及重交通 荷载等级_&gt;1.5m_≧93_≧92_≧90_实测值或实测偏差值"
  602. ,"1△_压 实 度 (%)_上路提_轻、中及重交通 荷载等级_0.8m~1.5m_≧94_≧94_≧93_实测值或实测偏差值"
  603. ,"压 实 度 (%)下路提 轻、中及重交通荷载等级 设计值"
  604. ,"压 实 度 (%)下路床 特重、极重交通荷载等级 合格率"
  605. ,"压 实 度 (%)下路提 轻、中及重交通荷载等级\t合格率"
  606. ,"5△_保护层 厚度 (mm)_基础、锚碇、墩台身、墩柱_±10_实测值或实测偏差值"
  607. ,"钢筋骨架尺寸宽、高或直径 (mm)_尺量:按骨架总数30%抽测_±5_实测值或实测偏差值"
  608. ,"钢筋骨架尺寸长 (mm)_±10_尺量:按骨架总数30%抽测_实测值或实测偏差值"
  609. , "受力钢筋间距 (mm)同排 梁、板、拱肋及拱上建筑 设计值"
  610. ,"受力钢筋间距 (mm)同排 梁、板、拱肋及拱上建筑 合格率"
  611. ," 箍筋、构造钢筋、螺旋筋间距(mm) 设计值"
  612. ,"箍筋、构造钢筋、螺旋筋间距(mm) 合格率"
  613. ,"实测项目_桩位 (mm)_群桩_≤100_质量评定_合格判定"
  614. ,"实测项目_桩位 (mm)_群桩_≤100_实测值或实测偏差值"
  615. ,"实测项目_桩位 (mm)_排架桩_实测值或实测偏差值"
  616. ,"实测项目_桩位 (mm)_排架桩_质量评定_合格判定"
  617. ,"实测项目_桩位 (mm)_群桩_≤100_质量评定_合格率(%)"
  618. ,"实测项目_桩位 (mm)_排架桩_质量评定_合格率(%)"
  619. ,"3△_支座高程(mm)_满足设计要求;设 计未要求时±5_水准仪:测每支座中心线_实测值或实测偏差值"
  620. ,"基底承载力(KPa)_不小于设计_直观或动力触探试验_实测值或实测偏差值"
  621. ,"实 测 项 目_花卉数量_满足设计要求_实测值或实测偏差值"
  622. ,"实 测 项 目_2△_草坪、草本地被覆盖率(%)_取弃土场绿 地_≥90_实测值或实测偏差值"
  623. ,"轴线偏位(mm)_全站仪:20m检查3点_实测值或实测偏差值"
  624. ,"1△_基材混合物喷射厚度(mm)_设计厚度±10_实测值或实测偏差值"
  625. ,"1△_混凝土强度 (MPA)_在合格标准内_按附录D检查_实测值或实测偏差值"
  626. ,"边坡坡度_不陡于设计值_水准仪:每200m测2点,且不少于5点_实测值或实测偏差值"
  627. ,"几何尺寸(mm)_±50_尺量:长、宽、高、壁厚各2点_实测值或实测偏差值"
  628. ,"4△_桩长(mm)_不小于设计_查施工记录_实测值或偏差值"
  629. ,"单桩每延米喷粉 (浆)量_不小于设计_查施工记录_实测值或偏差值"
  630. ,"搭接宽度(mm)_≥150【纵向】_尺量:抽查2%_实测值或实测偏差值",
  631. "搭接宽度(mm)_≥50(横向)_尺量:抽查2%_实测值或实测偏差值"
  632. ,"竖直度(mm)_挖孔桩_0.5%桩长,且≤200_铅锤线:每桩检测_实测值或实测偏差值"
  633. , "2△_压浆压力值 (Mpa)_满足施工技术 规范规定_查油压表读书;每管道检查_实测值或实测偏差值"
  634. , "基底承载力(KPa)_不小于设计_实测值或实测偏差值"
  635. ,"1△_受力钢筋间距 (mm)_两排以上间距_±5_实测值或实测偏差值"
  636. ,"1△梁(板)长度 (mm)_±5_实测值或实测偏差值"
  637. ,"墙面平整度(mm)_施工缝、变形缝处≤20_实测值或实测偏差值"
  638. ,"基底承载力(KPa)_不小于设计_实测值或实测偏差值"
  639. ,"1△_拱部超挖(mm)_Ⅱ、Ⅲ、Ⅳ级围岩(中硬岩 、软岩)_平均150,最大250_实测值或实测偏差值"
  640. ,"实 测 项 目_关键项目_压实度(%)_上路堤_轻、中及重交通荷载等级_0.8~1.5m_≥94_≥94_≥93_检查情况 (实测值)"
  641. ,"表面平整度(mm)_片石_≤35_检验结果"
  642. );
  643. /* public static void main(String[] args) {
  644. // itemNames.stream().map(FormulaUtils::parseItemName).forEach(System.out::println);
  645. itemNames.stream().map(FormulaUtils::checkItemName).forEach(System.out::println);
  646. }*/
  647. public static Object getValue(Cell cell) {
  648. if (cell != null) {
  649. switch (cell.getCellTypeEnum()) {
  650. case STRING:
  651. return cell.getStringCellValue() == null ? null : cell.getStringCellValue().trim();
  652. case NUMERIC:
  653. HSSFDataFormatter dataFormatter = new HSSFDataFormatter();
  654. return dataFormatter.formatCellValue(cell);
  655. case BOOLEAN:
  656. return cell.getBooleanCellValue();
  657. case ERROR:
  658. return cell.getErrorCellValue();
  659. case FORMULA:
  660. try {
  661. return cell.getStringCellValue();
  662. } catch (IllegalStateException e) {
  663. return "";
  664. }
  665. default:
  666. cell.setCellType(CellType.STRING);
  667. return cell.getStringCellValue() == null ? null : cell.getStringCellValue().trim();
  668. }
  669. }
  670. return null;
  671. }
  672. public static List<ElementData> getElementDataList(String coords,String values){
  673. if(StringUtils.isNotEmpty(coords,values)){
  674. List<Coords> coordsList = Stream.of(coords).flatMap(s -> Arrays.stream(s.split(";"))).map(s -> {
  675. String[] xy = s.split("_");
  676. return new Coords(xy[1], xy[0]);
  677. }).collect(Collectors.toList());
  678. return str2ElementData(values,coordsList,null,null);
  679. }
  680. return Collections.emptyList();
  681. }
  682. public static List<ElementData> str2ElementData(String pg, List<Coords> coordsList ,String code,Integer index){
  683. List<ElementData> eds = new ArrayList<>();
  684. if(StringUtils.isNotEmpty(pg)&&ListUtils.isNotEmpty(coordsList)) {
  685. if(code==null){
  686. code="code";
  687. }
  688. if(index==null){
  689. index=1;
  690. }
  691. String[] val = pg.split("☆");
  692. Map<String, Object> tmpMap = new LinkedHashMap<>();
  693. for (String s : val) {
  694. String[] t = s.split("_\\^_");
  695. String[] c = t[1].split("_");
  696. tmpMap.put(StringUtils.join(code, 0, index, Func.toInt(c[1]), Func.toInt(c[0]), StringPool.AT), t[0]);
  697. }
  698. for (Coords c : coordsList) {
  699. Object data = null;
  700. String key = StringUtils.join(code, 0, index, c.getX(), c.getY(), StringPool.AT);
  701. if (tmpMap.containsKey(key)) {
  702. data = tmpMap.get(key);
  703. }
  704. eds.add(new ElementData(index, 0, data, c.getX(), c.getY()));
  705. }
  706. }
  707. return eds;
  708. }
  709. /**
  710. * @Description Poi 动态执行公式 测试
  711. * @Param [url]
  712. * @Author yangyj
  713. * @Date 2023.05.05 14:28
  714. **/
  715. public static void evaluateFormulaCell(String url) {
  716. try {
  717. url="C:/Users/yangyj/Desktop/test.xlsx";
  718. Workbook workbook = WorkbookFactory.create(new File(url));
  719. Sheet sheet = workbook.getSheetAt(0);
  720. Cell cell = sheet.getRow(0).getCell(0);
  721. FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
  722. CellType cellType = evaluator.evaluateFormulaCellEnum(cell);
  723. if (cellType == CellType.NUMERIC) {
  724. double value = cell.getNumericCellValue();
  725. System.out.println("公式计算结果:" + value);
  726. } else if (cellType == CellType.STRING) {
  727. String value = cell.getStringCellValue();
  728. System.out.println("公式计算结果:" + value);
  729. }
  730. cell.setCellFormula("B1+C1+D1");
  731. evaluator.clearAllCachedResultValues();
  732. cellType = evaluator.evaluateFormulaCellEnum(cell);
  733. if (cellType == CellType.NUMERIC) {
  734. double value = cell.getNumericCellValue();
  735. System.out.println("公式计算结果:" + value);
  736. } else if (cellType == CellType.STRING) {
  737. String value = cell.getStringCellValue();
  738. System.out.println("公式计算结果:" + value);
  739. }
  740. }catch (IOException | InvalidFormatException e){
  741. e.printStackTrace();
  742. }
  743. }
  744. public static Map<String, String> getElementCell(String uri){
  745. return getElementCell(uri,null,null);
  746. }
  747. public static Map<String, String> getElementCell(String uri,String key) {
  748. return getElementCell(uri,key,null);
  749. }
  750. public static Map<String, String> getElementCell(String uri,String key,Document document) {
  751. try {
  752. String filter=" [keyname]";
  753. if(Func.isNotBlank(key)){
  754. filter="[keyname^="+key+"__]";
  755. }
  756. if(document==null){
  757. InputStream inputStreamByUrl = FileUtils.getInputStreamByUrl(uri);
  758. document=Jsoup.parse(IoUtil.readToString(inputStreamByUrl));
  759. }
  760. Map<String,String> result= document
  761. .select("table").first()
  762. .select(filter).stream()
  763. .map(d -> d.attr("keyname")).filter(StringUtils::isNotEmpty).map(e -> e.split("__"))
  764. .collect(
  765. Collectors.toMap(
  766. b -> b[0],
  767. b -> b[1],
  768. (v1, v2) -> v1 + ";" + v2
  769. )
  770. );
  771. if(result.size()>0){
  772. for(Map.Entry<String,String> entry:result.entrySet()){
  773. entry.setValue(FormulaUtils.coordsSorted(entry.getValue()));
  774. }
  775. }
  776. return result;
  777. }catch (Exception e){
  778. e.printStackTrace();
  779. return new HashMap<>();
  780. }
  781. }
  782. public static Map<String, String> getElementExcelCoords(String uri){
  783. return getElementExcelCoords(uri,null,null);
  784. }
  785. public static Map<String, String> getElementExcelCoords(Document document){
  786. return getElementExcelCoords(null,null,document);
  787. }
  788. public static Map<String, String> getElementExcelCoords(String uri,String key,Document document){
  789. try {
  790. String filter=" [keyname]";
  791. if(Func.isNotBlank(key)){
  792. filter="[keyname^="+key+"__]";
  793. }
  794. if(document==null){
  795. InputStream inputStreamByUrl = FileUtils.getInputStreamByUrl(uri);
  796. document=Jsoup.parse(IoUtil.readToString(inputStreamByUrl));
  797. }
  798. Map<String,String> result= document
  799. .select("table").first()
  800. .select(filter).stream()
  801. .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")})
  802. .collect(
  803. Collectors.toMap(
  804. b -> b[0],
  805. b -> b[1],
  806. (v1, v2) -> v1 + ";" + v2
  807. )
  808. );
  809. if(result.size()>0){
  810. for(Map.Entry<String,String> entry:result.entrySet()){
  811. entry.setValue(FormulaUtils.coordsSorted(entry.getValue()));
  812. }
  813. }
  814. return result;
  815. }catch (Exception e){
  816. e.printStackTrace();
  817. return new HashMap<>();
  818. }
  819. }
  820. public static LinkedHashMap<String,String> analyzeHtml(String uri,String key,Document document){
  821. try {
  822. String filter=" [keyname]";
  823. if(Func.isNotBlank(key)){
  824. filter="[keyname^="+key+"__]";
  825. }
  826. if(document==null){
  827. InputStream inputStreamByUrl = FileUtils.getInputStreamByUrl(uri);
  828. document=Jsoup.parse(IoUtil.readToString(inputStreamByUrl));
  829. }
  830. LinkedHashMap<String,String> map= document.select("table").first()
  831. .select(filter).stream()
  832. .filter(d -> Func.isNotEmpty(d.attr("keyname"))&&d.attr("keyname").split("__")[0].length()>3)
  833. .sorted(Comparator.comparingInt(e->Integer.parseInt(e.attr("keyname").split("__")[0].split("_")[1])))
  834. .collect(Collectors.toMap(e->e.attr("placeholder"),e->e.attr("keyname"),(v1,v2)-> v1+","+v2,LinkedHashMap::new));
  835. return map;
  836. }catch (Exception e){
  837. e.printStackTrace();
  838. }
  839. return new LinkedHashMap<>();
  840. }
  841. /* public static void main(String[] args) {
  842. String uri="C:\\www\\wwwroot\\Users\\hongchuangyanfa\\Desktop\\privateUrl\\1661661730033369088.html";
  843. analyzeHtml(uri,"",null);
  844. }*/
  845. /*解析html里的电签关键字*/
  846. public static Map<String,String> getESignMap(Document document){
  847. Map<String,String> result = new HashMap<>();
  848. if(document!=null) {
  849. Elements list = document.getElementsByAttribute("dqid");
  850. if (list != null && !list.isEmpty()) {
  851. list.stream().forEach(e -> {
  852. String dqid = e.attr("dqid");
  853. int y1=0;
  854. int x1=0;
  855. if (!e.hasAttr("y1") && !e.hasAttr("x1")&&e.children().size()>0) {
  856. Element element = e.children().get(0);
  857. y1 = Func.toInt(element.attr("y1"));
  858. x1 = Func.toInt(element.attr("x1"));
  859. }else {
  860. y1 = Func.toInt(e.attr("y1"));
  861. x1 = Func.toInt(e.attr("x1"));
  862. }
  863. result.put(y1+"_"+x1,dqid);
  864. });
  865. }
  866. }
  867. return result;
  868. }
  869. /*保留小数缺失的情况会自动识别小数位*/
  870. public static List<ElementData> setScale(Integer scale, List<ElementData> data){
  871. if(scale==null){
  872. scale=StringUtils.getScale(data.stream().map(ElementData::getValue).filter(StringUtils::isDouble).collect(Collectors.toList()));
  873. }
  874. Integer finalScale = scale;
  875. return data.stream().peek(e->{if(StringUtils.isDouble(e.getValue())){e.setValue(StringUtils.number2StringZero(e.getValue(),finalScale));}}).collect(Collectors.toList());
  876. }
  877. /*不会自动识别小数位*/
  878. public static List<ElementData> setScaleMeter(Integer scale, List<ElementData> data){
  879. if(scale!=null){
  880. return data.stream().peek(e->{if(StringUtils.isDouble(e.getValue())){e.setValue(StringUtils.number2String(e.getValue(),scale));}}).collect(Collectors.toList());
  881. }
  882. return data;
  883. }
  884. /**
  885. * @Description 定位信息排序
  886. * @Param [coords]
  887. * @return java.lang.String
  888. * @Author yangyj
  889. * @Date 2023.07.11 15:39
  890. **/
  891. public static String coordsSorted(String coords){
  892. if(StringUtils.isNotEmpty(coords)){
  893. List<String> dataList=Arrays.asList(coords.split(";"));
  894. if(dataList.size()>2){
  895. LinkedList<Integer> list=dataList.stream().map(e->e.split("_")[1]).distinct().map(Integer::parseInt).sorted(Comparator.comparingInt(e->e)).collect(Collectors.toCollection(LinkedList::new));
  896. if(list.getLast()-list.getFirst()>list.size()-1){
  897. coords=dataList.stream()
  898. .sorted(Comparator.comparingInt((String str) -> Integer.parseInt(str.split("_")[1]))
  899. .thenComparingInt(str -> Integer.parseInt(str.split("_")[0])))
  900. .collect(Collectors.joining(";"));
  901. }
  902. }
  903. }
  904. return coords;
  905. }
  906. public static String coordsSorted2(String coords){
  907. if(StringUtils.isNotEmpty(coords)){
  908. List<String> dataList=Arrays.asList(coords.split(";"));
  909. if(dataList.size()>2){
  910. /*判断分区:根据行列长度*/
  911. List<Integer> row =dataList.stream().map(e->e.split("_")[0]).distinct().map(Integer::parseInt).collect(Collectors.toList());
  912. List<Integer> column=dataList.stream().map(e->e.split("_")[1]).distinct().map(Integer::parseInt).collect(Collectors.toList());
  913. if(row.size()>=column.size()){
  914. /*纵向*/
  915. if(column.size()>1){
  916. List<List<Integer>> consecutiveGroups = IntStream.range(0, column.size())
  917. .boxed()
  918. .collect(Collectors.collectingAndThen(
  919. Collectors.groupingBy(
  920. i -> i - column.get(i),
  921. LinkedHashMap::new,
  922. Collectors.mapping(column::get, Collectors.toList())
  923. ),
  924. map -> new ArrayList<>(map.values())
  925. ));
  926. }
  927. }
  928. /* 确定区内方向:*/
  929. }
  930. }
  931. return coords;
  932. }
  933. /* public static void main(String[] args) {
  934. List<Integer> column = Arrays.asList(1, 2, 3, 5, 6, 7, 9, 11, 17);
  935. List<List<Integer>> consecutiveGroups = IntStream.range(0, column.size())
  936. .boxed()
  937. .collect(Collectors.collectingAndThen(
  938. Collectors.groupingBy(
  939. i -> i - column.get(i),
  940. LinkedHashMap::new,
  941. Collectors.mapping(column::get, Collectors.toList())
  942. ),
  943. map -> new ArrayList<>(map.values())
  944. ));
  945. AtomicInteger i = new AtomicInteger(column.get(0));
  946. List<List<Integer>> consecutiveGroups2= new ArrayList<>(column.stream().collect(Collectors.groupingBy(e -> e - i.getAndSet(e) > 1, LinkedHashMap::new, Collectors.toList())).values());
  947. System.out.println();
  948. }*/
  949. public static List<Object> slice(List<LocalVariable> local, String formula){
  950. int min =0;
  951. List<Object> result = new ArrayList<>();
  952. try {
  953. pretreatment(local,formula);
  954. List<Object> r= local.stream().map(e-> {
  955. /*所有依赖元素的内容必须非空才进行计算,否则返回空值*/
  956. return e.hasEmptyElementValue()?"": Expression.parse(e.getFormula()).calculate(e.getCurrentMap()).toString();
  957. }).collect(Collectors.toList());
  958. if(CollectionUtil.isNotEmpty(r)&&r.stream().anyMatch(StringUtils::isNotEmpty)){
  959. result.addAll(r);
  960. }
  961. }catch (Exception e){
  962. e.printStackTrace();
  963. StaticLog.error("公式:{},执行出错",formula);
  964. }
  965. return result;
  966. }
  967. public static void pretreatment(List<LocalVariable> local,String formula){
  968. formula=StringUtils.removeMultiSpace(formula);
  969. if(formula.contains("LIST")){
  970. Matcher m=RegexUtils.matcher("\\(([^)]*)\\)/LIST",formula);
  971. while (m.find()){
  972. List<String> codes=getCodeList(m.group(1).replaceAll("[+-]",","));
  973. local=local.stream().peek(e->{
  974. @SuppressWarnings("unckecked")
  975. Map<String,Object> map = (Map<String, Object>) e.getCurrentMap().getOrDefault("E",new HashMap<>());
  976. int listSize=(int)codes.stream().filter(c->StringUtils.isNotEmpty(map.get(c))).count();
  977. if(listSize<=0||listSize>codes.size()){
  978. listSize=codes.size();
  979. }
  980. map.put("LIST",listSize);
  981. }).collect(Collectors.toList());
  982. }
  983. }
  984. }
  985. /**从方法参数中获取全部code*/
  986. public static List<String> getCodeList(String param){
  987. List<String> list = new ArrayList<>();
  988. if(StringUtils.isNotEmpty(param)){
  989. Arrays.stream(param.split(",")).forEach(s->{
  990. list.add(s.replaceAll("[E\\[\\]']",""));
  991. });
  992. }
  993. return list;
  994. }
  995. /**从时间段中获取最后一个日期*/
  996. static final String RANGE_DATE_REG="^\\[(\\d{4}[年.\\-]\\d{2}[月.\\-]\\d{2}[日]?),\\s+(\\d{4}[年.\\-]\\d{2}[月.\\-]\\d{2}[日]?)]$";
  997. public static String range2end(String t){
  998. if(t!=null&&Pattern.matches(RANGE_DATE_REG,t)){
  999. t=t.replaceAll("^\\[|]$","").split(",")[1].trim();
  1000. }
  1001. if(StringUtils.isNotEmpty(t)){
  1002. t=t.replace("\"", "");
  1003. }
  1004. return t;
  1005. }
  1006. public static List<String> duration2date(String duration){
  1007. try {
  1008. if (duration != null && Pattern.matches(RANGE_DATE_REG, duration)) {
  1009. return Arrays.stream(duration.replaceAll("^\\[|]$", "").split(",")).map(String::trim).map(s -> new DateTime(s).toString(DatePattern.NORM_DATE_PATTERN)).collect(Collectors.toList());
  1010. }
  1011. return Collections.singletonList(new DateTime(duration).toString(DatePattern.NORM_DATE_PATTERN));
  1012. }catch (Exception e){
  1013. return Collections.singletonList(new DateTime().toString(DatePattern.NORM_DATE_PATTERN));
  1014. }
  1015. }
  1016. public static FormData createFormDataFast(String name,String code,String values,String coords){
  1017. if(StringUtils.isNotEmpty(code,name)){
  1018. if(StringUtils.isNotEmpty(coords)) {
  1019. /*定位信息存在才合法*/
  1020. List<Coords> coordsList = Stream.of(coords).flatMap(s -> Arrays.stream(s.split(";"))).map(s -> {
  1021. String[] xy = s.split("_");
  1022. return new Coords(xy[1], xy[0]);
  1023. }).collect(Collectors.toList());
  1024. List<ElementData> eds = new ArrayList<>();
  1025. if (StringUtils.isNotEmpty(values)) {
  1026. String[] pages = values.split(";;");
  1027. for (int index = 0; index < pages.length; index++) {
  1028. String pg = pages[index];
  1029. if (Func.isNotBlank(pg)) {
  1030. String[] val = pg.split("☆");
  1031. Map<String, Object> tmpMap = new LinkedHashMap<>();
  1032. for (String s : val) {
  1033. String[] t = s.split("_\\^_");
  1034. String[] c = t[1].split("_");
  1035. tmpMap.put(StringUtils.join(code, 0, index, Func.toInt(c[1]), Func.toInt(c[0]), StringPool.AT), t[0]);
  1036. }
  1037. for (Coords c : coordsList) {
  1038. Object data = null;
  1039. String key = StringUtils.join(code, 0, index, c.getX(), c.getY(), StringPool.AT);
  1040. if (tmpMap.containsKey(key)) {
  1041. data = tmpMap.get(key);
  1042. }
  1043. eds.add(new ElementData(index, 0, data, c.getX(), c.getY()));
  1044. }
  1045. }
  1046. }
  1047. } else {
  1048. eds = coordsList.stream().map(c -> new ElementData(0, 0, null, c.getX(), c.getY())).collect(Collectors.toList());
  1049. }
  1050. FormData one = new FormData(code, eds, null, coords);
  1051. one.setEName(name);
  1052. /*备份原始数据,用于更新比较*/
  1053. one.init();
  1054. return one;
  1055. }
  1056. }
  1057. return null;
  1058. }
  1059. public static void mainT2(String[] args) throws IOException {
  1060. XYSeries series = new XYSeries("每月实际完成");
  1061. series.add(10.2, 1.82);
  1062. series.add(11.9, 1.86);
  1063. series.add(15.9, 1.87);
  1064. series.add(19.3, 1.85);
  1065. series.add(20.3, 1.80);
  1066. XYSeriesCollection dataset = new XYSeriesCollection();
  1067. dataset.addSeries(series);
  1068. JFreeChart chart = ChartFactory.createXYLineChart(
  1069. "按月进度", // 标题
  1070. "X", // 横轴标题
  1071. "Y", // 纵轴标题
  1072. dataset, // 数据集
  1073. PlotOrientation.VERTICAL, // 图表方向
  1074. true, // 是否显示图例
  1075. false, // 是否生成工具提示
  1076. false // 是否生成URL链接
  1077. );
  1078. // 设置字体
  1079. Font titleFont = new Font("SimSun", Font.PLAIN, 18); // 指定使用宋体字体
  1080. Font axisFont = new Font("SimSun", Font.PLAIN, 12); // 指定使用宋体字体
  1081. // 设置标题字体
  1082. TextTitle title = chart.getTitle();
  1083. title.setFont(titleFont);
  1084. XYPlot plot = (XYPlot) chart.getPlot();
  1085. XYSplineRenderer renderer = new XYSplineRenderer();
  1086. plot.setRenderer(renderer);
  1087. plot.setBackgroundPaint(Color.WHITE);
  1088. // Set the line stroke and shape for the renderer
  1089. renderer.setSeriesStroke(0, new BasicStroke(2.0f));
  1090. Shape circle = new Ellipse2D.Double(-3, -3, 6, 6);
  1091. renderer.setSeriesShape(0, circle);
  1092. renderer.setSeriesPaint(0, Color.BLUE);
  1093. // 自定义 X 轴刻度
  1094. NumberAxis domainAxis = (NumberAxis) plot.getDomainAxis();
  1095. domainAxis.setTickUnit(new NumberTickUnit(5)); // 设置刻度间隔
  1096. domainAxis.setRange(0.0, 25); // 设置轴的范围
  1097. // 自定义 Y 轴刻度
  1098. NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
  1099. rangeAxis.setTickUnit(new NumberTickUnit(0.01)); // 设置刻度间隔
  1100. rangeAxis.setRange(1.79, 1.90); // 设置轴的范围
  1101. // 添加横杠
  1102. for(int i=175;i<190;i++){
  1103. ValueMarker marker = new ValueMarker((double) i /100);
  1104. marker.setPaint(Color.BLUE); // 横杠的颜色
  1105. plot.addRangeMarker(marker);
  1106. }
  1107. ChartPanel chartPanel = new ChartPanel(chart);
  1108. chartPanel.setPreferredSize(new Dimension(500, 400));
  1109. // 保存图表为图片
  1110. int width = 800;
  1111. int height = 600;
  1112. ChartUtils.saveChartAsPNG(new File("C:/Users/yangyj/Desktop/Swap_space/poi_statistics.png"), chart, width, height);
  1113. }
  1114. private static CategoryDataset createDataset( double[] actualProgress, double[] plannedProgress) {
  1115. String[] months = {"一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"};
  1116. /* int[] actualProgress = {10, 15, 18, 27, 35, 48};
  1117. int[] plannedProgress = {10, 15, 20, 25, 30, 35};*/
  1118. DefaultCategoryDataset dataset = new DefaultCategoryDataset();
  1119. for (int i = 0; i < actualProgress.length; i++) {
  1120. dataset.addValue(actualProgress[i], "实际进度", months[i]);
  1121. }
  1122. for (int i = 0; i < plannedProgress.length; i++) {
  1123. dataset.addValue(plannedProgress[i], "计划进度", months[i]);
  1124. }
  1125. return dataset;
  1126. }
  1127. private static JFreeChart createChart(CategoryDataset dataset) {
  1128. JFreeChart chart = ChartFactory.createBarChart(
  1129. "施工进度对比图",
  1130. "月份",
  1131. "进度 (%)",
  1132. dataset,
  1133. PlotOrientation.VERTICAL,
  1134. true,
  1135. true,
  1136. false
  1137. );
  1138. CategoryPlot plot = (CategoryPlot) chart.getPlot();
  1139. // 设置中文字体以避免乱码
  1140. Font font = new Font("宋体", Font.PLAIN, 12);
  1141. chart.getTitle().setFont(font);
  1142. plot.getDomainAxis().setTickLabelFont(font);
  1143. plot.getDomainAxis().setLabelFont(font);
  1144. plot.getRangeAxis().setTickLabelFont(font);
  1145. plot.getRangeAxis().setLabelFont(font);
  1146. chart.getLegend().setItemFont(font);
  1147. plot.setDomainAxis(new CategoryAxis("月份"));
  1148. plot.setRangeAxis(new NumberAxis("进度 (%)"));
  1149. BarRenderer barRenderer = new BarRenderer();
  1150. barRenderer.setSeriesPaint(0, new Color(0, 0, 255));
  1151. barRenderer.setSeriesPaint(1, new Color(0, 255, 0));
  1152. plot.setRenderer(barRenderer);
  1153. // 添加第二个数据集,绘制为曲线
  1154. DefaultCategoryDataset lineDataset = new DefaultCategoryDataset();
  1155. String[] months = {"一月", "二月", "三月", "四月", "五月", "六月"};
  1156. int[] actualProgress = {10, 15, 18, 27, 35, 48};
  1157. int[] plannedProgress = {10, 15, 20, 25, 30, 35};
  1158. for (int i = 0; i < actualProgress.length; i++) {
  1159. lineDataset.addValue(actualProgress[i], "实际进度", months[i]);
  1160. }
  1161. for (int i = 0; i < plannedProgress.length; i++) {
  1162. lineDataset.addValue(plannedProgress[i], "计划进度", months[i]);
  1163. }
  1164. plot.setDataset(1, lineDataset);
  1165. plot.mapDatasetToRangeAxis(1, 0);
  1166. LineAndShapeRenderer lineRenderer = new LineAndShapeRenderer();
  1167. lineRenderer.setSeriesPaint(0, new Color(255, 0, 0));
  1168. lineRenderer.setSeriesPaint(1, new Color(255, 165, 0));
  1169. plot.setRenderer(1, lineRenderer);
  1170. // 设置 X 轴标签
  1171. CategoryAxis domainAxis = plot.getDomainAxis();
  1172. domainAxis.setCategoryLabelPositions(
  1173. org.jfree.chart.axis.CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 4.0)
  1174. );
  1175. // 设置 Y 轴范围
  1176. ValueAxis rangeAxis = plot.getRangeAxis();
  1177. rangeAxis.setRange(0, 100);
  1178. return chart;
  1179. }
  1180. public static String getSysLocalFileUrl() {
  1181. String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
  1182. if (org.springblade.common.utils.SystemUtils.isMacOs()) {
  1183. file_path = "/Users/hongchuangyanfa/Desktop/";
  1184. } else if (SystemUtils.isWindows()) {
  1185. file_path = "C://upload//";
  1186. }
  1187. return file_path;
  1188. }
  1189. public static byte[] chapterScheduleChart( double[] actualProgress ,double[] plannedProgress){
  1190. CategoryDataset dataset = createDataset(actualProgress,plannedProgress);
  1191. JFreeChart chart = createChart(dataset);
  1192. try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
  1193. ChartUtils.writeChartAsPNG(out, chart, 800, 600);
  1194. return out.toByteArray();
  1195. } catch (IOException e) {
  1196. e.printStackTrace();
  1197. }
  1198. return null;
  1199. }
  1200. public static String chapterScheduleChartUrl( LinkedHashMap<Integer,Double> actualMap, LinkedHashMap<Integer,Double> plannedMap,int startYear,int endYear){
  1201. try {
  1202. JFreeChart chart =chartTest(actualMap,plannedMap, startYear, endYear);
  1203. String path= getSysLocalFileUrl() + "/pdf//"+SnowFlakeUtil.getId()+".png";
  1204. ChartUtils.saveChartAsPNG(new File(path), chart, 1200, 900);
  1205. return path;
  1206. } catch (Exception e) {
  1207. e.printStackTrace();
  1208. }
  1209. return null;
  1210. }
  1211. public static JFreeChart chartTest2(double[] actualProgressData ,double[] plannedProgressData) throws IOException {
  1212. // 创建数据集
  1213. XYSeries actualProgress = new XYSeries("实际进度");
  1214. XYSeries plannedProgress = new XYSeries("计划进度");
  1215. // 填充数据集
  1216. for (int i = 0; i < actualProgressData.length; i++) {
  1217. actualProgress.add(i, actualProgressData[i]);
  1218. plannedProgress.add(i, plannedProgressData[i]);
  1219. }
  1220. XYSeriesCollection dataset = new XYSeriesCollection();
  1221. dataset.addSeries(actualProgress);
  1222. dataset.addSeries(plannedProgress);
  1223. // 创建图表
  1224. JFreeChart chart = ChartFactory.createXYLineChart(
  1225. "施工进度对比图", // 标题
  1226. "日期进度 (%)", // X轴标签
  1227. "完成量 (%)", // Y轴标签
  1228. dataset, // 数据集
  1229. org.jfree.chart.plot.PlotOrientation.VERTICAL, // 方向
  1230. true, // 显示图例
  1231. true, // 生成工具
  1232. false // 生成URL
  1233. );
  1234. // 设置中文字体以避免乱码
  1235. Font font = new Font("宋体", Font.PLAIN, 12);
  1236. chart.getTitle().setFont(font);
  1237. chart.getLegend().setItemFont(font);
  1238. XYPlot plot = chart.getXYPlot();
  1239. plot.setDomainGridlinesVisible(true);
  1240. plot.setRangeGridlinesVisible(true);
  1241. plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
  1242. plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
  1243. plot.setBackgroundPaint(Color.WHITE);
  1244. XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
  1245. renderer.setSeriesPaint(0, Color.BLUE);
  1246. renderer.setSeriesPaint(1, Color.GREEN);
  1247. plot.setRenderer(renderer);
  1248. // 设置顶部的月份轴
  1249. /* String[] months = {"一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"};
  1250. String[] years = {"2023年", "2024年", "2025年", "2026年"};*/
  1251. String[] months =new String[4 * 12];
  1252. for(int i=2023;i<=2026;i++){
  1253. for(int n=1;n<=12;n++){
  1254. int index=(i-2023)*12+n-1;
  1255. months[index]=i+"年"+n+"月";
  1256. }
  1257. }
  1258. // 设置顶部的月份轴
  1259. SymbolAxis monthAxis = new SymbolAxis("月份", months) ;
  1260. monthAxis.setTickLabelFont(font);
  1261. monthAxis.setLabelFont(font);
  1262. monthAxis.setVerticalTickLabels(true);
  1263. monthAxis.setRange(0, 47); // 设置范围来适应月份标签
  1264. plot.setDomainAxis(monthAxis);
  1265. // 设置Y轴的范围
  1266. NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
  1267. rangeAxis.setRange(0, 100); // Y轴从0到100
  1268. rangeAxis.setTickUnit(new NumberTickUnit(10));
  1269. rangeAxis.setLabelFont(font);
  1270. rangeAxis.setTickLabelFont(font);
  1271. /* // 添加月份轴
  1272. plot.setRangeAxis(2, monthAxis);
  1273. plot.mapDatasetToDomainAxis(0, 1); // 将数据映射到月份轴*/
  1274. return chart;
  1275. }
  1276. public static JFreeChart chartTest(LinkedHashMap<Integer,Double> actualMap, LinkedHashMap<Integer,Double> plannedMap,int startYear,int endYear) {
  1277. // 创建完整的数据集
  1278. XYSeriesCollection dataset = new XYSeriesCollection();
  1279. // 创建日期范围
  1280. long startDate=BaseUtils.getTimeMs(startYear,4);
  1281. long endDate = BaseUtils.getTimeMs(endYear,12);
  1282. // 初始化数据系列
  1283. XYSeries actualSeries = new XYSeries("实际进度");
  1284. XYSeries plannedSeries = new XYSeries("计划进度");
  1285. // 填充数据系列
  1286. actualMap.forEach((yearMonth,ratio)->{
  1287. actualSeries.add(BaseUtils.getTimeMs(yearMonth/100,yearMonth%100),ratio);
  1288. });
  1289. plannedMap.forEach((yearMonth,ratio)->{
  1290. plannedSeries.add(BaseUtils.getTimeMs(yearMonth/100,yearMonth%100),ratio);
  1291. });
  1292. dataset.addSeries(actualSeries);
  1293. dataset.addSeries(plannedSeries);
  1294. // 创建图表
  1295. JFreeChart chart = ChartFactory.createTimeSeriesChart(
  1296. "",
  1297. "",
  1298. "",
  1299. dataset,
  1300. true,
  1301. true,
  1302. false);
  1303. // 设置中文字体以避免乱码
  1304. Font font = new Font("宋体", Font.PLAIN, 12);
  1305. chart.getTitle().setFont(font);
  1306. chart.getLegend().setItemFont(font);
  1307. chart.getLegend().setVisible(false);
  1308. XYPlot plot = (XYPlot) chart.getPlot();
  1309. plot.setDomainGridlinesVisible(false);
  1310. plot.setRangeGridlinesVisible(false);
  1311. plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
  1312. plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
  1313. plot.setBackgroundPaint(Color.WHITE);
  1314. XYItemRenderer renderer = new XYSplineRenderer();
  1315. // 设置第一个系列为实线
  1316. renderer.setSeriesPaint(0, Color.GREEN); // 设置颜色
  1317. renderer.setSeriesStroke(0, new BasicStroke(2.0f)); // 设置实线
  1318. // 设置第二个系列为虚线
  1319. renderer.setSeriesPaint(1, Color.BLUE); // 设置颜色
  1320. renderer.setSeriesStroke(1, new BasicStroke(
  1321. 0.3f, // 线宽
  1322. BasicStroke.CAP_SQUARE, // 端点样式
  1323. BasicStroke.JOIN_BEVEL, // 连接点样式
  1324. 0.0f, // 斜接长度
  1325. new float[]{10.0f, 10f}, // 虚线模式:10像素线,6像素空白
  1326. 0.0f // 偏移量
  1327. ));
  1328. plot.setRenderer(renderer);
  1329. plot.setInsets(new RectangleInsets(0, 0, 0, 0));
  1330. // 设置 DateAxis
  1331. DateAxis monthAxis = (DateAxis) plot.getDomainAxis();
  1332. monthAxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
  1333. monthAxis.setDateFormatOverride(new SimpleDateFormat("yyyy年MM月"));
  1334. monthAxis.setTickLabelsVisible(true); // 禁用标签
  1335. monthAxis.setTickLabelFont(font);
  1336. monthAxis.setLabelFont(font);
  1337. monthAxis.setLowerBound(startDate);
  1338. monthAxis.setUpperBound(endDate);
  1339. // 确保每个月都有一个标签
  1340. monthAxis.setTickUnit(new DateTickUnit(DateTickUnitType.MONTH,1));
  1341. monthAxis.setVerticalTickLabels(true);
  1342. // 设置Y轴的范围
  1343. NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
  1344. rangeAxis.setRange(0, 100);
  1345. rangeAxis.setTickUnit(new NumberTickUnit(10));
  1346. rangeAxis.setLabelFont(font);
  1347. rangeAxis.setTickLabelFont(font);
  1348. rangeAxis.setVisible(false);
  1349. rangeAxis.setLabelInsets(new RectangleInsets(0, 0, 0, 0));
  1350. chart.setPadding(new RectangleInsets(0, 0, 0, 0));
  1351. return chart;
  1352. }
  1353. public static void mainT(String[] args) throws IOException {
  1354. LinkedHashMap<Integer,Double> actualProgress = new LinkedHashMap<>();
  1355. actualProgress.put(202311,5.0);
  1356. actualProgress.put(202312,10.2);
  1357. actualProgress.put(202401,14.99);
  1358. actualProgress.put(202402,19.7);
  1359. actualProgress.put(202403,23.6);
  1360. LinkedHashMap<Integer,Double> plannedProgress = new LinkedHashMap<>();
  1361. plannedProgress.put(202311,3.0);
  1362. plannedProgress.put(202312,6.0);
  1363. plannedProgress.put(202401,8.0);
  1364. plannedProgress.put(202402,9.0);
  1365. plannedProgress.put(202403,12.0);
  1366. JFreeChart chart = chartTest(actualProgress,plannedProgress,2023,2025);
  1367. /* try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
  1368. BufferedImage bufferedImage = chart.createBufferedImage(800, 600);
  1369. ImageIO.write(bufferedImage, "png", out);
  1370. FileOutputStream fos = new FileOutputStream("C:/Users/yangyj/Desktop/Swap_space/poi_statistics.png");
  1371. fos.write(out.toByteArray());
  1372. } catch (IOException e) {
  1373. e.printStackTrace();
  1374. }*/
  1375. try {
  1376. ChartUtils.saveChartAsPNG(new File("C:/Users/yangyj/Desktop/Swap_space/poi_statistics.png"), chart, 1200, 900);
  1377. // 保存图表到内存
  1378. } catch (Exception e) {
  1379. e.printStackTrace();
  1380. }
  1381. }
  1382. /**字符串sha256映射*/
  1383. public static String sha256(String input) {
  1384. try {
  1385. MessageDigest digest = MessageDigest.getInstance("SHA-256");
  1386. byte[] encodedHash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
  1387. StringBuilder hexString = new StringBuilder();
  1388. for (byte b : encodedHash) {
  1389. String hex = Integer.toHexString(0xff & b);
  1390. if (hex.length() == 1) {
  1391. hexString.append('0');
  1392. }
  1393. hexString.append(hex);
  1394. }
  1395. return hexString.toString();
  1396. } catch (NoSuchAlgorithmException e) {
  1397. e.printStackTrace();
  1398. }
  1399. return "";
  1400. }
  1401. /**根据步长获取字符*/
  1402. public static String getEveryNthChar(String input, int step) {
  1403. StringBuilder result = new StringBuilder();
  1404. for (int i = 0; i < input.length(); i += step) {
  1405. result.append(input.charAt(i));
  1406. }
  1407. return result.toString();
  1408. }
  1409. /**最大循环次数*/
  1410. public static int MAX_LOOP=20;
  1411. /**
  1412. * @Description 当前提交表单数据公式执行最小影响元素范围
  1413. * @Param [curTableNames:当前提交页面对应表编号, processFds:当前工序包含的所有元素]
  1414. * @Author yangyj
  1415. * @Date 2023.10.09 15:26
  1416. **/
  1417. public static List<FormData> registerFd(List<String> curTableNames, List<FormData> processFds){
  1418. Map<Boolean,List<FormData>> group = processFds.stream().collect(Collectors.partitioningBy(e->curTableNames.contains(e.getTableName())));
  1419. List<FormData> curFormDatas =group.get(true);
  1420. /*提交叶包含元素*/
  1421. List<FormData> initiator= new ArrayList<>(curFormDatas);
  1422. List<FormData> other=group.get(false);
  1423. /*当前提交页元素影响到的元素都要重新执行公式*/
  1424. pick(curFormDatas,other,curFormDatas,fds->fds.stream().map(FormData::getCode).collect(Collectors.toSet()));
  1425. /*当前提交页的元素公式依赖加载*/
  1426. pick(initiator,other,curFormDatas,fds->fds.stream().filter(f->f.executable()&&f.getFormula().getRely()!=null).flatMap(f->f.getFormula().getRelyList().stream()).collect(Collectors.toSet()));
  1427. return curFormDatas;
  1428. }
  1429. /**
  1430. * @Description 调训符合条件的元素
  1431. * @Param [initiator 初始集合, other 待选集合, curFormDatas 结果集, function:挑选方法]
  1432. * @Author yangyj
  1433. * @Date 2023.10.12 14:53
  1434. **/
  1435. public static void pick(List<FormData> initiator,List<FormData> other,List<FormData> curFormDatas ,Function<List<FormData>,Set<String>> function){
  1436. List<FormData> curFormDatasAdd=new ArrayList<>(initiator);
  1437. int loop=0;
  1438. do{
  1439. loop++;
  1440. Set<String> codeSet= function.apply(curFormDatasAdd);
  1441. Map<Boolean,List<FormData>> groupTmp = other.stream().collect(Collectors.partitioningBy(e->codeSet.contains(e.getCode())));
  1442. curFormDatasAdd=groupTmp.get(true);
  1443. if(curFormDatasAdd.isEmpty()){
  1444. loop=MAX_LOOP;
  1445. }else{
  1446. curFormDatas.addAll(curFormDatasAdd);
  1447. }
  1448. other=groupTmp.get(false);
  1449. }while (!other.isEmpty()&&loop<MAX_LOOP);
  1450. }
  1451. /**最小加载页面,只要包含当前提交元素的页面都需要加载*/
  1452. public static Map<String,List<Long>> relatedPages(List<FormData> curFormDatas ,List<NodeTable> tableAll){
  1453. Set<String> initTableNames= curFormDatas.stream().map(FormData::getTableName).collect(Collectors.toSet());
  1454. return tableAll.stream().filter(e->initTableNames.contains(e.getInitTableName())).collect(Collectors.groupingBy(NodeTable::getInitTableName,Collectors.mapping(NodeTable::getPKeyId,Collectors.toList())));
  1455. }
  1456. /*比较两组单元格内容是否一样*/
  1457. public static boolean compareElementDataList(List<ElementData> before ,List<ElementData> cur){
  1458. if(Func.isNotEmpty(before)&&Func.isNotEmpty(cur)&&before.size()==cur.size()){
  1459. String sa= before.stream().map(ElementData::stringValue).collect(Collectors.joining());
  1460. String sc= cur.stream().map(ElementData::stringValue).collect(Collectors.joining());
  1461. return sa.equals(sc);
  1462. }
  1463. return false;
  1464. }
  1465. /**分割treeCode*/
  1466. public static List<String> treeCodeSplit(String treeCode){
  1467. List<String> result = new ArrayList<>();
  1468. if(Func.isNotBlank(treeCode)){
  1469. /*字符总长度*/
  1470. int max =treeCode.length()-3,
  1471. /*累计字符长度字符*/
  1472. sum=0,
  1473. /*第几次循环*/
  1474. count=0;
  1475. do{
  1476. result.add(treeCode.substring(0, sum+=Math.min(3,++count)));
  1477. }while (sum<max&&count<MAX_LOOP);
  1478. }
  1479. return result;
  1480. }
  1481. /* public static void main(String[] args) {
  1482. System.out.println(milestone("k8+120.23"));
  1483. }*/
  1484. /*从测点名称中获取里程*/
  1485. public static Double milestone(String s){
  1486. Pattern pattern=Pattern.compile("(?i)K(\\d+)\\+([\\d.]+)");
  1487. Matcher matcher = pattern.matcher(s);
  1488. if(matcher.find()){
  1489. return Double.parseDouble(matcher.group(1))*1000+ Double.parseDouble(matcher.group(2));
  1490. }
  1491. return null;
  1492. }
  1493. public static void sort( List<FormData> list,int n){
  1494. /*System.out.println("剩余计算次数:"+n+"次");*/
  1495. if(move(list)&&n>0){
  1496. sort(list,--n);
  1497. }
  1498. }
  1499. public static Boolean move( List<FormData> list){
  1500. for(int i=0;i<list.size();i++){
  1501. FormData f=list.get(i);
  1502. Matcher m =P.matcher(f.getFormula().getFormula());
  1503. List<String> cp = new ArrayList<>();
  1504. while (m.find()){
  1505. cp.add(m.group());
  1506. }
  1507. Map<Boolean,List<FormData>> map= list.stream().skip(i+1).collect(Collectors.partitioningBy(e->cp.contains(e.getCode())));
  1508. List<FormData> match =map.get(true);
  1509. if(CollectionUtil.isNotEmpty(match)){
  1510. for(FormData r:match){
  1511. list.remove(r);
  1512. }
  1513. list.addAll(0,match);
  1514. return true;
  1515. }
  1516. }
  1517. return false;
  1518. }
  1519. public static void relyParse(Formula f){
  1520. if(Func.isNotBlank(f.getFormula())){
  1521. List<String> l = new ArrayList<>();
  1522. Matcher m = P.matcher(f.getFormula());
  1523. while (m.find()){
  1524. String tmp =m.group().replaceAll("'","");
  1525. String cp=tmp;
  1526. if(tmp.indexOf(StringPool.COLON)!=tmp.lastIndexOf(StringPool.COLON)){
  1527. tmp=tmp.substring(tmp.indexOf(":")+1);
  1528. /*移除跨节点标识*/
  1529. f.setFormula(f.getFormula().replace(cp,tmp));
  1530. }
  1531. l.add(tmp);
  1532. }
  1533. if(l.size()>0){
  1534. f.setRely(String.join(",", l));
  1535. }else{
  1536. f.setRely("");
  1537. }
  1538. }
  1539. }
  1540. /*复制表页*/
  1541. public static WbsTreeContract copyPage(WbsTreeContract origin){
  1542. WbsTreeContract target = new WbsTreeContract();
  1543. BeanUtil.copy(origin, target);
  1544. target.setPKeyId(SnowFlakeUtil.getId());
  1545. target.setCreateTime(new Date());
  1546. String nodeName = origin.getNodeName();
  1547. String[] oldName = nodeName.split("__");
  1548. if (oldName.length>1) {
  1549. nodeName = oldName[0] + "__" + (Integer.parseInt(oldName[1]) + 1);
  1550. } else {
  1551. nodeName = nodeName + "__" + 1;
  1552. }
  1553. target.setNodeName(nodeName);
  1554. target.setIsCopeTab(2);
  1555. target.setIsTabPdf(1); // pdf 不能预览
  1556. target.setIsBussShow(1); // 是否隐藏表
  1557. target.setTabFileType(1);//没有上传附件
  1558. target.setPdfUrl("");
  1559. return target;
  1560. }
  1561. public static String recovery(List<ElementData> dataList) {
  1562. if (Func.isNotEmpty(dataList)) {
  1563. String collect = dataList.stream().filter(e -> !e.isEmpty()).map(e -> e.stringValue() + "_^_" + e.getY() + "_" + e.getX()).collect(Collectors.joining("☆"));
  1564. return collect;
  1565. }
  1566. return "";
  1567. }
  1568. private static final Map<Character, Integer> CHINESE_TO_ARABIC = new HashMap<>();
  1569. static {
  1570. CHINESE_TO_ARABIC.put('零', 0);
  1571. CHINESE_TO_ARABIC.put('一', 1);
  1572. CHINESE_TO_ARABIC.put('二', 2);
  1573. CHINESE_TO_ARABIC.put('三', 3);
  1574. CHINESE_TO_ARABIC.put('四', 4);
  1575. CHINESE_TO_ARABIC.put('五', 5);
  1576. CHINESE_TO_ARABIC.put('六', 6);
  1577. CHINESE_TO_ARABIC.put('七', 7);
  1578. CHINESE_TO_ARABIC.put('八', 8);
  1579. CHINESE_TO_ARABIC.put('九', 9);
  1580. CHINESE_TO_ARABIC.put('十', 10);
  1581. CHINESE_TO_ARABIC.put('百', 100);
  1582. CHINESE_TO_ARABIC.put('千', 1000);
  1583. CHINESE_TO_ARABIC.put('万', 10000);
  1584. }
  1585. public static int chineseToArabic(String chineseNumber) {
  1586. int result = 0;
  1587. int multiplier = 1;
  1588. for (int i = chineseNumber.length() - 1; i >= 0; i--) {
  1589. char c = chineseNumber.charAt(i);
  1590. if (CHINESE_TO_ARABIC.containsKey(c)) {
  1591. int value = CHINESE_TO_ARABIC.get(c);
  1592. if(value!=0&&value%10==0&&i!=0){
  1593. multiplier=value;
  1594. }else{
  1595. result=result+value*multiplier;
  1596. }
  1597. } else {
  1598. throw new IllegalArgumentException("Invalid Chinese numeral: " + c);
  1599. }
  1600. }
  1601. return result;
  1602. }
  1603. /*public static void main(String[] args) {
  1604. *//* System.out.println(chineseToArabic("二十九"));
  1605. System.out.println(chineseToArabic("一"));
  1606. System.out.println(chineseToArabic("十一"));*//*
  1607. System.out.println(chineseToArabic("十"));
  1608. *//* System.out.println(chineseToArabic("一百二十"));
  1609. System.out.println(chineseToArabic("一百二十二"));
  1610. System.out.println(chineseToArabic("一百零二"));*//*
  1611. }*/
  1612. /*获取引用code的元素*/
  1613. public static Stream<FormData> beRelyFrom( Map<String, FormData> formDataMap ,String code){
  1614. return formDataMap.values().stream().filter(e->e.executable()&& code.equals(e.getFormula().getRely()));
  1615. }
  1616. public static Stream<FormData> beRelyFrom( Map<String, FormData> formDataMap ,String tableNumber ,String keys){
  1617. Set<String> keySet = Arrays.stream(keys.split(",")).map(s->tableNumber+":"+s.trim()).collect(Collectors.toSet());
  1618. return formDataMap.values().stream().filter(e->e.executable()&& keySet.contains(e.getFormula().getRely()));
  1619. }
  1620. /*根据code查找元素 */
  1621. public static Optional<FormData> elementFindByCode( Map<String, FormData> formDataMap ,String code){
  1622. return formDataMap.values().stream().filter(e->code.equals(e.getCode())).findAny();
  1623. }
  1624. /*根据key查找元素 ,用于元素范围在同一张表情况*/
  1625. public static Optional<FormData> elementFindByKey( Map<String, FormData> fdm ,String key){
  1626. return fdm.values().stream().filter(e->key.equals(e.getCode().split(":")[1])).findAny();
  1627. }
  1628. /*创建T集合的指定字段fb的合计方法*/
  1629. public static <T> Function<List<T>, String> createSumFunction(Function<T,BigDecimal> fb) {
  1630. return (pl) -> pl.stream()
  1631. .map(fb)
  1632. .reduce(BigDecimal.ZERO, BigDecimal::add)
  1633. .toPlainString();
  1634. }
  1635. public static Optional<Integer> getScale(String unit){
  1636. if(StringUtils.isNotEmpty(unit)) {
  1637. unit=unit.toLowerCase(Locale.ROOT);
  1638. if (unit.contains("吨")||unit.contains("t")){
  1639. return Optional.of(3);
  1640. }else if (unit.contains("米")||unit.contains("m")){
  1641. return Optional.of(2);
  1642. }else if (RegexUtil.find("个|项|台|套|棵|块|处|座|kg",unit)){
  1643. return Optional.of(0);
  1644. }
  1645. }
  1646. return Optional.empty();
  1647. }
  1648. public static List<TableInfo> getTableInfoList(JSONArray dataArray) {
  1649. if (dataArray != null && !dataArray.isEmpty()) {
  1650. List<TableInfo> result = new ArrayList<>();
  1651. for (int m = 0; m < dataArray.size(); m++) {
  1652. TableInfo tableInfo = new TableInfo();
  1653. com.alibaba.fastjson.JSONObject dataInfo2 = dataArray.getJSONObject(m);
  1654. //
  1655. tableInfo.setContractId(dataInfo2.getString("contractId"));
  1656. tableInfo.setPkeyId(dataInfo2.getString("pkeyId"));
  1657. tableInfo.setProjectId(dataInfo2.getString("projectId"));
  1658. //huangjn 填报的类型,施工或监理
  1659. tableInfo.setClassify(dataInfo2.getString("classify"));
  1660. //设置首件信息
  1661. setFirstData(dataInfo2, tableInfo);
  1662. //设置日志信息
  1663. setTheLogData(dataInfo2, tableInfo);
  1664. dataInfo2.fluentRemove("contractId")
  1665. .fluentRemove("pkeyId")
  1666. .fluentRemove("p_key_id")
  1667. .fluentRemove("projectId")
  1668. .fluentRemove("classify")
  1669. .fluentRemove("pickerKey")
  1670. .fluentRemove("id")
  1671. .fluentRemove("isFirst")
  1672. .fluentRemove("firstNodeId")
  1673. .fluentRemove("isTheLog")
  1674. .fluentRemove("theLogId")
  1675. .fluentRemove("linkTabIds")
  1676. .fluentRemove("recordTime")
  1677. .fluentRemove("businessId")
  1678. .fluentRemove("sourceUrl")
  1679. .fluentRemove("pdfUrl")
  1680. .fluentRemove("firstFileName")
  1681. .fluentRemove("");
  1682. // 计算数据
  1683. LinkedHashMap<String, List<String>> dataMap = dataInfo2.keySet().stream().filter(e -> e.contains("__")).collect(Collectors.groupingBy(e -> e.split("__")[0], LinkedHashMap<String, List<String>>::new, Collectors.toList()));
  1684. LinkedHashMap<String, String> dataMap2 = new LinkedHashMap<>();
  1685. // 字段组合
  1686. for (String k : dataMap.keySet()) {
  1687. if (dataMap.get(k).size() > 1 && !dataMap.get(k).contains("000Z")) {
  1688. String[] ziduan = dataMap.get(k).toArray(new String[]{});
  1689. String temp = "";
  1690. for (int i = 0; i < ziduan.length - 1; i++) {
  1691. for (int j = 0; j < ziduan.length - i - 1; j++) {
  1692. Integer tr = Integer.parseInt((ziduan[j].split("__")[1]).split("_")[0]);
  1693. Integer td = Integer.parseInt(ziduan[j].split("__")[1].split("_")[1]);
  1694. Integer tr_1 = Integer.parseInt(ziduan[j + 1].split("__")[1].split("_")[0]);
  1695. Integer td_1 = Integer.parseInt(ziduan[j + 1].split("__")[1].split("_")[1]);
  1696. if (tr > tr_1 && td.equals(td_1)) { //纵向排序
  1697. temp = ziduan[j];
  1698. ziduan[j] = ziduan[j + 1];
  1699. ziduan[j + 1] = temp;
  1700. }
  1701. }
  1702. }
  1703. String lastStr = dataInfo2.getString(ziduan[0]) + "_^_" + ziduan[0].split("__")[1];
  1704. for (int i = 1; i < ziduan.length; i++) {
  1705. String keyData = dataInfo2.getString(ziduan[i]);
  1706. if (org.apache.commons.lang.StringUtils.isNotEmpty(keyData) && !keyData.equals("")) {
  1707. lastStr += "☆" + dataInfo2.getString(ziduan[i]) + "_^_" + ziduan[i].split("__")[1];
  1708. }
  1709. }
  1710. dataMap2.put(k, lastStr);
  1711. } else {
  1712. String dataVal = dataInfo2.getString(dataMap.get(k).get(0));
  1713. if (org.apache.commons.lang.StringUtils.isNotEmpty(dataVal)) {
  1714. if (dataVal.contains("Ljava")) {
  1715. Object o = dataInfo2.get(dataMap.get(k).get(0));
  1716. dataVal = JSON.toJSONString(o).replace("\"", "");
  1717. }
  1718. dataMap2.put(k, dataVal + "_^_" + dataMap.get(k).get(0).split("__")[1]);
  1719. }
  1720. }
  1721. }
  1722. dataInfo2.put("p_key_id", tableInfo.getPkeyId());
  1723. dataInfo2.put("classify",tableInfo.getClassify());
  1724. dataInfo2.put("contractId",tableInfo.getContractId());
  1725. dataInfo2.put("projectId",tableInfo.getProjectId());
  1726. tableInfo.setDataMap(dataMap2);
  1727. result.add(tableInfo);
  1728. }
  1729. return result;
  1730. }
  1731. return null;
  1732. }
  1733. public static void setFirstData(com.alibaba.fastjson.JSONObject dataInfo2, TableInfo tableInfo) {
  1734. //huangjn 判断是否是首件
  1735. if (dataInfo2.containsKey("isFirst")) {
  1736. tableInfo.setIsFirst(dataInfo2.getString("isFirst"));
  1737. }
  1738. //huangjn 判断是否是首件
  1739. //首件资料绑定的节点
  1740. if (dataInfo2.containsKey("firstNodeId")) {
  1741. tableInfo.setFirstNodeId(dataInfo2.getString("firstNodeId"));
  1742. }
  1743. //首件ID(编辑时有值,新增时为空)
  1744. if (dataInfo2.containsKey("firstId")) {
  1745. tableInfo.setFirstId(dataInfo2.getString("firstId"));
  1746. }
  1747. //源文件
  1748. if (dataInfo2.containsKey("sourceUrl")) {
  1749. tableInfo.setSourceUrl(dataInfo2.getString("sourceUrl"));
  1750. }
  1751. //pdfUrl
  1752. if (dataInfo2.containsKey("pdfUrl")) {
  1753. tableInfo.setPdfUrl(dataInfo2.getString("pdfUrl"));
  1754. }
  1755. //文件名称
  1756. if (dataInfo2.containsKey("firstFileName")) {
  1757. tableInfo.setFirstFileName(dataInfo2.getString("firstFileName"));
  1758. }
  1759. //关联的信息
  1760. if (dataInfo2.containsKey("linkProcessList")) {
  1761. tableInfo.setLinkProcessList(dataInfo2.getJSONArray("linkProcessList"));
  1762. }
  1763. }
  1764. public static void setTheLogData(JSONObject dataInfo2, TableInfo tableInfo) {
  1765. //huangjn 判断是否是日志
  1766. if (dataInfo2.containsKey("isTheLog")) {
  1767. tableInfo.setIsTheLog(dataInfo2.getString("isTheLog"));
  1768. }
  1769. //huangjn 判断是否是日志
  1770. //huangjn 日志ID
  1771. if (dataInfo2.containsKey("theLogId")) {
  1772. tableInfo.setTheLogId(dataInfo2.getString("theLogId"));
  1773. }
  1774. //huangjn 日志ID
  1775. //huangjn 日志勾选的工序
  1776. if (dataInfo2.containsKey("linkTabIds")) {
  1777. tableInfo.setLinkTabIds(dataInfo2.getJSONArray("linkTabIds"));
  1778. }
  1779. //huangjn 日志勾选的工序
  1780. //huangjn 日志所选时间
  1781. if (dataInfo2.containsKey("recordTime")) {
  1782. tableInfo.setRecordTime(dataInfo2.getString("recordTime"));
  1783. }
  1784. //huangjn 日志所选时间
  1785. //huangjn 每份填报数据的id,目前日志专用
  1786. if (dataInfo2.containsKey("id")) {
  1787. tableInfo.setBusinessId(dataInfo2.getString("id"));
  1788. }
  1789. //huangjn 每份填报数据的id,目前日志专用
  1790. }
  1791. }