template_node.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. 'use strict';
  2. /**
  3. * 指标节点业务类
  4. *
  5. * @author Mai
  6. * @date 2018/4/19
  7. * @version
  8. */
  9. const paramCode = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
  10. 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'aa', 'ab', 'ac', 'ad', 'ae', 'af',
  11. 'ag', 'ah', 'ai', 'aj', 'ak', 'al', 'am', 'an', 'ao', 'ap', 'aq', 'ar', 'as', 'at', 'au',
  12. 'av', 'aw', 'ax', 'ay', 'az'];
  13. const defaultGlobalParams = [
  14. {
  15. template_id: 1,
  16. node_id: 0,
  17. param_id: 1,
  18. code: 'g_a',
  19. name: '公路基本造价',
  20. },{
  21. template_id: 1,
  22. node_id: 0,
  23. param_id: 2,
  24. code: 'g_b',
  25. name: '建安费',
  26. },{
  27. template_id: 1,
  28. node_id: 0,
  29. param_id: 3,
  30. code: 'g_c',
  31. name: '工程建设其他费用',
  32. },{
  33. template_id: 1,
  34. node_id: 0,
  35. param_id: 4,
  36. code: 'g_d',
  37. name: '路线总长度(主线长度)',
  38. },{
  39. template_id: 1,
  40. node_id: 0,
  41. param_id: 5,
  42. code: 'g_e',
  43. name: '建筑总面积{路线总长度(主线长度)×路基(或桥隧)宽度}',
  44. },{
  45. template_id: 1,
  46. node_id: 0,
  47. param_id: 6,
  48. code: 'g_f',
  49. name: '路基长度(指不含桥梁、隧道的路基长度(双幅平均计))',
  50. },
  51. ];
  52. module.exports = app => {
  53. class TemplateNode extends app.BaseService {
  54. /**
  55. * 构造函数
  56. *
  57. * @param {Object} ctx - egg全局context
  58. * @return {void}
  59. */
  60. constructor(ctx) {
  61. super(ctx);
  62. this.tableName = 'template_node';
  63. }
  64. /**
  65. * 从计算规则中解析出指标参数
  66. * @param {String} rule - 指标规则
  67. * @param {Number} nodeId - 指标节点id
  68. * @param {Array} params - 参数列表
  69. * @returns {*[]}
  70. * @private
  71. */
  72. _parseParam(rule, nodeId, params) {
  73. if (rule === '') { return; }
  74. const self = this;
  75. const ruleParams = rule.split('/');
  76. const nodeParams = params.filter(function (p) {
  77. return p.node_id === nodeId;
  78. });
  79. const addParam = function (paramName) {
  80. if (paramName === '') { return ''; }
  81. let param = self.ctx.helper.findObj(defaultGlobalParams, 'name', paramName);
  82. if (!param) {
  83. param = self.ctx.helper.findObj(nodeParams, 'name', paramName);
  84. }
  85. if (!param) {
  86. const newParam = {
  87. template_id: 1,
  88. node_id: nodeId,
  89. param_id: nodeParams.length + 1,
  90. code: paramCode[nodeParams.length],
  91. name: paramName,
  92. };
  93. nodeParams.push(newParam);
  94. params.push(newParam);
  95. return newParam.code;
  96. } else {
  97. return param.code;
  98. }
  99. }
  100. if (ruleParams.length > 1) {
  101. const paramName1 = ruleParams[0];
  102. const paramCode1 = addParam(paramName1);
  103. const paramName2 = ruleParams.slice(1, ruleParams.length).join('/');
  104. const paramCode2 = addParam(paramName2);
  105. return [paramCode1 + '/' + paramCode2,
  106. paramCode1 + '(' + paramName1 + ')' + '/' + paramCode2 + '(' + paramName2 + ')'];
  107. } else {
  108. const paramCode = addParam(rule);
  109. return [paramCode, paramCode + '(' + rule + ')'];
  110. }
  111. }
  112. /**
  113. * 查找父节点(根据编号),忽略大小写
  114. * e.g. z1(z), z1-e(z1), z1-e-a(z1-e)
  115. * @param code
  116. * @param nodes
  117. * @returns {*}
  118. * @private
  119. */
  120. _findParentId(code, nodes) {
  121. if (nodes.length === 0) { return -1; }
  122. const codeList = code.split('-');
  123. if (codeList.length > 1) {
  124. codeList.splice(codeList.length - 1);
  125. const parentCode = codeList.join('-');
  126. for (const node of nodes) {
  127. if (parentCode.toLowerCase() === node.code.toLowerCase()) {
  128. return node.node_id;
  129. }
  130. }
  131. } else {
  132. for (const node of nodes) {
  133. if (code.toLowerCase().search(node.code.toLowerCase()) === 0) {
  134. return node.node_id;
  135. }
  136. }
  137. }
  138. }
  139. /**
  140. * 解析一个Excel工作表内的全部 指标节点 和 指标
  141. * @param {Object} excelSheet
  142. * @param {Array} nodes - 解析后的指标节点
  143. * @param {Array} indexes - 解析后的指标
  144. * @private
  145. */
  146. _parseSheetData(excelSheet, nodes, indexes, params) {
  147. for (const row of excelSheet.data) {
  148. if (!row[0]) { continue; }
  149. if (this.ctx.helper.ValidTemplateNodeCode(row[0])) {
  150. if (!this.ctx.helper.findObj(nodes, 'code', row[0])) {
  151. const node = {
  152. template_id: 1,
  153. node_id: nodes.length + 1,
  154. node_pid: this._findParentId(row[0], nodes) || -1,
  155. code: row[0],
  156. name: row[1],
  157. };
  158. nodes.push(node);
  159. }
  160. } else if (this.ctx.helper.ValidTemplateIndexCode(row[0])) {
  161. const index = {
  162. code: row[0],
  163. name: row[1],
  164. unit1: row[2],
  165. unit2: row[3],
  166. node_id: nodes.length,
  167. index_id: indexes.length + 1,
  168. rule: row[9]
  169. };
  170. if (row[4] === '√') {
  171. index.index_type = 1;
  172. } else if (row[5] === '√') {
  173. index.index_type = 2;
  174. } else if (row[6] === '√') {
  175. index.index_type = 3;
  176. } else if (row[7] === '√') {
  177. index.index_type = 4;
  178. }
  179. [index.calc_rule, index.parse_rule] = this._parseParam(index.rule, index.node_id, params);
  180. indexes.push(index);
  181. }
  182. }
  183. }
  184. /**
  185. * 导入Excel数据
  186. *
  187. * @param {Array} excelSheets - Excel文件中的全部工作表
  188. * @returns {Promise<boolean>}
  189. */
  190. async importData(excelSheets) {
  191. let result = false;
  192. const limit = 30000;
  193. const transaction = await this.db.beginTransaction();
  194. try {
  195. const nodes = [], indexes = [], params = [];
  196. for (const sheet of excelSheets) {
  197. this._parseSheetData(sheet, nodes, indexes, params);
  198. }
  199. if (nodes.length > 0) {
  200. await transaction.delete(this.tableName, {template_id: 1});
  201. const insertResult = await transaction.insert(this.tableName, nodes);
  202. if (insertResult.affectedRows !== nodes.length) {
  203. throw '导入指标节点错误';
  204. }
  205. await this.ctx.service.templateIndex.importData(indexes, transaction);
  206. await this.ctx.service.templateParam.importData(params.concat(defaultGlobalParams), transaction);
  207. } else {
  208. throw 'Excel文件中无标准的指标数据';
  209. }
  210. await transaction.commit();
  211. result = true;
  212. } catch(err) {
  213. await transaction.rollback();
  214. throw err;
  215. }
  216. return result;
  217. }
  218. }
  219. return TemplateNode;
  220. };