importBills.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Zhong
  6. * @date 2018/8/2
  7. * @version
  8. */
  9. /*
  10. * 清单导入模块,前端导入excel,进行数据提取,用lz-string进行压缩上传处理
  11. * */
  12. const importBills = (function(){
  13. //单元格数据是否存在
  14. function _isDef(data){
  15. return typeof data !== 'undefined' && data !== null && data !== '';
  16. }
  17. //去除转义字符
  18. function _deESC(data) {
  19. return _isDef(data) ? data.toString().replace(/[\r\n\s\t]/g, '') : data;
  20. }
  21. function _deNR(data) {
  22. return _isDef(data) ? data.toString().replace(/\r\r/g, '\r') : data;
  23. }
  24. //列名对应中文字符
  25. const colText = {
  26. serialNo: ['序号'],
  27. code: ['编码', '项目编码'],
  28. name: ['名称', '项目名称'],
  29. itemCharacterText: ['特征', '项目特征', '项目特征描述'],
  30. unit: ['单位', '计量单位'],
  31. quantity: ['工程量', '项目工程量'],
  32. money: ['金额'],
  33. unitPrice: ['综合单价', '单价'],
  34. quantityDetail: ['工程量明细'],
  35. feeDetail: ['费用明细'],
  36. summation: ['合计', '本页小计'],
  37. };
  38. //导入位置对应清单固定标记
  39. const positionFlag = {
  40. fbfx: fixedFlag.SUB_ENGINERRING,
  41. jscsxm: fixedFlag.CONSTRUCTION_TECH,
  42. zzcsxm: fixedFlag.CONSTRUCTION_ORGANIZATION,
  43. };
  44. //上传类型
  45. const uploadType = {
  46. general: 'general',
  47. lj: 'lj',
  48. gld: 'gld',
  49. };
  50. let curFileType = uploadType.general;
  51. //设置导入表内容(选择导入位置)
  52. //@param {Object}workBook
  53. function setImportSheetsInfo(sheets){
  54. let sheetNames = [];
  55. let indexMapping = {};
  56. for(let sheetName in sheets){
  57. indexMapping[sheets[sheetName]['index']] = sheetName;
  58. }
  59. let sheetsCount = Object.keys(sheets).length;
  60. for(let i = 0; i < sheetsCount; i++){
  61. sheetNames.push(indexMapping[i]);
  62. }
  63. let sheetArea = $('#uploadSheets'),
  64. sheetHeader = $('#uploadSheetsHead');
  65. $('#uploadSheets').height('');
  66. sheetArea.empty();
  67. for(let sheetName of sheetNames){
  68. let sheetDiv = $(`<div style="margin-left: 5px;margin-top: 5px;" title="${sheetName}" class="input-group form-check"><label class="form-check-label" style="width:270px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis">
  69. <input class="form-check-input" type="checkbox">${sheetName}</label></div>`);
  70. sheetDiv.find('input[type="checkbox"]').click(function () {
  71. if($('#uploadAlert').is(':visible')){
  72. $('#uploadAlert').hide();
  73. }
  74. });
  75. let sel = $(`<select style="margin-left: 5px; border-radius: .20rem;"><option value="fbfx">分部分项工程</option><option value="zzcsxm">施工组织措施项目</option><option value="jscsxm">施工技术措施项目</option></select>`);
  76. if(sheetName.includes('分部分项工程项目清单计价表')){
  77. sheetDiv.find('input[type="checkbox"]').prop('checked', true);
  78. sel.find('option:eq(0)').prop('selected', true);
  79. }
  80. else if(sheetName.includes('施工组织措施项目清单计价表')){
  81. sheetDiv.find('input[type="checkbox"]').prop('checked', true);
  82. sel.find('option:eq(1)').prop('selected', true);
  83. }
  84. else if(sheetName.includes('施工技术措施项目清单计价表')){
  85. sheetDiv.find('input[type="checkbox"]').prop('checked', true);
  86. sel.find('option:eq(2)').prop('selected', true);
  87. }
  88. sheetDiv.append(sel);
  89. sheetArea.append(sheetDiv);
  90. }
  91. if(sheetNames.length > 0){
  92. sheetArea.show();
  93. sheetHeader.show();
  94. }
  95. if($('#uploadSheets').height() > 250){
  96. sheetArea.css('overflow', 'auto');
  97. sheetArea.height(250);
  98. }
  99. else {
  100. sheetArea.css('overflow', 'hidden');
  101. }
  102. }
  103. //获得选择导入的表信息(表索引及导入位置)
  104. //@return {Object}
  105. function getImportSheetsInfo(){
  106. let rst = [];
  107. let sheetArea = $('#uploadSheets');
  108. let checkedInputs = sheetArea.find('input:checked');
  109. for(let checked of checkedInputs){
  110. rst.push({index: $(checked).parent().parent().index(), position: $(checked).parent().next().select().val()})
  111. }
  112. return rst;
  113. }
  114. function getSheetByIndex(sheets, index){
  115. for(let sheetName in sheets){
  116. let sheet = sheets[sheetName];
  117. if(sheet.index === index){
  118. return sheet;
  119. }
  120. }
  121. return null;
  122. }
  123. //提取excel表头列名与列下标映射
  124. function getColMapping(dataTable){
  125. //获取表头
  126. function getHeadRow(dataTable){
  127. const headTexts = [colText.serialNo[0], ...colText.code];
  128. for(let rowIdx in dataTable ){
  129. for(let colIdx in dataTable[rowIdx]){
  130. let cellData = dataTable[rowIdx][colIdx]['value'];
  131. if(cellData && headTexts.includes(_deESC(cellData))){
  132. return dataTable[rowIdx];
  133. }
  134. }
  135. }
  136. return {};
  137. }
  138. //获取需要的表头列与列号对应关系
  139. let colMapping = {};
  140. let headRow = getHeadRow(dataTable);
  141. for(let colIdx in headRow){
  142. let cellData = headRow[colIdx]['value'];
  143. if(!_isDef(cellData)){
  144. continue;
  145. }
  146. //序号
  147. if(colMapping.serialNo === undefined && _deESC(cellData) === colText.serialNo[0]){
  148. colMapping.serialNo = colIdx;
  149. }
  150. //编码
  151. else if(colMapping.code === undefined && (_deESC(cellData) === colText.code[0] || _deESC(cellData) === colText.code[1])){
  152. colMapping.code = colIdx;
  153. }
  154. //名称
  155. else if(colMapping.name === undefined && (_deESC(cellData) === colText.name[0] || _deESC(cellData) === colText.name[1])){
  156. colMapping.name = colIdx;
  157. }
  158. //项目特征
  159. else if(colMapping.itemCharacterText === undefined && (_deESC(cellData) === colText.itemCharacterText[0] || _deESC(cellData) === colText.itemCharacterText[1]
  160. || _deESC(cellData) === colText.itemCharacterText[2])){
  161. colMapping.itemCharacterText = colIdx;
  162. }
  163. //单位
  164. else if(colMapping.unit === undefined && (_deESC(cellData) === colText.unit[0] || _deESC(cellData) === colText.unit[1])){
  165. colMapping.unit = colIdx;
  166. }
  167. //工程量
  168. else if(colMapping.quantity === undefined && (_deESC(cellData) === colText.quantity[0] || _deESC(cellData) === colText.quantity[1])){
  169. colMapping.quantity = colIdx;
  170. }
  171. //金额
  172. else if(colMapping.money === undefined && _deESC(cellData).includes(colText.money[0])){
  173. colMapping.money = colIdx;
  174. // 特殊处理单价
  175. colMapping.unitPrice = colIdx;
  176. }
  177. //工程量明细
  178. else if(colMapping.quantityDetail === undefined && _deESC(cellData) === colText.quantityDetail[0]){
  179. colMapping.quantityDetail = colIdx;
  180. }
  181. //费用明细
  182. else if(colMapping.feeDetail === undefined && _deESC(cellData) === colText.feeDetail[0]){
  183. colMapping.feeDetail = colIdx;
  184. }
  185. }
  186. return colMapping;
  187. }
  188. // 根据列设置判断从excel表上传界面,上传的具体类型是什么:自定义通用表和09表使用了同一个按钮,因此在获取列设置的时候,还要再区分general和lj
  189. function getExactlyFileType(colMapping) {
  190. // 只需要区分自定义通用表和09表
  191. return !_isDef(colMapping.serialNo) && !_isDef(colMapping.money)
  192. ? uploadType.general
  193. : uploadType.lj;
  194. }
  195. //是否是有效的表头列格式,只要含有各表需要的列就行,不严格控制多少列
  196. function isValidSheet(colMapping){
  197. function hasField(field, all){
  198. for(let i of all){
  199. if(field === i){
  200. return true;
  201. }
  202. }
  203. return false;
  204. }
  205. let needFields;
  206. if (curFileType === uploadType.general) {
  207. // 自定义通用表:项目编码 项目名称 项目特征 计量单位 工程量
  208. needFields = ['code', 'name', 'itemCharacterText', 'unit', 'quantity'];
  209. } else if(curFileType === uploadType.lj){
  210. //09表:序号、项目编码、项目名称、项目特征、计量单位、工程量、金额
  211. needFields = ['serialNo', 'code', 'name', 'money'];
  212. } else {
  213. //广联达表:序号、项目编码、项目名称、项目特征、计量单位、工程量、工程量明细、费用明细
  214. needFields = ['serialNo', 'code', 'name', 'itemCharacterText', 'unit', 'quantity', 'quantityDetail', 'feeDetail'];
  215. }
  216. let hasFieldCount = 0;
  217. for(let attr in colMapping){
  218. if(hasField(attr, needFields)){
  219. hasFieldCount++;
  220. }
  221. }
  222. return hasFieldCount === needFields.length;
  223. }
  224. //获取要无效和有效导入表
  225. //@param {Array}importSheetInfo 勾选要导入的表
  226. function getImportSheets(sheets, sheetsInfo, fileType){
  227. curFileType = fileType; // 自定义通用表和09表使用了同一个按钮,因此在获取列设置的时候,还要再区分general和lj
  228. let isGetType = false;
  229. let rst = {invalidSheets: [], validSheets: {fbfx: [], jscsxm: [], zzcsxm: []}};
  230. for(let sheetInfo of sheetsInfo){
  231. let sheet = getSheetByIndex(sheets, sheetInfo.index);
  232. if(!sheet){
  233. continue;
  234. }
  235. //没有数据
  236. if(!sheet.data.dataTable){
  237. rst.invalidSheets.push(sheet.name);
  238. continue;
  239. }
  240. //获取表的列设置确定导入的格式是否合法(通用excel、09、广联达)
  241. let colMapping = getColMapping(sheet.data.dataTable);
  242. // 以第一个有效的sheet作为类型基准
  243. if (!isGetType && fileType === uploadType.lj) {
  244. curFileType = getExactlyFileType(colMapping);
  245. }
  246. if(!isValidSheet(colMapping)){
  247. rst.invalidSheets.push(sheet.name);
  248. continue;
  249. }
  250. isGetType = true;
  251. //合法的表
  252. sheet.colMapping = colMapping;
  253. //将合法的表按导入位置分类当做一个表来处理
  254. if(rst.validSheets[sheetInfo.position] !== undefined){
  255. rst.validSheets[sheetInfo.position].push(sheet)
  256. }
  257. }
  258. return rst;
  259. }
  260. //行存在数据
  261. function rowExistData(rowData){
  262. for(let colIdx in rowData){
  263. let colData = rowData[colIdx]['value'];
  264. if(_isDef(colData)){
  265. return true;
  266. }
  267. }
  268. return false;
  269. }
  270. //提取excel表数据中的有效数据(去表头表尾,提取其中的excel数据)(根据fixedBill获取栏头占行数)
  271. function getValidImportData(colMapping, sheetData){
  272. let withingD = false;
  273. let validData = [];
  274. function isHead(rData){
  275. return curFileType === uploadType.general
  276. ? rData[colMapping.code] && colText.code.includes(_deESC(rData[colMapping.code]['value']))
  277. : rData[colMapping.serialNo] && _deESC(rData[colMapping.serialNo]['value']) === colText.serialNo[0];
  278. }
  279. function isTail(rowData){
  280. for(let colIdx in rowData){
  281. let colData = rowData[colIdx]['value'];
  282. if(colData){
  283. let trimColData= _deESC(colData);
  284. if(trimColData === colText.summation[0] || trimColData === colText.summation[1]){
  285. return true;
  286. }
  287. }
  288. }
  289. return false;
  290. }
  291. for(let rowIdx in sheetData){
  292. let rowData = sheetData[rowIdx];
  293. if(isHead(rowData)){
  294. withingD = true;
  295. continue;
  296. }
  297. else if(isTail(rowData)){
  298. withingD = false;
  299. }
  300. if(withingD && rowExistData(rowData)){
  301. validData.push(rowData);
  302. }
  303. }
  304. return validData;
  305. }
  306. //excel数据转换成清单数据
  307. function parseToBillData(validData, colMapping, flag, projectID){
  308. let rst = [];
  309. let billIdx = {};
  310. let preRootID = -1,
  311. preLeafID = -1,
  312. preID = -1;
  313. //父节点
  314. function isRoot(rData){
  315. //序号和编码去除转义字符(有的表格单元格看起来是没数据,实际含有\r,\n等数据)
  316. const code = rData[colMapping.code] ? _deESC(rData[colMapping.code]['value']) : '';
  317. const unit = rData[colMapping.unit] ? _deESC(rData[colMapping.unit]['value']) : '';
  318. if (curFileType === uploadType.general) {
  319. // 通用表:项目编码非12位或者无单位的
  320. return !_isDef(code) || !/\w{12}/.test(code) || !_isDef(unit);
  321. } else {
  322. // 09、广联达表:1.无序号 2有编码
  323. const serialNo = rData[colMapping.serialNo] ? _deESC(rData[colMapping.serialNo]['value']) : '';
  324. return !_isDef(serialNo) && _isDef(code);
  325. }
  326. }
  327. //子节点
  328. function isLeaf(rData){
  329. if (curFileType === uploadType.general) {
  330. // 通用表:项目编码12位且有单位的
  331. const code = rData[colMapping.code] ? _deESC(rData[colMapping.code]['value']) : '';
  332. const unit = rData[colMapping.unit] ? _deESC(rData[colMapping.unit]['value']) : '';
  333. return _isDef(code) && /\w{12}/.test(code) && _isDef(unit);
  334. } else {
  335. // 09、广联达表:有序号
  336. const serialNo = rData[colMapping.serialNo] ? _deESC(rData[colMapping.serialNo]['value']) : '';
  337. return _isDef(serialNo);
  338. }
  339. }
  340. //续数据:1. 前数据有效 2.无序号 3.无编码 4.有名称或特征
  341. function isExtend(preData, rData){
  342. if (curFileType === uploadType.general) {
  343. // 通用表:1. 前数据有效 2.无编码 3.无单位 4.有名称或特征
  344. let code = rData[colMapping.code] ? _deESC(rData[colMapping.code]['value']) : '';
  345. let unit = rData[colMapping.unit] ? _deESC(rData[colMapping.unit]['value']) : '';
  346. let name = rData[colMapping.name] ? _deESC(rData[colMapping.name]['value']) : '';
  347. let itemCharacterText = rData[colMapping.itemCharacterText] ? _deESC(rData[colMapping.itemCharacterText]['value']) : '';
  348. return _isDef(preData) && (isRoot(preData) || isLeaf(preData)) && !_isDef(unit) && !_isDef(code) && (_isDef(name) || _isDef(itemCharacterText));
  349. } else {
  350. // 09、广联达表:1. 前数据有效 2.无序号 3.无编码 4.有名称或特征
  351. let serialNo = rData[colMapping.serialNo] ? _deESC(rData[colMapping.serialNo]['value']) : '';
  352. let code = rData[colMapping.code] ? _deESC(rData[colMapping.code]['value']) : '';
  353. let name = rData[colMapping.name] ? _deESC(rData[colMapping.name]['value']) : '';
  354. let itemCharacterText = rData[colMapping.itemCharacterText] ? _deESC(rData[colMapping.itemCharacterText]['value']) : '';
  355. return _isDef(preData) && (isRoot(preData) || isLeaf(preData)) && !_isDef(serialNo) && !_isDef(code) && (_isDef(name) || _isDef(itemCharacterText));
  356. }
  357. }
  358. function getBillType(rData, flag){
  359. if(flag === fixedFlag.CONSTRUCTION_TECH || flag === fixedFlag.CONSTRUCTION_ORGANIZATION){
  360. return billType.BILL;
  361. }
  362. else if(flag === fixedFlag.SUB_ENGINERRING){
  363. return isLeaf(rData) ? billType.FX : billType.FB;
  364. }
  365. return null;
  366. }
  367. let preData = null;
  368. for(let r = 0; r < validData.length; r++){
  369. let rData = validData[r];
  370. if(flag == fixedFlag.CONSTRUCTION_TECH && rData[colMapping.name] && rData[colMapping.name]['value'] === '施工技术措施项目'
  371. || flag == fixedFlag.CONSTRUCTION_ORGANIZATION && rData[colMapping.name] && rData[colMapping.name]['value'] === '施工组织措施项目'){
  372. continue;
  373. }
  374. //过滤无效数据
  375. if(!isRoot(rData) && !isLeaf(rData) && !isExtend(preData, rData)){
  376. continue;
  377. }
  378. if(isExtend(preData, rData)){
  379. let preBill = billIdx[preID];
  380. if(preBill){
  381. //合并续数据
  382. preBill.code += rData[colMapping.code] && rData[colMapping.code]['value'] && _isDef(_deESC(rData[colMapping.code]['value'])) ? rData[colMapping.code]['value'] : '';
  383. preBill.name += rData[colMapping.name] && rData[colMapping.name]['value'] && _isDef(_deESC(rData[colMapping.name]['value'])) ? rData[colMapping.name]['value'] : '';
  384. preBill.itemCharacterText += rData[colMapping.itemCharacterText] && rData[colMapping.itemCharacterText]['value'] && _isDef(_deESC(rData[colMapping.itemCharacterText]['value']))
  385. ? '\n' + _deNR(rData[colMapping.itemCharacterText]['value']) : '';
  386. preBill.unit += rData[colMapping.unit] && rData[colMapping.unit]['value'] && _isDef(_deESC(rData[colMapping.unit]['value'])) ? rData[colMapping.unit]['value'] : '';
  387. preBill.quantity += rData[colMapping.quantity] && rData[colMapping.quantity]['value'] && _isDef(_deESC(rData[colMapping.quantity]['value'])) ? rData[colMapping.quantity]['value'] : '';
  388. preBill.unitPrice += rData[colMapping.unitPrice] && rData[colMapping.unitPrice]['value'] && _isDef(_deESC(rData[colMapping.unitPrice]['value'])) ? rData[colMapping.unitPrice]['value'] : '';
  389. }
  390. } else {
  391. let newID = uuid.v1();
  392. let pID = -1;
  393. let preBill = null;
  394. let preRoot = null,
  395. preLeaf = null;
  396. let nodeType = 'root';//后端以此标记来设置ParentID
  397. let preSerialBill = billIdx[preID];
  398. if(isRoot(rData)){
  399. //pID = 'fixedBillID';
  400. preBill = billIdx[preRootID];
  401. preRoot = billIdx[preRootID];
  402. } else if(isLeaf(rData)){
  403. nodeType = 'leaf';
  404. //pID = preRootID !== -1 ? preRootID : fixedBill.ID;
  405. preBill = billIdx[preLeafID];
  406. preLeaf = billIdx[preLeafID];
  407. }
  408. //set bill data
  409. billIdx[newID] = {
  410. nodeType: nodeType,
  411. ID: newID, ParentID: pID, NextSiblingID: -1,
  412. code: rData[colMapping.code] && rData[colMapping.code]['value'] ? _deESC(rData[colMapping.code]['value']) : '',
  413. name: rData[colMapping.name] && rData[colMapping.name]['value'] ? _deESC(rData[colMapping.name]['value']) : '',
  414. itemCharacterText: rData[colMapping.itemCharacterText] && rData[colMapping.itemCharacterText]['value'] ? _deNR(rData[colMapping.itemCharacterText]['value']) : '',
  415. itemCharacter: [],
  416. jobContentText: '',
  417. jobContent: [],
  418. programID: null,
  419. unit: rData[colMapping.unit] && rData[colMapping.unit]['value'] ? _deESC(rData[colMapping.unit]['value']) : '',
  420. quantity: rData[colMapping.quantity] && rData[colMapping.quantity]['value'] ? _deESC(rData[colMapping.quantity]['value']) : '',
  421. quantityEXP: rData[colMapping.quantity] && rData[colMapping.quantity]['value'] ? _deESC(rData[colMapping.quantity]['value']) : '',
  422. unitPrice: rData[colMapping.unitPrice] && rData[colMapping.unitPrice]['value'] ? _deESC(rData[colMapping.unitPrice]['value']) : '',
  423. //安全文明
  424. flags: flag === fixedFlag.CONSTRUCTION_ORGANIZATION && (rData[colMapping.name] && (rData[colMapping.name]['value'] === '安全文明施工专项费用' || rData[colMapping.name]['value'] === '安全文明施工费')) ?
  425. [{fieldName: 'fixed', flag: fixedFlag.SAFETY_CONSTRUCTION}] : [],
  426. fees: [],
  427. projectID: projectID,
  428. type: getBillType(rData, flag)};
  429. //update preBill NextSibling
  430. if(nodeType === 'root' && preRoot){
  431. preRoot.NextSiblingID = newID;
  432. } else if(nodeType === 'leaf' && preLeaf && preSerialBill && preSerialBill.nodeType === preLeaf.nodeType){
  433. preLeaf.NextSiblingID = newID;
  434. }
  435. /* if(preBill){
  436. preBill.NextSiblingID = newID;
  437. }*/
  438. //set new preID
  439. preID = newID;
  440. preRootID = isRoot(rData) ? newID : preRootID;
  441. preLeafID = isLeaf(rData) ? newID : preLeafID;
  442. }
  443. preData = rData;
  444. }
  445. for(let i in billIdx){
  446. if (!commonUtil.isEmptyVal(billIdx[i].unitPrice)) {
  447. billIdx[i].lockUnitPrice = true;
  448. const quantity = +billIdx[i].quantity || 0;
  449. const unitPrice = +billIdx[i].unitPrice;
  450. const totalPrice = scMathUtil.roundForObj(unitPrice * quantity, decimalObj.bills.totalPrice);
  451. billIdx[i].fees = [
  452. {
  453. fieldName: "common",
  454. tenderTotalFee: totalPrice,
  455. tenderUnitFee: unitPrice,
  456. totalFee: totalPrice,
  457. unitFee: unitPrice,
  458. }
  459. ];
  460. delete billIdx[i].unitPrice;
  461. }
  462. rst.push(billIdx[i]);
  463. }
  464. return rst;
  465. }
  466. /* function parseToBillData(validData, colMapping, flag, projectID){
  467. let rst = [];
  468. let billIdx = {};
  469. let preRootID = -1,
  470. preLeafID = -1,
  471. preID = -1;
  472. //父节点:1.无序号 2有编码
  473. function isRoot(rData){
  474. //序号和编码去除转义字符(有的表格单元格看起来是没数据,实际含有\r,\n等数据)
  475. let serialNo = rData[colMapping.serialNo] ? _deESC(rData[colMapping.serialNo]['value']) : '';
  476. let code = rData[colMapping.code] ? _deESC(rData[colMapping.code]['value']) : '';
  477. return !_isDef(serialNo) && _isDef(code);
  478. }
  479. //子节点:有序号
  480. function isLeaf(rData){
  481. let serialNo = rData[colMapping.serialNo] ? _deESC(rData[colMapping.serialNo]['value']) : '';
  482. return _isDef(serialNo);
  483. }
  484. //续数据:1. 前数据有效 2.无序号 3.无编码 4.有名称或特征
  485. function isExtend(preData, rData){
  486. let serialNo = rData[colMapping.serialNo] ? _deESC(rData[colMapping.serialNo]['value']) : '';
  487. let code = rData[colMapping.code] ? _deESC(rData[colMapping.code]['value']) : '';
  488. let name = rData[colMapping.name] ? _deESC(rData[colMapping.name]['value']) : '';
  489. let itemCharacterText = rData[colMapping.itemCharacterText] ? _deESC(rData[colMapping.itemCharacterText]['value']) : '';
  490. return _isDef(preData) && (isRoot(preData) || isLeaf(preData)) && !_isDef(serialNo) && !_isDef(code) && (_isDef(name) || _isDef(itemCharacterText));
  491. }
  492. function getBillType(rData, flag){
  493. if(flag === fixedFlag.CONSTRUCTION_TECH || flag === fixedFlag.CONSTRUCTION_ORGANIZATION){
  494. return billType.BILL;
  495. }
  496. else if(flag === fixedFlag.SUB_ENGINERRING){
  497. return isLeaf(rData) ? billType.FX : billType.FB;
  498. }
  499. return null;
  500. }
  501. let preData = null;
  502. for(let r = 0; r < validData.length; r++){
  503. let rData = validData[r];
  504. if(flag == fixedFlag.CONSTRUCTION_TECH && rData[colMapping.name] && rData[colMapping.name]['value'] === '施工技术措施项目'
  505. || flag == fixedFlag.CONSTRUCTION_ORGANIZATION && rData[colMapping.name] && rData[colMapping.name]['value'] === '施工组织措施项目'){
  506. continue;
  507. }
  508. //过滤无效数据
  509. if(!isRoot(rData) && !isLeaf(rData) && !isExtend(preData, rData)){
  510. continue;
  511. }
  512. if(isExtend(preData, rData)){
  513. let preBill = billIdx[preID];
  514. if(preBill){
  515. //合并续数据
  516. preBill.code += rData[colMapping.code] && rData[colMapping.code]['value'] && _isDef(_deESC(rData[colMapping.code]['value'])) ? rData[colMapping.code]['value'] : '';
  517. preBill.name += rData[colMapping.name] && rData[colMapping.name]['value'] && _isDef(_deESC(rData[colMapping.name]['value'])) ? rData[colMapping.name]['value'] : '';
  518. preBill.itemCharacterText += rData[colMapping.itemCharacterText] && rData[colMapping.itemCharacterText]['value'] && _isDef(_deESC(rData[colMapping.itemCharacterText]['value']))
  519. ? '\n' + _deNR(rData[colMapping.itemCharacterText]['value']) : '';
  520. preBill.unit += rData[colMapping.unit] && rData[colMapping.unit]['value'] && _isDef(_deESC(rData[colMapping.unit]['value'])) ? rData[colMapping.unit]['value'] : '';
  521. preBill.quantity += rData[colMapping.quantity] && rData[colMapping.quantity]['value'] && _isDef(_deESC(rData[colMapping.quantity]['value'])) ? rData[colMapping.quantity]['value'] : '';
  522. }
  523. }
  524. else {
  525. let newID = uuid.v1();
  526. let pID = -1;
  527. let preBill = null;
  528. let preRoot = null,
  529. preLeaf = null;
  530. let nodeType = 'root';//后端以此标记来设置ParentID
  531. let preSerialBill = billIdx[preID];
  532. if(isRoot(rData)){
  533. //pID = 'fixedBillID';
  534. preBill = billIdx[preRootID];
  535. preRoot = billIdx[preRootID];
  536. }
  537. else if(isLeaf(rData)){
  538. nodeType = 'leaf';
  539. //pID = preRootID !== -1 ? preRootID : fixedBill.ID;
  540. preBill = billIdx[preLeafID];
  541. preLeaf = billIdx[preLeafID];
  542. }
  543. //set bill data
  544. billIdx[newID] = {
  545. nodeType: nodeType,
  546. ID: newID, ParentID: pID, NextSiblingID: -1,
  547. code: rData[colMapping.code] && rData[colMapping.code]['value'] ? _deESC(rData[colMapping.code]['value']) : '',
  548. name: rData[colMapping.name] && rData[colMapping.name]['value'] ? _deESC(rData[colMapping.name]['value']) : '',
  549. itemCharacterText: rData[colMapping.itemCharacterText] && rData[colMapping.itemCharacterText]['value'] ? _deNR(rData[colMapping.itemCharacterText]['value']) : '',
  550. itemCharacter: [],
  551. jobContentText: '',
  552. jobContent: [],
  553. programID: null,
  554. unit: rData[colMapping.unit] && rData[colMapping.unit]['value'] ? _deESC(rData[colMapping.unit]['value']) : '',
  555. quantity: rData[colMapping.quantity] && rData[colMapping.quantity]['value'] ? _deESC(rData[colMapping.quantity]['value']) : '',
  556. quantityEXP: rData[colMapping.quantity] && rData[colMapping.quantity]['value'] ? _deESC(rData[colMapping.quantity]['value']) : '',
  557. //安全文明
  558. flags: flag === fixedFlag.CONSTRUCTION_ORGANIZATION && (rData[colMapping.name] && (rData[colMapping.name]['value'] === '安全文明施工专项费用' || rData[colMapping.name]['value'] === '安全文明施工费')) ?
  559. [{fieldName: 'fixed', flag: fixedFlag.SAFETY_CONSTRUCTION}] : [],
  560. fees: [],
  561. projectID: projectID,
  562. type: getBillType(rData, flag)};
  563. //update preBill NextSibling
  564. if(nodeType === 'root' && preRoot){
  565. preRoot.NextSiblingID = newID;
  566. }
  567. else if(nodeType === 'leaf' && preLeaf && preSerialBill && preSerialBill.nodeType === preLeaf.nodeType){
  568. preLeaf.NextSiblingID = newID;
  569. }
  570. //set new preID
  571. preID = newID;
  572. preRootID = isRoot(rData) ? newID : preRootID;
  573. preLeafID = isLeaf(rData) ? newID : preLeafID;
  574. }
  575. preData = rData;
  576. }
  577. for(let i in billIdx){
  578. rst.push(billIdx[i]);
  579. }
  580. return rst;
  581. } */
  582. function getImportData(validSheets, projectID){
  583. let rst = {fbfx: [], jscsxm: [], zzcsxm: []};
  584. let validSheetsDatas = [];
  585. for(let uploadPosition in validSheets){
  586. let validExcelData = [];
  587. for(let uSheet of validSheets[uploadPosition]){
  588. validExcelData = validExcelData.concat(getValidImportData(uSheet.colMapping, uSheet.data.dataTable));
  589. }
  590. if(validSheets[uploadPosition].length > 0){
  591. validSheetsDatas.push({position: uploadPosition, colMapping: validSheets[uploadPosition][0].colMapping, validExcelData: validExcelData});
  592. }
  593. }
  594. for(let validSheetData of validSheetsDatas){
  595. if(validSheetData.validExcelData.length > 0){
  596. rst[validSheetData.position] = parseToBillData(validSheetData.validExcelData, validSheetData.colMapping, positionFlag[validSheetData.position], projectID);
  597. }
  598. }
  599. return rst;
  600. }
  601. function excelHasValidBills(importBillsData){
  602. for(let i in importBillsData){
  603. if(importBillsData[i].length > 0){
  604. return true;
  605. }
  606. }
  607. return false;
  608. }
  609. // 获取需要删除的D
  610. function getRemoveIDs(position, positionBills) {
  611. const rBillIDs = [];
  612. const rRationIDs = [];
  613. const rst = { rBillIDs, rRationIDs };
  614. if (!positionBills || !positionBills.length) {
  615. return rst;
  616. }
  617. let flag;
  618. if (position === 'fbfx') {
  619. flag = fixedFlag.SUB_ENGINERRING;
  620. } else if (position === 'jscsxm') {
  621. flag = fixedFlag.CONSTRUCTION_TECH;
  622. } else {
  623. flag = fixedFlag.CONSTRUCTION_ORGANIZATION;
  624. }
  625. const fixedNode = calcTools.getNodeByFlag(flag);
  626. if (!fixedNode) {
  627. return rst;
  628. }
  629. fixedNode.getPosterity().forEach(node => {
  630. if (node.sourceType === 'bills') {
  631. rBillIDs.push(node.data.ID);
  632. } else {
  633. rRationIDs.push(node.data.ID);
  634. }
  635. });
  636. return rst;
  637. }
  638. return {setImportSheetsInfo, getImportSheetsInfo, getImportSheets, getImportData, excelHasValidBills, getRemoveIDs}
  639. })();