chongqing_2018_export_sei.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /**
  2. * Created by zhang on 2019/5/20.
  3. */
  4. let exportUtil = {
  5. setEngineerPriceIndex:function (tender,projectData) {
  6. return gljUtil.getEngineerCostData(tender.property,projectData.bills,fixedFlag,scMathUtil);
  7. },
  8. getTotalFee:function (b) {
  9. return gljUtil.getTotalFee(b,scMathUtil);
  10. },
  11. getFlag: function (name,totalCost,engineerCost,buildingArea) {
  12. return gljUtil.getEngineerFlag(name,totalCost,engineerCost,buildingArea);
  13. },
  14. getBuildArea:function (features) {
  15. return gljUtil.getBuildArea(features)
  16. },
  17. calcUnitB:function (total,building,scMathUtil,coe,decimal = 3) {
  18. return gljUtil.calcUnitB(total,building,scMathUtil,coe,decimal)
  19. },
  20. calUnitWidthCoe:function (total,noNeedCoe) {
  21. return gljUtil.calUnitWidthCoe(total,noNeedCoe,projectObj.project.property.engineerFeatures,_,scMathUtil);
  22. },
  23. getIndexBills:function (bills) {
  24. return gljUtil.getIndexBills(bills,fixedFlag,_,scMathUtil);
  25. }
  26. };
  27. let SEIObject = {};
  28. async function selfChecking(projectID,exprotCall=false) {//自检和正式导出共用接口
  29. let pr = new SCComponent.InitProgressBar();
  30. if(!exprotCall) pr.start('导出数据接口', '正在自检,请稍候……');
  31. //先检查招投标数据 - todo
  32. //检查重庆指标接口数量
  33. if(_.isEmpty(SEIObject.errorMap)){
  34. let [errorMap,SEIFile] = await getSEIIndexFile(projectID);
  35. if(errorMap) {
  36. SEIObject.errorMap = errorMap;
  37. }else {
  38. SEIObject.fileCache.push(SEIFile);
  39. }
  40. }
  41. _.isEmpty(SEIObject.errorMap)?alert("自检完成,未检测到错误数据。"): showExportError(SEIObject.errorMap);
  42. SEIObject.selfChecked = true;
  43. if(!exprotCall) pr.end();
  44. }
  45. async function exportSEI(projectID){
  46. if(!_.isEmpty(SEIObject.errorMap)) return showExportError(SEIObject.errorMap);//如果自检的时候已经有错误,直接提示;
  47. let pr = new SCComponent.InitProgressBar();
  48. pr.start('导出数据接口', '正在导出文件,请稍候……');
  49. SEIObject.exporting = true;
  50. try {
  51. if(!SEIObject.selfChecked){//没有经过自检,则从招投标接口开始取数据
  52. await selfChecking(projectID,true);
  53. if(!_.isEmpty(SEIObject.errorMap)) return pr.end();
  54. }
  55. //导出建设项目数据
  56. //导出压缩包
  57. // saveZBFX(SEIObject.fileCache);
  58. }catch (e){
  59. console.log(e);
  60. }finally {
  61. pr.end();
  62. $('#exportCode').modal('show');
  63. //SEIObject.exporting = false;
  64. }
  65. async function saveZBFX(fileData) {
  66. let zip = new JSZip();
  67. for (let file of fileData) {
  68. zip.file(file.fileName, file.blob, {binary: true});
  69. }
  70. let zipFile = await zip.generateAsync({type: 'blob'});
  71. saveAs(zipFile, '经济指标.ZBFX');
  72. }
  73. }
  74. function showExportError(errorMap) {
  75. let infoList = [];
  76. for(let name in errorMap){
  77. infoList.push(`<span style="font-weight: bold">单位工程“${name}”下:</span>`);
  78. for(let err of errorMap[name]){
  79. infoList.push(err);
  80. }
  81. }
  82. if(infoList.length > 20){
  83. $('#hintBox_caption').addClass('export-check');
  84. }
  85. let msg = infoList.join(`<br>`);
  86. alert(msg);
  87. }
  88. async function getSEIIndexFile(projectID) {
  89. let tenderProjects = [];
  90. let errorMap = {};
  91. let result = await ajaxPost("/project/getSEIProjects",{projectID:projectID});
  92. let project = getProject(result);
  93. await prepareTenderDatas(tenderProjects,project);
  94. if(!_.isEmpty(errorMap)){
  95. return [errorMap,null];
  96. }
  97. let file = toXml(project);
  98. return [null,file];
  99. function getProject(orignal) {//取建设项目信息
  100. let basicInformation = getBaseInfo(orignal);
  101. let textTpye = orignal.property.taxType == 1 ?"一般计税":"简易计税";
  102. let project = {
  103. name: "建设项目",
  104. attrs: [
  105. {name: "项目名称", value: orignal.name},
  106. {name:"建设单位",value:getItemValueBykey(basicInformation.items,"constructionUnit")},
  107. {name:"施工单位",value:getItemValueBykey(basicInformation.items,"buildingUnit")},
  108. {name: "标准名称", value: "重庆市建设工程造价指标采集标准(清单计价)"},
  109. {name: "标准版本号", value: "1.1"},
  110. {name: "计税模式", value: textTpye}
  111. ],
  112. basicInformation:basicInformation,
  113. children:[]
  114. };
  115. initAtts(project.attrs);
  116. for(let c of orignal.children){
  117. project.children.push(getEngineering(c));
  118. }
  119. return project;
  120. }
  121. function getEngineering(source){
  122. let engineer = {
  123. name:"单项工程",
  124. attrs:[
  125. {name: "名称", value: source.name}
  126. ],
  127. children:[]
  128. };
  129. for(let c of source.children){
  130. let tenderProject = getTender(c);
  131. engineer.children.push(tenderProject);
  132. tenderProjects.push(tenderProject);
  133. }
  134. return engineer
  135. };
  136. function getTender(source) {
  137. let tender = {
  138. ID:source.ID,
  139. name:"单位工程",
  140. attrs:[
  141. {name: "名称", value: source.name}
  142. ],
  143. children:[],
  144. valuationType:source.property.valuationType,
  145. taxType:source.property.taxType,
  146. property:source.property,
  147. projectName:source.name
  148. };
  149. return tender;
  150. }
  151. async function prepareTenderDatas(tenders,project) {
  152. for(let t of tenders){
  153. await setTenderData(t,project);
  154. await setTimeoutSync(null,500);
  155. }
  156. }
  157. async function setTenderData(tender,project) {
  158. let projectData = await ajaxPost("/project/loadSEIProjectData",{projectID:tender.ID});
  159. tender.children.push(setEngineerInfo(tender));//设置工程信息
  160. tender.children.push(setEngineerFeature(tender));//设置工程特征
  161. tender.children.push(setEngineerIndex(tender,projectData));
  162. tender.children.push(await setGLJSummy(tender,projectData));
  163. //
  164. }
  165. function setEngineerIndex(tender,projectData) {//设置工程指标
  166. let index = {
  167. name:"工程指标",
  168. attrs:[],
  169. children:[],
  170. };
  171. let indexName = tender.property.indexName?tender.property.indexName:"建筑工程";
  172. index.children.push(exportUtil.setEngineerPriceIndex(tender,projectData));
  173. index.children.push(setEngineerEcoIndex(tender,projectData,indexName));
  174. index.children.push(setMainMaterialIndex(tender,projectData,indexName));
  175. index.children.push(setQuantityIndex(tender,projectData,indexName));
  176. return index;
  177. function setMainMaterialIndex(tender,projectData,indexName){
  178. let mainIndex = {
  179. name:`${indexName}工料指标`,
  180. attrs:[],
  181. children:[]
  182. };
  183. if(projectData) gljUtil.calcProjectGLJQuantity(projectData.projectGLJs,projectData.ration_gljs,projectData.rations,projectData.bills,getDecimal("glj.quantity"),_,scMathUtil);
  184. let materials = indexObj.getMainMaterialDatas(tender.property,tender.property.materials,projectData.projectGLJs,tender.property.calcOptions,tender.property.decimal,false,_,scMathUtil);
  185. for(let m of materials){
  186. if(m.name == "其他材料") continue;//2020-01-08 其他材料 不输出字段(不管是否有值)。
  187. mainIndex.children.push(getMaterial(m))
  188. }
  189. let index = {
  190. name:"主要工料价格及消耗量指标",
  191. attrs:[],
  192. children:[mainIndex]
  193. };
  194. return index;
  195. function getMaterial(m) {
  196. let mname = m.exportName?m.exportName:m.name;
  197. let material = {
  198. name:mname,
  199. attrs:[
  200. {name:"综合单价",value:scMathUtil.roundToString(m.unitPrice,2)},
  201. {name:"数量",value:scMathUtil.roundToString(m.quantity,2)},
  202. {name:"单方指标",value:scMathUtil.roundToString(m.unitIndex,3)},
  203. {name:"单位",value:m.unit}
  204. ]
  205. };
  206. return material;
  207. }
  208. }
  209. function setQuantityIndex(tender,projectData,indexName) {
  210. let quantityIndex = {
  211. name:`${indexName}量指标`,
  212. attrs:[],
  213. children:[]
  214. };
  215. let quantities = indexObj.getQuantityDatas(tender.property.mainQuantities,projectData.bills);
  216. for(let q of quantities){
  217. quantityIndex.children.push(getQuantity(q));
  218. }
  219. let index = {
  220. name:`主要工程量指标`,
  221. attrs:[],
  222. children:[quantityIndex]
  223. };
  224. return index;
  225. function getQuantity(q) {
  226. let qname = q.exportName?q.exportName:q.name;
  227. let quantity = {
  228. name:qname,
  229. attrs:[
  230. {name:"工程量指标",value:scMathUtil.roundToString(q.quantity,3)},
  231. {name:"单位",value:q.quantityIndexUnit}
  232. ]
  233. };
  234. return quantity;
  235. }
  236. }
  237. function setEngineerEcoIndex(tender,projectData,indexName) {
  238. let ecoIndex = {
  239. name:`${indexName}经济指标`,
  240. attrs:[],
  241. children:[]
  242. };
  243. let economicDatas = indexObj.getEconomicDatas(tender.property.economics,projectData.bills);
  244. for(let e of economicDatas){
  245. ecoIndex.children.push(getEco(e))
  246. }
  247. let index = {
  248. name:`工程经济指标`,
  249. attrs:[],
  250. children:[ecoIndex]
  251. };
  252. return index;
  253. function getEco(e) {
  254. let ename = e.exportName?e.exportName:e.name;
  255. let eco = {
  256. name:ename,
  257. attrs:[
  258. {name:"综合合价",value:scMathUtil.roundToString(e.cost,2)},
  259. {name:"单方指标",value:scMathUtil.roundToString(e.unitCost,2)},
  260. {name:"占造价比例",value:scMathUtil.roundToString(e.per,2)}
  261. ]
  262. };
  263. return eco;
  264. }
  265. }
  266. }
  267. async function setGLJSummy(tender,projectData) {
  268. let gljs = {
  269. name:"人材机汇总",
  270. attrs:[],
  271. children:[]
  272. };
  273. setGLJDetail(projectData,tender.property,gljs);
  274. return gljs;
  275. }
  276. function setGLJDetail(projectData,property,gljs) {
  277. if(projectData){
  278. gljUtil.calcProjectGLJQuantity(projectData.projectGLJs,projectData.ration_gljs,projectData.rations,projectData.bills,getDecimal("glj.quantity"),_,scMathUtil,true);
  279. }
  280. for(let g of projectData.projectGLJs.gljList) {
  281. if (!g.quantity || g.quantity == "") continue;
  282. let tenderCoe = gljUtil.getTenderPriceCoe(g,property);
  283. g.marketPrice = gljUtil.getMarketPrice(g,projectData.projectGLJs,property.calcOptions,property.decimal,false,_,scMathUtil,tenderCoe);
  284. gljs.children.push(setEachGLJ(g));
  285. }
  286. }
  287. function setEachGLJ(source){
  288. let g = {
  289. name:"人材机",
  290. attrs:[
  291. {name: "代码", value: source.code},
  292. {name: "名称", value: source.name},
  293. {name: "规格型号", value: source.specs},
  294. {name: "单位", value: source.unit},
  295. {name: "市场单价", value: source.marketPrice},
  296. {name: "数量", value: source.quantity},
  297. {name: "类型", value: source.type},
  298. {name: "产地", value: source.originPlace},
  299. {name: "厂家", value: source.vender},
  300. {name: "备注", value: source.remark}
  301. ]
  302. };
  303. handleXMLEntity(g.attrs);
  304. return g;
  305. }
  306. // 对每个元素的所有属性值进行特殊字符处理
  307. function handleXMLEntity(attrs) {
  308. let _xmlEntity = {
  309. '&': '&amp;',
  310. '\n': '&#xA;',
  311. '"': '&quot;',
  312. '\'': '&apos;',
  313. '<': '&lt;',
  314. '>': '&gt;'
  315. };
  316. for (let attr of attrs) {
  317. if (!attr.value) {
  318. continue;
  319. }
  320. for (let [key, value] of Object.entries(_xmlEntity)) {
  321. attr.value = attr.value+"";
  322. attr.value = attr.value.replace(new RegExp(key, 'g'), value);
  323. }
  324. }
  325. }
  326. function setEngineerInfo(tender) {//设置工程信息
  327. let infos = tender.property.engineerInfos?tender.property.engineerInfos:[];
  328. let errors = infoRequireChecking(infos);
  329. if(errors.length > 0) errorMap[tender.projectName] = errors;
  330. let info = {
  331. name:"工程信息",
  332. attrs:[
  333. {name:"造价编制单位",value:getItemValueByDispName(infos,"造价编制单位")},
  334. {name:"造价审核单位",value:getItemValueByDispName(infos,"造价审核单位")},
  335. {name:"项目负责人",value:getItemValueByDispName(infos,"项目负责人")},
  336. {name:"施工单位编制人员",value:getItemValueByDispName(infos,"施工单位编制人员")},
  337. {name:"编制人员",value:getItemValueByDispName(infos,"编制人员")},
  338. {name:"审核人员",value:getItemValueByDispName(infos,"审核人员")},
  339. {name:"开工日期",value:getItemValueByDispName(infos,"开工日期")},
  340. {name:"竣工日期",value:getItemValueByDispName(infos,"竣工日期")},
  341. {name:"工程地点",value:getItemValueByDispName(infos,"工程地点")},
  342. {name:"工程类型",value:getItemValueByDispName(infos,"工程类型")},
  343. {name:"合同价类型",value:getItemValueByDispName(infos,"合同价类型")},
  344. {name:"造价类型",value:getItemValueByDispName(infos,"造价类型")},
  345. {name:"计价方式及依据",value:getItemValueByDispName(infos,"计价方式及依据")},
  346. {name:"工程类别",value:getItemValueByDispName(infos,"工程类别")},
  347. {name:"编制日期",value:getItemValueByDispName(infos,"编制日期")},
  348. {name:"审查日期",value:getItemValueByDispName(infos,"审查日期"),required:false}
  349. ]
  350. };
  351. initAtts(info.attrs);
  352. return info;
  353. }
  354. function setEngineerFeature(tender) {
  355. let fea = {
  356. name:"工程特征",
  357. attrs:[],
  358. children:[]
  359. };
  360. fea.children.push(setIndexName(tender));
  361. return fea;
  362. function setIndexName(tender) {
  363. let indexName = {
  364. name:tender.property.indexName?tender.property.indexName:"建筑工程",
  365. attrs:[],
  366. children:[]
  367. };
  368. setFeatures(tender,indexName.children);
  369. return indexName
  370. }
  371. function setFeatures(tender,arr) {
  372. let features = tender.property.engineerFeatures?tender.property.engineerFeatures:[];
  373. if(features.length == 0) return;
  374. let parentMap = _.groupBy(features,"ParentID");
  375. let rootNodes = parentMap["-1"]?parentMap["-1"]:parentMap[null];
  376. for(let r of rootNodes){
  377. arr.push(getFeatrue(r,parentMap))
  378. }
  379. }
  380. function getFeatrue(node,parentMap){
  381. let name = node.exportName?node.exportName:node.name;
  382. if(parentMap[node.ID]){//如果有子节点,那么它就是一个节点
  383. let tem = {
  384. name:name.replace("*",""),
  385. attrs:[],
  386. children:[]
  387. };
  388. for(let s of parentMap[node.ID]){
  389. let f = getFeatrue(s,parentMap);
  390. f.children?tem.children.push(f):tem.attrs.push(f);//如果有children这个属性,则返回的是一个节点,如果没有,则返回的是一个属性
  391. }
  392. return tem;
  393. }else {//如果没有子节点,那么它就是父节点的一个属性
  394. if(node.isDetail == true){//如果是明细节点,则造一个明细节点
  395. return {name:"明细",attrs:[{name:"名称",value:getValue(node)}],children:[]};
  396. }
  397. return {name:name.replace("*",""),value:getValue(node)};
  398. }
  399. }
  400. function getValue(node) {
  401. let value = node.value;
  402. if(node.required == true || node.cellType == "number"){//必填项的值为空时导出0
  403. if(value == undefined || value == null || value == "") value = "0";
  404. }
  405. return value;
  406. }
  407. }
  408. function getBaseInfo(project){
  409. let basicInformation = {items:[]};
  410. let tem = null;
  411. if(project.property&&project.property.basicInformation) tem =_.find(project.property.basicInformation,{"key":"basicInfo"});
  412. if(tem) basicInformation = tem;
  413. return basicInformation;
  414. }
  415. function infoRequireChecking(items) {
  416. let error = [];
  417. for(let i of items){
  418. if(i.required == true && _.isEmpty(i.value)) error.push(`工程信息 - ${i.dispName}不能为空。`);
  419. }
  420. return error;
  421. }
  422. function getItemValueBykey(items,key) {
  423. let item = _.find(items,{"key":key});
  424. if(item) return item.value;
  425. return ""
  426. }
  427. function getItemValueByDispName(items,dispName) {
  428. let item = _.find(items,{"dispName":dispName});
  429. if(item){
  430. return item.value;
  431. }
  432. return ""
  433. }
  434. function initAtts(arrs) {
  435. _.remove(arrs,function (item) {
  436. return item.required == false && _.isEmpty(item.value)
  437. })
  438. }
  439. //开始标签
  440. function startTag(ele) {
  441. let rst = `<${ele.name}`;
  442. for (let attr of ele.attrs) {
  443. rst += ` ${attr.name}="${ attr.value!=undefined&&attr.value!= null?attr.value:""}"`;
  444. }
  445. rst += ele.children&&ele.children.length > 0 ? '>' : '/>';
  446. return rst;
  447. }
  448. //结束标签
  449. function endTag(ele) {
  450. return `</${ele.name}>`;
  451. }
  452. //拼接成xml字符串
  453. function toXMLStr(eles) {
  454. let rst = '';
  455. for (let ele of eles) {
  456. rst += startTag(ele);
  457. if (ele.children&& ele.children.length > 0) {
  458. rst += toXMLStr(ele.children);
  459. rst += endTag(ele);
  460. }
  461. }
  462. return rst;
  463. }
  464. //格式化xml字符串
  465. function formatXml(text) {
  466. //去掉多余的空格
  467. text = '\n' + text.replace(/>\s*?</g, ">\n<");
  468. //调整格式
  469. let rgx = /\n(<(([^\?]).+?)(?:\s|\s*?>|\s*?(\/)>)(?:.*?(?:(?:(\/)>)|(?:<(\/)\2>)))?)/mg;
  470. let nodeStack = [];
  471. let output = text.replace(rgx, function($0, all, name, isBegin, isCloseFull1, isCloseFull2, isFull1, isFull2){
  472. let isClosed = (isCloseFull1 === '/') || (isCloseFull2 === '/' ) || (isFull1 === '/') || (isFull2 === '/');
  473. let prefix = '';
  474. if (isBegin === '!') {
  475. prefix = getPrefix(nodeStack.length);
  476. } else {
  477. if (isBegin !== '/') {
  478. prefix = getPrefix(nodeStack.length);
  479. if (!isClosed) {
  480. nodeStack.push(name);
  481. }
  482. } else {
  483. nodeStack.pop();
  484. prefix = getPrefix(nodeStack.length);
  485. }
  486. }
  487. let ret = '\n' + prefix + all;
  488. return ret;
  489. });
  490. let outputText = output.substring(1);
  491. return outputText;
  492. function getPrefix(prefixIndex) {
  493. let span = ' ';
  494. let output = [];
  495. for (let i = 0 ; i < prefixIndex; ++i) {
  496. output.push(span);
  497. }
  498. return output.join('');
  499. }
  500. }
  501. /*
  502. * 导出数据
  503. * @param {Number}tenderID(当前界面的单位工程ID,后台根据这个单位工程,根据导出粒度去找其建设项目下相关数据)
  504. * @return {void}
  505. * */
  506. function toXml(eleData) {
  507. //转换成xml字符串
  508. let xmlStr = toXMLStr([eleData]);
  509. //加上xml声明
  510. xmlStr = `<?xml version="1.0" encoding="utf-8"?>${xmlStr}`;
  511. //格式化
  512. xmlStr = formatXml(xmlStr);
  513. let blob = new Blob([xmlStr], {type: 'text/plain;charset=utf-8'});
  514. return {
  515. blob: blob,
  516. fileName: "经济指标.ZBF"
  517. };
  518. //saveAs(blob, '经济指标.ZBF');
  519. }
  520. }
  521. $(function () {
  522. $("#export-index-check").click( function (){
  523. selfChecking(projectObj.project.property.rootProjectID);
  524. });
  525. $("#export-index-confirm").click(async function (){
  526. await exportSEI(projectObj.project.property.rootProjectID);
  527. // $("#exportIndex").modal("hide");
  528. });
  529. $('#exportIndex').on('hide.bs.modal', function() {
  530. SEIObject = {
  531. exporting:false,
  532. fileCache:[],
  533. errorMap:{},
  534. selfChecked:false
  535. }
  536. })
  537. });