rpt_calculation_data_util.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973
  1. 'use strict';
  2. /**
  3. * Created by Tony on 2019/6/18.
  4. * 计量报表数据提取class,是协助报表模板里指标字段自主提取数据的工具类
  5. */
  6. const JV = require('../rpt_component/jpc_value_define');
  7. const $JE = require('../rpt_component/jpc_rte');
  8. const fs = require('fs');
  9. const fsUtil = require('../../public/js/fsUtil');
  10. const stringUtil = require('../../public/js/stringUtil');
  11. const scMathUtil = require('../../public/js/scMathUtil');
  12. const _ = require('lodash');
  13. const treeUtil = require('../public/treeUtil');
  14. const RELATION_TABLES_KEYS = {
  15. project: { main_key: 'id' },
  16. tender: { main_key: 'id', foreign_key: { project: 'project_id' } },
  17. tender_info: { main_key: 'id', foreign_key: { project: 'pid', tender: 'tid' } },
  18. ledger: { main_key: 'id', isTree: true, tree_pid: 'ledger_pid', tree_id: 'ledger_id', foreign_key: { tender: 'tender_id' } },
  19. };
  20. class Rpt_Common {
  21. initialize(rpt_tpl, currentDataObj) {
  22. this.template = rpt_tpl;
  23. this.currentDataObj = currentDataObj;
  24. }
  25. Multiply(val1, val2, fixFormat) {
  26. const rst = [];
  27. let maxLen = val1.length;
  28. let minLen = val2.length;
  29. if (minLen > maxLen) {
  30. maxLen = maxLen + minLen; minLen = maxLen - minLen; maxLen = maxLen - minLen;
  31. }
  32. for (let i = 0; i < maxLen; i++) {
  33. let value = ((i < val1.length) ? val1[i] : val1[minLen - 1]) * ((i < val2.length) ? val2[i] : val2[minLen - 1]);
  34. if (value === null || value === undefined) {
  35. value = '0';
  36. }
  37. if (fixFormat) value = value.toFixed(fixFormat);
  38. rst.push(value);
  39. }
  40. return rst;
  41. }
  42. Divide(val1, val2, fixFormat) {
  43. const rst = [];
  44. let maxLen = val1.length;
  45. let minLen = val2.length;
  46. if (minLen > maxLen) {
  47. maxLen = maxLen + minLen; minLen = maxLen - minLen; maxLen = maxLen - minLen;
  48. }
  49. for (let i = 0; i < maxLen; i++) {
  50. let value = ((i < val1.length) ? val1[i] : val1[minLen - 1]) / ((i < val2.length) ? val2[i] : val2[minLen - 1]);
  51. if (fixFormat) value = value.toFixed(fixFormat);
  52. rst.push(value);
  53. }
  54. return rst;
  55. }
  56. Plus(val1, val2, fixFormat) {
  57. const rst = [];
  58. let maxLen = val1.length;
  59. let minLen = val2.length;
  60. if (minLen > maxLen) {
  61. maxLen = maxLen + minLen; minLen = maxLen - minLen; maxLen = maxLen - minLen;
  62. }
  63. for (let i = 0; i < maxLen; i++) {
  64. let value = ((i < val1.length) ? val1[i] : val1[minLen - 1]) + ((i < val2.length) ? val2[i] : val2[minLen - 1]);
  65. if (fixFormat) value = value.toFixed(fixFormat);
  66. rst.push(value);
  67. }
  68. return rst;
  69. }
  70. MultiPlus(arrVal, fixFormat) {
  71. const rst = [];
  72. for (let i = 0; i < arrVal.length; i++) {
  73. const valItem = arrVal[i];
  74. if (i === 0) {
  75. for (const dtl of valItem) {
  76. let value = parseFloat(dtl);
  77. if (fixFormat) value = value.toFixed(fixFormat);
  78. rst.push(value);
  79. }
  80. } else {
  81. for (let j = 0; j < valItem.length; j++) {
  82. if (j < rst.length) {
  83. let value = rst[j] + valItem[j];
  84. if (fixFormat) value = value.toFixed(fixFormat);
  85. rst[j] = value;
  86. } else {
  87. let value = parseFloat(valItem[j]);
  88. if (fixFormat) value = value.toFixed(fixFormat);
  89. rst.push(value);
  90. }
  91. }
  92. }
  93. }
  94. return rst;
  95. }
  96. Minus(val1, val2, fixFormat) {
  97. const rst = [];
  98. let maxLen = val1.length;
  99. let minLen = val2.length;
  100. if (minLen > maxLen) {
  101. maxLen = maxLen + minLen; minLen = maxLen - minLen; maxLen = maxLen - minLen;
  102. }
  103. for (let i = 0; i < maxLen; i++) {
  104. let value = ((i < val1.length) ? val1[i] : val1[minLen - 1]) - ((i < val2.length) ? val2[i] : val2[minLen - 1]);
  105. if (fixFormat) value = value.toFixed(fixFormat);
  106. rst.push(value);
  107. }
  108. return rst;
  109. }
  110. FormatString(arrVal, formatStr) {
  111. const rst = [];
  112. for (const val of arrVal) {
  113. rst.push(stringUtil.replaceAll(formatStr, '%S', val));
  114. }
  115. return rst;
  116. }
  117. }
  118. class Rpt_Data_Extractor {
  119. constructor() {
  120. this.COMMON = new Rpt_Common();
  121. }
  122. initialize(tpl) {
  123. this.rptTpl = tpl;
  124. }
  125. // 因为计量是采用传统的关系数据库(MySQL), 有一些表关系是需要先约定(如上下级关系,外键关系等)
  126. // 根据报表模板映射指标(非离散指标)的定义,罗列出所有需要用到的data对象key,作为数据请求的过滤依据
  127. getDataRequestFilter() {
  128. const rst = {};
  129. const memFieldKeys = {}; // 内存表优化用,需要获得相关内存表的指标请求,因为有些额外指标需要花资源去获得
  130. const tables = []; // 记录需要查询哪些表
  131. // const filters = []; // 记录过滤条件(预处理中的过滤),目前先不处理
  132. const tpl = this.rptTpl;
  133. const pri_func_split_mem_fieldKey = function(field) {
  134. // 计量需要获取所有内存表指标的key,优化用
  135. if (memFieldKeys[field.TableName] === undefined) {
  136. memFieldKeys[field.TableName] = [];
  137. }
  138. const strs = field[JV.PROP_FIELD_EXP_MAP].split("', '");
  139. if (strs.length === 2) {
  140. const codeKey = strs[1].slice(0, strs[1].indexOf("'"));
  141. if (field.TableName.indexOf('mem_') === 0 && memFieldKeys[field.TableName].indexOf(codeKey) < 0) {
  142. memFieldKeys[field.TableName].push(codeKey);
  143. }
  144. }
  145. };
  146. const pri_func_chk_filter = function(field) {
  147. // 计量的机制有所不同,数据分开保存在不同的表里,
  148. if (field.TableName && tables.indexOf(field.TableName) < 0) {
  149. tables.push(field.TableName);
  150. }
  151. pri_func_split_mem_fieldKey(field);
  152. };
  153. const pri_setup_filter = function(FIELD_LIST_KEY) {
  154. // console.log(tpl[JV.NODE_FIELD_MAP][FIELD_LIST_KEY]);
  155. if (tpl[JV.NODE_FIELD_MAP][FIELD_LIST_KEY]) {
  156. for (const field of tpl[JV.NODE_FIELD_MAP][FIELD_LIST_KEY]) {
  157. pri_func_chk_filter(field);
  158. }
  159. }
  160. };
  161. pri_setup_filter(JV.NODE_DISCRETE_FIELDS);
  162. pri_setup_filter(JV.NODE_MASTER_FIELDS);
  163. pri_setup_filter(JV.NODE_DETAIL_FIELDS);
  164. pri_setup_filter(JV.NODE_MASTER_FIELDS_EX);
  165. pri_setup_filter(JV.NODE_DETAIL_FIELDS_EX);
  166. if (tpl[JV.NODE_MAP_DATA_HANDLE_INFO] && tpl[JV.NODE_MAP_DATA_HANDLE_INFO].length > 0) {
  167. // 计量的预处理会有所变化,没有那么多方式,这里只记录过滤
  168. for (const preHandle of tpl[JV.NODE_MAP_DATA_HANDLE_INFO]) {
  169. if (preHandle[JV.PROP_HANDLE_TYPE] === JV.PROP_HANDLE_TYPE_FILTER) {
  170. if (tables.indexOf(preHandle[JV.PROP_DATA_KEY]) < 0) {
  171. tables.push(preHandle[JV.PROP_DATA_KEY]);
  172. }
  173. // 目前还没想好有哪些过滤,骑驴找马吧
  174. }
  175. }
  176. }
  177. rst.tables = tables;
  178. rst.memFieldKeys = memFieldKeys;
  179. return rst;
  180. }
  181. // 装配数据(把收集到的数据,依据报表模板的指示,预处理(如:排序、过滤、合计)及装配到相关指标)
  182. assembleData(rawDataObj, baseDir) {
  183. const $PROJECT = { REPORT: {} };
  184. const tpl = this.rptTpl;
  185. this.COMMON.initialize(tpl, rawDataObj);
  186. $PROJECT.COMMON = this.COMMON;
  187. // console.log(rawDataObj);
  188. setupFunc($PROJECT.REPORT, rawDataObj, baseDir);
  189. if (tpl[JV.NODE_MAP_DATA_HANDLE_INFO]) {
  190. for (const preHandle of tpl[JV.NODE_MAP_DATA_HANDLE_INFO]) {
  191. const srcData = getModuleDataByKey(rawDataObj.prjData, preHandle[JV.PROP_DATA_KEY]);
  192. switch (preHandle[JV.PROP_HANDLE_TYPE]) {
  193. case JV.PROP_HANDLE_TYPE_SORT:
  194. sortData(srcData, preHandle, rawDataObj.prjData);
  195. break;
  196. case JV.PROP_HANDLE_TYPE_FILTER:
  197. filterData(srcData, preHandle, rawDataObj.prjData);
  198. break;
  199. case JV.PROP_HANDLE_TYPE_ADJUST:
  200. adjustData(srcData, preHandle);
  201. break;
  202. default:
  203. break;
  204. }
  205. }
  206. }
  207. const rptDataObj = {};
  208. rptDataObj[JV.DATA_DISCRETE_DATA] = [];
  209. rptDataObj[JV.DATA_MASTER_DATA] = [];
  210. rptDataObj[JV.DATA_DETAIL_DATA] = [];
  211. rptDataObj[JV.DATA_MASTER_DATA_EX] = [];
  212. rptDataObj[JV.DATA_DETAIL_DATA_EX] = [];
  213. assembleFields(tpl[JV.NODE_FIELD_MAP][JV.NODE_DISCRETE_FIELDS], rptDataObj[JV.DATA_DISCRETE_DATA], $PROJECT);
  214. // console.log(JV.DATA_DISCRETE_DATA);
  215. // console.log(rptDataObj[JV.DATA_DISCRETE_DATA]);
  216. assembleFields(tpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS], rptDataObj[JV.DATA_MASTER_DATA], $PROJECT);
  217. // console.log(JV.DATA_MASTER_DATA);
  218. // console.log(rptDataObj[JV.DATA_MASTER_DATA]);
  219. assembleFields(tpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS], rptDataObj[JV.DATA_DETAIL_DATA], $PROJECT);
  220. // console.log(JV.DATA_DETAIL_DATA);
  221. // console.log(rptDataObj[JV.DATA_DETAIL_DATA]);
  222. assembleFields(tpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS_EX], rptDataObj[JV.DATA_MASTER_DATA_EX], $PROJECT);
  223. // console.log(JV.DATA_MASTER_DATA_EX);
  224. // console.log(rptDataObj[JV.DATA_MASTER_DATA_EX]);
  225. assembleFields(tpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS_EX], rptDataObj[JV.DATA_DETAIL_DATA_EX], $PROJECT);
  226. // console.log(JV.DATA_DETAIL_DATA_EX);
  227. // console.log(rptDataObj[JV.DATA_DETAIL_DATA_EX]);
  228. // fsUtil.writeObjToFile(rptDataObj, 'D:/GitHome/temp/insertedOriginalData.jsp');
  229. // fsUtil.writeObjToFile(rawDataObj, 'D:/GitHome/temp/insertedRawDataData.jsp');
  230. // fsUtil.writeObjToFile($PROJECT, 'D:/GitHome/temp/$PROJECTData.jsp');
  231. // fsUtil.writeObjToFile(tpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS], 'D:/GitHome/temp/masterFieldsAfterAssemble.jsp');
  232. // fsUtil.writeObjToFile(tpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS], 'D:/GitHome/temp/detailFieldsAfterAssemble.jsp');
  233. // fsUtil.writeObjToFile(tpl[JV.NODE_FIELD_MAP][JV.NODE_DISCRETE_FIELDS], 'D:/GitHome/temp/discreteFieldsAfterAssemble.jsp');
  234. return rptDataObj;
  235. }
  236. }
  237. function getModuleDataByKey(prjData, key) {
  238. let rst = null;
  239. if (prjData) {
  240. for (const item of prjData) {
  241. if (item.moduleName === key) {
  242. rst = item;
  243. break;
  244. }
  245. }
  246. }
  247. return rst;
  248. }
  249. function filterData(sourceData, handleCfg, prjData) {
  250. let rstArr = [];
  251. const tempRstArr = [];
  252. for (const item of getActDataArr(sourceData)) {
  253. if (item._doc) {
  254. tempRstArr.push(item._doc);
  255. } else {
  256. tempRstArr.push(item);
  257. }
  258. }
  259. const private_chkVal = function(src, compVal, compStr) {
  260. let rst = true;
  261. switch (compStr) {
  262. case '==' :
  263. rst = (src == compVal);
  264. break;
  265. case '===' :
  266. rst = (src === compVal);
  267. break;
  268. case '>' :
  269. rst = (src > compVal);
  270. break;
  271. case '>=' :
  272. rst = (src >= compVal);
  273. break;
  274. case '<' :
  275. rst = (src < compVal);
  276. break;
  277. case '<=' :
  278. rst = (src <= compVal);
  279. break;
  280. case '!=' :
  281. rst = (src != compVal);
  282. break;
  283. case '!==' :
  284. rst = (src !== compVal);
  285. break;
  286. case 'in' :
  287. if (compVal instanceof Array) {
  288. rst = compVal.indexOf(src) >= 0;
  289. } else {
  290. // string,需要转类型
  291. const newInCv = JSON.parse(compVal);
  292. if (newInCv instanceof Array) {
  293. rst = newInCv.indexOf(src) >= 0;
  294. } else {
  295. rst = false;
  296. }
  297. }
  298. break;
  299. case 'not in':
  300. if (compVal instanceof Array) {
  301. rst = compVal.indexOf(src) < 0;
  302. } else {
  303. // string,需要转类型
  304. const newNotInCv = JSON.parse(compVal);
  305. if (newNotInCv instanceof Array) {
  306. rst = (newNotInCv.indexOf(src) < 0);
  307. } else {
  308. rst = true;
  309. }
  310. }
  311. break;
  312. default:
  313. rst = true;
  314. }
  315. return rst;
  316. };
  317. const private_chkArrVal = function(arr, key, compVal, compStr) {
  318. let rst = false;
  319. if (arr.length > 0) {
  320. for (const arrItem of arr) {
  321. if (arrItem[key] !== undefined) {
  322. // 可以为null值去判断
  323. rst = private_chkVal(arrItem[key], compVal, compStr);
  324. }
  325. if (rst) {
  326. break;
  327. }
  328. }
  329. } else {
  330. // 在某些判断条件下(含有'非'判断),如arr没有数组项,默认结果反而是true
  331. switch (compStr) {
  332. case '!=' :
  333. case '!==' :
  334. case 'not in':
  335. rst = true;
  336. break;
  337. default:
  338. break;
  339. }
  340. }
  341. return rst;
  342. };
  343. const private_filter_compare = function(item, filterCfg) {
  344. const compareObj = {};
  345. let compRst = true;
  346. let curComparePrjData = null;
  347. let startIdx = 0;
  348. const private_ref_join = function(refKey, targetDataKey, targetPropertyKey) {
  349. let rst = null;
  350. let objDataArr = null;
  351. curComparePrjData = getModuleDataByKey(prjData, targetDataKey);
  352. try {
  353. if (curComparePrjData !== null) {
  354. objDataArr = getActDataArr(curComparePrjData);
  355. for (const dtl of objDataArr) {
  356. if (item[refKey] === dtl[targetPropertyKey]) {
  357. rst = dtl;
  358. break;
  359. }
  360. }
  361. }
  362. } finally {
  363. curComparePrjData = null;
  364. }
  365. return rst;
  366. };
  367. for (const cfg of filterCfg[JV.PROP_FILTER_KEYS]) {
  368. if (cfg[JV.PROP_FILTER_COMPARE_VAL]) {
  369. // 比较key值
  370. const keys = cfg.key.split('.');
  371. if (keys.length > 1) {
  372. let lastObj = item;
  373. for (let i = 0; i < keys.length - 1; i++) {
  374. if (keys[i].indexOf('ref_join(') === 0) {
  375. const params = keys[i].slice(9, keys[i].length - 1).split(',');
  376. if (params.length === 3) {
  377. lastObj = private_ref_join(params[0], params[1], params[2]);
  378. }
  379. if (!(lastObj)) {
  380. compRst = false;
  381. break;
  382. }
  383. } else {
  384. lastObj = item[keys[i]];
  385. if (!(lastObj)) {
  386. compRst = false;
  387. break;
  388. }
  389. }
  390. }
  391. if (lastObj) {
  392. if (lastObj instanceof Array) {
  393. compRst = private_chkArrVal(lastObj, keys[keys.length - 1], cfg[JV.PROP_FILTER_COMPARE_VAL], cfg[JV.PROP_FILTER_CONDITION]);
  394. } else {
  395. compRst = private_chkVal(lastObj[keys[keys.length - 1]], cfg[JV.PROP_FILTER_COMPARE_VAL], cfg[JV.PROP_FILTER_CONDITION]);
  396. }
  397. }
  398. } else {
  399. compRst = private_chkVal(item[cfg.key], cfg[JV.PROP_FILTER_COMPARE_VAL], cfg[JV.PROP_FILTER_CONDITION]);
  400. }
  401. } else if (cfg[JV.PROP_FILTER_COMPARE_OBJ] && cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY]) {
  402. // 通过其他对象来过滤
  403. if (!curComparePrjData) {
  404. curComparePrjData = getModuleDataByKey(prjData, cfg[JV.PROP_FILTER_COMPARE_OBJ]);
  405. }
  406. if (cfg[JV.PROP_FILTER_CONDITION] === 'in' || cfg[JV.PROP_FILTER_CONDITION] === 'not in') {
  407. let compareArr = null;
  408. if (!compareObj.hasOwnProperty(cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY] + startIdx.toString())) {
  409. compareObj[cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY] + startIdx.toString()] = [];
  410. compareArr = compareObj[cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY] + startIdx.toString()];
  411. for (const data of getActDataArr(curComparePrjData)) {
  412. if (compareArr.indexOf(data[cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY]]) < 0) {
  413. compareArr.push(data[cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY]]);
  414. }
  415. }
  416. } else {
  417. compareArr = compareObj[cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY] + startIdx.toString()];
  418. }
  419. compRst = private_chkVal(item[cfg.key], compareArr, cfg[JV.PROP_FILTER_CONDITION]);
  420. } else {
  421. for (const data of getActDataArr(curComparePrjData)) {
  422. compRst = private_chkVal(item[cfg.key], data[cfg[JV.PROP_FILTER_COMPARE_OBJ_KEY]], cfg[JV.PROP_FILTER_CONDITION]);
  423. if (compRst) break;
  424. }
  425. }
  426. }
  427. startIdx++;
  428. if (!compRst) {
  429. break; // 有不符合条件的数据则退出(这里的判断条件是and关系)
  430. }
  431. }
  432. return compRst;
  433. };
  434. const private_sub_filter_compare = function(dtlItem, subFilters) {
  435. let cmpRst = false;
  436. for (const dtlCfg of subFilters) {
  437. cmpRst = private_filter_compare(dtlItem, dtlCfg);
  438. if (cmpRst) {
  439. if (dtlCfg[JV.PROP_OTHER_SUB_FILTER] && dtlCfg[JV.PROP_OTHER_SUB_FILTER].length > 0) {
  440. cmpRst = private_sub_filter_compare(dtlItem, dtlCfg[JV.PROP_OTHER_SUB_FILTER]);
  441. if (cmpRst) break;
  442. } else {
  443. break;
  444. }
  445. }
  446. }
  447. return cmpRst;
  448. };
  449. for (const item of tempRstArr) {
  450. if (private_filter_compare(item, handleCfg)) {
  451. rstArr.push(item);
  452. }
  453. }
  454. if (handleCfg[JV.PROP_OTHER_SUB_FILTER] && handleCfg[JV.PROP_OTHER_SUB_FILTER].length > 0) {
  455. const newRstArr = [];
  456. for (const dtlItem of rstArr) {
  457. const cmpRst = private_sub_filter_compare(dtlItem, handleCfg[JV.PROP_OTHER_SUB_FILTER]);
  458. if (cmpRst) {
  459. newRstArr.push(dtlItem);
  460. }
  461. }
  462. rstArr = newRstArr;
  463. }
  464. replaceActDataArr(sourceData, rstArr);
  465. // fsUtil.writeObjToFile(sourceData.data, 'D:/GitHome/ConstructionCost/tmp/filteredRst.jsp');
  466. }
  467. function adjustData(sourceData, adjustCfg) {
  468. const rstArr = [];
  469. for (const item of getActDataArr(sourceData)) {
  470. if (item._doc) {
  471. rstArr.push(item._doc);
  472. } else {
  473. rstArr.push(item);
  474. }
  475. }
  476. for (const item of adjustCfg[JV.PROP_ADJUST_COLLECTION]) {
  477. for (const rec of rstArr) {
  478. if (item[JV.PROP_ADJUST_ACTION] === 'prefix') {
  479. rec[item.key] = item[JV.PROP_ADJUST_ACTION_VAL] + rec[item.key];
  480. } else if (item[JV.PROP_ADJUST_ACTION] === 'suffix') {
  481. rec[item.key] = rec[item.key] + item[JV.PROP_ADJUST_ACTION_VAL];
  482. }
  483. }
  484. }
  485. replaceActDataArr(sourceData, rstArr);
  486. }
  487. function sortData(sourceData, sortCfg, prjData) {
  488. let rst = getActDataArr(sourceData);
  489. const tempRstArr = [];
  490. const sortType = sortCfg[JV.PROP_SORT_TYPE];
  491. const srcData = getActDataArr(sourceData);
  492. for (const item of srcData) {
  493. if (item._doc) {
  494. tempRstArr.push(item._doc);
  495. } else {
  496. tempRstArr.push(item);
  497. }
  498. }
  499. function private_normal_sort(destArr, sortKeys) {
  500. destArr.sort(function(a, b) {
  501. let compRst = 0;
  502. for (const comp of sortKeys) {
  503. const reverse = (comp.order === 'ascend') ? 1 : (-1);
  504. //
  505. if (a[comp.key] > b[comp.key]) {
  506. compRst = reverse;
  507. break;
  508. } else if (a[comp.key] < b[comp.key]) {
  509. compRst = -reverse;
  510. break;
  511. }
  512. }
  513. return compRst;
  514. });
  515. }
  516. function private_parent_sort(parentArr, parentKeys, childArr, childKeys) {
  517. const tmpRst = {};
  518. const rst = [];
  519. for (const pItem of parentArr) {
  520. let pKey = 'key';
  521. for (const key of parentKeys) {
  522. pKey += '_' + pItem[key];
  523. }
  524. tmpRst[pKey] = [];
  525. }
  526. for (const cItem of childArr) {
  527. let cKey = 'key';
  528. for (const key of childKeys) {
  529. cKey += '_' + cItem[key];
  530. }
  531. if (tmpRst[cKey]) {
  532. tmpRst[cKey].push(cItem);
  533. } else {
  534. // unknown child value! should be filtered!
  535. }
  536. }
  537. // childArr.splice(0);
  538. for (const pItem of parentArr) {
  539. let pKey = 'key';
  540. for (const key of parentKeys) {
  541. pKey += '_' + pItem[key];
  542. }
  543. rst.push(tmpRst[pKey]);
  544. // for (let rItem of tmpRst[pKey]) {
  545. // childArr.push(rItem);
  546. // }
  547. }
  548. return rst;
  549. }
  550. switch (sortType) {
  551. case 'tree':
  552. const addLevel = true;
  553. rst = treeUtil.buildTreeNodeDirectly(tempRstArr, addLevel);
  554. let newTopArr = [];
  555. if ((sortCfg[JV.PROP_FILTER_TOP_BILLS_NODES] && sortCfg[JV.PROP_FILTER_TOP_BILLS_NODES].length > 0) ||
  556. (sortCfg[JV.PROP_FILTER_OTHER_BILLS_NODES] && sortCfg[JV.PROP_FILTER_OTHER_BILLS_NODES].length > 0)) {
  557. const local_check_bills = function(tItem) {
  558. let chkDtl = false;
  559. if (tItem.flags && tItem.flags.length > 0) {
  560. for (const flagItem of tItem.flags) {
  561. if (sortCfg[JV.PROP_FILTER_OTHER_BILLS_NODES].indexOf(flagItem.flag) >= 0) {
  562. newTopArr.push(tItem);
  563. chkDtl = true;
  564. break;
  565. }
  566. }
  567. }
  568. if (!chkDtl && tItem.items && tItem.items.length > 0) {
  569. for (const dtlItem of tItem.items) {
  570. local_check_bills(dtlItem);
  571. }
  572. }
  573. };
  574. for (const topItem of rst) {
  575. let chkTop = false;
  576. if (topItem.flags && topItem.flags.length > 0) {
  577. for (const flagItem of topItem.flags) {
  578. if (sortCfg[JV.PROP_FILTER_TOP_BILLS_NODES].indexOf(flagItem.flag) >= 0) {
  579. newTopArr.push(topItem);
  580. chkTop = true;
  581. break;
  582. }
  583. }
  584. }
  585. if (!chkTop && sortCfg[JV.PROP_FILTER_OTHER_BILLS_NODES] && sortCfg[JV.PROP_FILTER_OTHER_BILLS_NODES].length > 0) {
  586. local_check_bills(topItem);
  587. }
  588. }
  589. } else {
  590. newTopArr = rst;
  591. }
  592. const destArr = [];
  593. // fsUtil.writeObjToFile(newTopArr, 'D:/GitHome/ConstructionCost/tmp/sortedAndFlattedRstBefore.jsp');
  594. treeUtil.getFlatArray(newTopArr, destArr, true);
  595. // console.log(destArr);
  596. replaceActDataArr(sourceData, destArr);
  597. // fsUtil.writeObjToFile(sourceData.data, 'D:/GitHome/ConstructionCost/tmp/sortedAndFlattedRst.jsp');
  598. break;
  599. case 'normal':
  600. private_normal_sort(tempRstArr, sortCfg[JV.PROP_SORT_KEYS]);
  601. replaceActDataArr(sourceData, tempRstArr);
  602. // fsUtil.writeObjToFile(sourceData.data, 'D:/GitHome/ConstructionCost/tmp/normalSortedRst.jsp');
  603. break;
  604. case 'accord_to_parent':
  605. const pcKey = sortCfg[JV.PROP_PARENT_CHILD_SORT_KEY];
  606. const parentSrcData = getModuleDataByKey(prjData, pcKey[JV.PROP_PARENT_DATA_KEY]);
  607. if (parentSrcData) {
  608. const tempParentArr = [];
  609. for (const item of getActDataArr(parentSrcData)) {
  610. if (item._doc) {
  611. tempParentArr.push(item._doc);
  612. } else {
  613. tempParentArr.push(item);
  614. }
  615. }
  616. const sortedRstArr = private_parent_sort(tempParentArr, pcKey[JV.PROP_PARENT_SORT_KEYS], tempRstArr, pcKey[JV.PROP_CHILD_SORT_KEYS]);
  617. if (sortCfg[JV.PROP_OTHER_SUB_SORT] && sortCfg[JV.PROP_OTHER_SUB_SORT].length > 0) {
  618. for (const sort of sortCfg[JV.PROP_OTHER_SUB_SORT]) {
  619. if (sort[JV.PROP_SORT_TYPE] === 'normal') {
  620. for (const subArr of sortedRstArr) {
  621. private_normal_sort(subArr, sort[JV.PROP_SORT_KEYS]);
  622. }
  623. } else if (sort[JV.PROP_SORT_TYPE] === 'self_define') {
  624. for (const subArr of sortedRstArr) {
  625. // console.log(subArr);
  626. const selfDefFunc = null;
  627. eval('selfDefFunc = ' + sort[JV.PROP_SORT_TYPE_SELF_DEFINE_LOGIC]);
  628. subArr.sort(selfDefFunc);
  629. // console.log(subArr);
  630. }
  631. }
  632. }
  633. }
  634. tempRstArr.splice(0);
  635. for (const item of sortedRstArr) {
  636. for (const subItem of item) {
  637. tempRstArr.push(subItem);
  638. }
  639. }
  640. }
  641. replaceActDataArr(sourceData, tempRstArr);
  642. break;
  643. case 'self_define':
  644. if (sortCfg[JV.PROP_SORT_TYPE_SELF_DEFINE_LOGIC]) {
  645. let selfDefFuncA = null;
  646. eval('selfDefFuncA = ' + sortCfg[JV.PROP_SORT_TYPE_SELF_DEFINE_LOGIC]);
  647. if (selfDefFuncA !== null) {
  648. tempRstArr.sort(selfDefFuncA);
  649. } else {
  650. console.log('sorting function is null!!!');
  651. }
  652. }
  653. replaceActDataArr(sourceData, tempRstArr);
  654. break;
  655. default:
  656. //
  657. }
  658. return rst;
  659. }
  660. function setupFunc(obj, ownRawObj, baseDir) {
  661. obj.myOwnRawDataObj = ownRawObj;
  662. obj.baseDir = baseDir;
  663. obj.getProperty = ext_getProperty;
  664. obj.getSplitProperty = ext_getSplitProperty;
  665. obj.getPicProperty = ext_getPicProperty;
  666. // obj.getPropertyByForeignId = ext_getPropertyByForeignId;
  667. obj.getArrayProperty = ext_getArrayValues;
  668. obj.getBlank = ext_getBlank;
  669. }
  670. function assembleFields(fieldList, rstDataArr, $PROJECT) {
  671. if (fieldList) {
  672. for (const field of fieldList) {
  673. shielded_exec_env($PROJECT, field, rstDataArr);
  674. if ('Precision' in field) {
  675. if (field.Precision.type === 'fixed') {
  676. const vrst = eval(field.Precision.fixedMapExpression);
  677. if (vrst && vrst.length === 1) {
  678. field.fixedPrecisionNum = vrst[0];
  679. vrst.splice(0,1);
  680. }
  681. } else if (field.Precision.type === 'flexible') {
  682. const vrst = eval(field.Precision.flexibleMapExpression);
  683. if (vrst && vrst.length === 1) {
  684. field.flexiblePrecisionRefObj = vrst[0];
  685. vrst.splice(0, 1);
  686. }
  687. }
  688. }
  689. }
  690. }
  691. }
  692. function shielded_exec_env($PROJECT, $ME, rptDataItemObj) {
  693. if ($ME[JV.PROP_FIELD_EXP_MAP]) {
  694. rptDataItemObj.push(eval($ME[JV.PROP_FIELD_EXP_MAP]));
  695. }
  696. }
  697. function getActPropertyVal(firstPropKey, secPropKey, orgObj) {
  698. let rst = null;
  699. if (orgObj[firstPropKey]) {
  700. rst = orgObj[firstPropKey];
  701. } else if (orgObj[secPropKey]) {
  702. rst = orgObj[secPropKey];
  703. }
  704. return rst;
  705. }
  706. function getDeepProperty(propKey, orgObj, destArr) {
  707. const keys = propKey.split('.');
  708. const dftPropKey = 'key';
  709. const dftPropVal = 'value';
  710. const secDftPropVal = 'items';
  711. let parent = orgObj;
  712. let lastVal = null;
  713. for (const key of keys) {
  714. if (parent instanceof Array) {
  715. for (const item of parent) {
  716. if (item[dftPropKey] === key) {
  717. lastVal = getActPropertyVal(dftPropVal, secDftPropVal, item);
  718. break;
  719. }
  720. }
  721. } else {
  722. lastVal = null;
  723. if (parent[key] !== undefined) {
  724. lastVal = parent[key];
  725. } else if (parent[secDftPropVal]) {
  726. for (const item of parent[secDftPropVal]) {
  727. if (item[dftPropKey] === key) {
  728. // lastVal = item[dftPropVal];
  729. lastVal = getActPropertyVal(dftPropVal, secDftPropVal, item);
  730. break;
  731. }
  732. }
  733. }
  734. }
  735. parent = lastVal;
  736. if (parent === null) break;
  737. }
  738. if (destArr && destArr instanceof Array) {
  739. destArr.push(lastVal);
  740. }
  741. }
  742. function ext_getProperty(dataKey, propKey) {
  743. const rst = [];
  744. const parentObj = this;
  745. const dtObj = parentObj.myOwnRawDataObj[dataKey];
  746. // console.log('dataKey: ' + dataKey);
  747. // console.log(dtObj);
  748. if (propKey && dtObj) {
  749. // console.log('---- dtObj[' + dataKey + '] ----');
  750. // console.log(dtObj[dataKey]);
  751. const da = getActDataArr(dtObj);
  752. // console.log(da);
  753. for (const dItem of da) {
  754. // const doc = (dItem._doc === null || dItem._doc === undefined) ? dItem : dItem._doc;
  755. pri_push_property(propKey, dItem, rst);
  756. }
  757. }
  758. // console.log('---- result ----');
  759. // console.log(rst);
  760. return rst;
  761. }
  762. function ext_getSplitProperty(dataKey, propKey, splitChar, index, dftValue) {
  763. const rst = [];
  764. const parentObj = this;
  765. const dtObj = parentObj.myOwnRawDataObj[dataKey];
  766. if (propKey && dtObj) {
  767. const da = getActDataArr(dtObj);
  768. for (const dItem of da) {
  769. pri_push_property(propKey, dItem, rst);
  770. }
  771. }
  772. // const rst = ext_getProperty(dataKey, propKey);
  773. for (let idx = 0; idx < rst.length; idx++) {
  774. if (typeof rst[idx] === 'string') {
  775. const splitArr = rst[idx].split(splitChar);
  776. if (splitArr.length > index) {
  777. rst[idx] = splitArr[index];
  778. } else {
  779. rst[idx] = dftValue;
  780. }
  781. }
  782. }
  783. return rst;
  784. }
  785. async function ext_getPicProperty(dataKey, propKey, isPath) {
  786. const rst = [];
  787. const parentObj = this;
  788. const dtObj = parentObj.myOwnRawDataObj[dataKey];
  789. if (propKey && dtObj) {
  790. const da = getActDataArr(dtObj);
  791. for (const dItem of da) {
  792. pri_push_property(propKey, dItem, rst);
  793. }
  794. if (isPath) {
  795. for (let picIdx = 0; picIdx < rst.length; picIdx++) {
  796. if (rst[picIdx] !== undefined && rst[picIdx] !== null && rst[picIdx] !== '') {
  797. const filePath = parentObj.baseDir + '/app/' + rst[picIdx];
  798. try {
  799. fs.accessSync(filePath, fs.constants.R_OK);
  800. const bData = fs.readFileSync(filePath);
  801. const base64Str = bData.toString('base64');
  802. const datauri = 'data:image/png;base64,' + base64Str;
  803. rst[picIdx] = datauri;
  804. // const res = await isFileExisted(filePath);
  805. // if (res) {
  806. // const bData = fs.readFileSync(filePath);
  807. // const base64Str = bData.toString('base64');
  808. // const datauri = 'data:image/png;base64,' + base64Str;
  809. // rst[picIdx] = datauri;
  810. // } else {
  811. // rst[picIdx] = ''; // 不存在图片,则设置为空,后续的方法就不会当作图片来处理了
  812. // }
  813. } catch (err) {
  814. rst[picIdx] = ''; // 不存在图片,则设置为空,后续的方法就不会当作图片来处理了
  815. console.error(err);
  816. }
  817. }
  818. }
  819. } else {
  820. // 不是路径,那么必须是image data,不用处理,正常走即可
  821. }
  822. }
  823. return rst;
  824. }
  825. function ext_getArrayValues(dataKey, itemKey) {
  826. const rst = [];
  827. const parentObj = this;
  828. const dtObj = parentObj.myOwnRawDataObj[dataKey];
  829. // 计量需要重写
  830. const keysArr = itemKey.split('.');
  831. const da = getActDataArr(dtObj);
  832. // console.log(keysArr);
  833. for (const dataItem of da) {
  834. let itemArr = [];
  835. if (keysArr.length <= 2) {
  836. if (dataItem[keysArr[0]] instanceof Array) {
  837. if (keysArr.length === 2) {
  838. for (const item of dataItem[keysArr[0]]) {
  839. itemArr.push(item[keysArr[1]]);
  840. }
  841. } else {
  842. itemArr = itemArr.concat(dataItem[keysArr[0]]);
  843. }
  844. } else {
  845. if (keysArr.length === 2) {
  846. const subProperty = dataItem[keysArr[0]][keysArr[1]];
  847. if (subProperty instanceof Array) {
  848. itemArr = itemArr.concat(subProperty);
  849. } else {
  850. itemArr.push(subProperty);
  851. }
  852. } else {
  853. itemArr.push(dataItem[keysArr[0]]);
  854. }
  855. }
  856. }
  857. rst.push(itemArr);
  858. // console.log(itemArr);
  859. }
  860. return rst;
  861. }
  862. function ext_getBlank(dataKey, dftVal) {
  863. const rst = [];
  864. const parentObj = this;
  865. const dtObj = parentObj.myOwnRawDataObj[dataKey]; // dataKey是有必要的,必须知道是哪个Table
  866. // 计量需要重写
  867. if (dtObj) {
  868. const dtData = getActDataArr(dtObj);
  869. for (let i = 0; i < dtData.length; i++) {
  870. if (dftVal !== null && dftVal !== undefined) {
  871. rst.push(dftVal)
  872. } else rst.push('');
  873. }
  874. }
  875. return rst;
  876. }
  877. function ext_getPropertyByForeignId(foreignIdVal, adHocIdKey, propKey, dftValIfNotFound) {
  878. const rst = [];
  879. // 计量需要重写
  880. return rst;
  881. }
  882. function getActDataArr(dtObj) {
  883. let rst = [];
  884. if (dtObj) {
  885. if (dtObj instanceof Array) {
  886. rst = rst.concat(dtObj);
  887. } else {
  888. rst.push(dtObj);
  889. }
  890. }
  891. return rst;
  892. }
  893. function replaceActDataArr(dtObj, newArr) {
  894. if (dtObj.moduleName === 'projectGLJ') {
  895. delete dtObj.data.gljList;
  896. dtObj.data.gljList = newArr;
  897. } else {
  898. delete dtObj.data;
  899. dtObj.data = newArr;
  900. }
  901. }
  902. function pri_push_property(propKey, doc, rst) {
  903. if (propKey instanceof Array) {
  904. // 备注:这里的key数组表示取value的优先级
  905. for (let pi = 0; pi < propKey.length; pi++) {
  906. if (doc.hasOwnProperty('property')) {
  907. if (doc['property'].hasOwnProperty(propKey[pi])) {
  908. rst.push(doc['property'][propKey[pi]]);
  909. break;
  910. }
  911. } else if (doc.hasOwnProperty(propKey[pi])) {
  912. rst.push(doc[propKey[pi]]);
  913. break;
  914. } else {
  915. const lenBefore = rst.length;
  916. getDeepProperty(propKey[pi], doc, rst);
  917. if (rst.length === (lenBefore + 1)) {
  918. if (rst[lenBefore] !== null && rst[lenBefore] !== undefined && rst[lenBefore] !== '') {
  919. break;
  920. } else {
  921. rst.splice(-1, 1); // 删除末尾一条数据,给后面留空间
  922. }
  923. }
  924. }
  925. if (pi === propKey.length - 1) rst.push('');
  926. }
  927. } else {
  928. if (doc.hasOwnProperty('property') && doc['property'].hasOwnProperty(propKey)) {
  929. rst.push(doc['property'][propKey]);
  930. } else if (doc.hasOwnProperty(propKey)) {
  931. rst.push(doc[propKey]);
  932. } else {
  933. getDeepProperty(propKey, doc, rst);
  934. }
  935. }
  936. }
  937. // export default Rpt_Data_Extractor;
  938. module.exports = Rpt_Data_Extractor;