match.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Mai
  6. * @date 2018/4/25
  7. * @version
  8. */
  9. const Service = require('egg').Service;
  10. const paramConst = require('../const/template_param');
  11. const nodeConst = require('../const/template_node');
  12. module.exports = app => {
  13. class Match extends Service {
  14. /**
  15. * 初始化匹配所需变量
  16. * @param {Array|Object} bills - 导入的清单数据
  17. * @private
  18. */
  19. _init(bills) {
  20. this.bills = bills instanceof Array ? bills : [bills];
  21. this.bills[0].match_node = null;
  22. this.fixedBills = this.bills.filter(function (b) {
  23. return b.n_id < 100;
  24. });
  25. this.nodes = [];
  26. this.indexes = [];
  27. this.params = [];
  28. }
  29. /**
  30. * 获取指标模板数据
  31. * @param {Number} templateId - 指标模板Id
  32. * @returns {Promise<void>}
  33. * @private
  34. */
  35. async _getTemplateData (templateId) {
  36. this.templateNodes = await this.ctx.service.templateNode.getAllDataByCondition({ template_id: templateId });
  37. this.templateIndexes = await this.ctx.service.templateIndex.getAllDataByCondition({ template_id: templateId });
  38. this.templateParams = await this.ctx.service.templateParam.getAllDataByCondition({ template_id: templateId });
  39. }
  40. /**
  41. * 检查code是否满足匹配规则rule
  42. * @param {String} code - 匹配编号
  43. * @param {String} rule - 匹配规则
  44. * @returns {boolean}
  45. * @private
  46. */
  47. _matchCode(code, rule) {
  48. const codeParts = code.split('-');
  49. const ruleParts = rule.split('-');
  50. const numReg = /(^[0-9]+$)/;
  51. if (codeParts.length !== ruleParts.length) { return false; }
  52. for (let i = 0, iLen = codeParts.length; i < iLen; i++) {
  53. if (numReg.test(ruleParts[i]) && ruleParts[i] !== codeParts[i]) {
  54. return false;
  55. }
  56. }
  57. return true;
  58. }
  59. /**
  60. * 过滤符合指标节点node匹配规则的清单
  61. * 已经匹配过的清单不再匹配
  62. *
  63. * @param {Object} node - 指标节点
  64. * @private
  65. */
  66. _filterBills (node) {
  67. const self = this;
  68. return this.bills.filter(function (b) {
  69. if (!b.match_node) {
  70. if (node.match_type === nodeConst.matchType.code) {
  71. return self._matchCode(b.code, node.match_key);
  72. } else {
  73. return node.match_key === b.name;
  74. }
  75. } else {
  76. return false;
  77. }
  78. })
  79. }
  80. /**
  81. * 根据指标参数取值类别,从清单取值
  82. *
  83. * @param {Object} param - 指标参数
  84. * @param {Object} bills - 清单节点
  85. * @returns {number}
  86. * @private
  87. */
  88. _getNodeBillsValue(param, bills) {
  89. switch (param.match_num) {
  90. case paramConst.matchNum.quantity: return bills.quantity;
  91. case paramConst.matchNum.total_price: return bills.total_price;
  92. case paramConst.matchNum.dgn_quantity1: return bills.dgn_quantity1;
  93. case paramConst.matchNum.dgn_quantity2: return bills.dgn_quantity2;
  94. }
  95. }
  96. /**
  97. * 获取指标参数取值(固定Id匹配)
  98. * @param {Object} param - 指标参数
  99. * @returns {*}
  100. * @private
  101. */
  102. _getFixedIdParamValue(param) {
  103. for (const b of this.fixedBills) {
  104. if (b.n_id == param.match_key) {
  105. return this._getNodeBillsValue(param, b);
  106. }
  107. }
  108. return undefined;
  109. }
  110. /**
  111. * 获取指标参数取值(编号匹配)
  112. * @param param
  113. * @param nodeBills
  114. * @returns {*}
  115. * @private
  116. */
  117. _getCodeParamValue(param) {
  118. for (const b of this.bills) {
  119. if (this._matchCode(b.code, param.match_key)) {
  120. return this._getNodeBillsValue(param, b);
  121. }
  122. }
  123. return undefined;
  124. }
  125. /**
  126. * 获取指标参数取值
  127. * @param {Object} param - 指标参数
  128. * @param {Object} nodeBills - 指标参数 所属 指标节点,绑定的 清单
  129. * @returns {*}
  130. * @private
  131. */
  132. _getParamValue(param, nodeBills) {
  133. switch (param.match_type) {
  134. case paramConst.matchType.fixed_id: return this._getFixedIdParamValue(param);
  135. case paramConst.matchType.node_default: return this._getNodeBillsValue(param, nodeBills);
  136. case paramConst.matchType.code: return this._getCodeParamValue(param);
  137. // to do 匹配属性
  138. default: return undefined;
  139. }
  140. }
  141. /**
  142. * 同步指标节点下的全部指标参数
  143. * @param {Number} nodeId
  144. * @private
  145. */
  146. _syncNodeParam(sourceId, nodeId, nodeBills) {
  147. const nodeParams = this.templateParams.filter(function (p) {
  148. return p.node_id === sourceId;
  149. });
  150. for (const np of nodeParams) {
  151. const newParam = {
  152. node_id: nodeId,
  153. lib_id: nodeBills.lib_id,
  154. param_id: this.params.length + 1,
  155. source_id: np.param_id,
  156. code: np.code,
  157. name: np.name,
  158. match_type: np.match_type,
  159. match_key: np.match_key,
  160. match_num: np.match_num,
  161. }
  162. newParam.match_value = this._getParamValue(newParam, nodeBills);
  163. newParam.calc_value = newParam.match_value;
  164. this.params.push(newParam);
  165. }
  166. }
  167. /**
  168. * 同步指标节点下的全部指标
  169. * @param {Number} nodeId
  170. * @private
  171. */
  172. _syncNodeIndex(node) {
  173. const nodeIndexes = this.templateIndexes.filter(function (i) {
  174. return i.node_id === node.source_id;
  175. });
  176. for (const ni of nodeIndexes) {
  177. const newIndex = {
  178. node_id: node.node_id,
  179. lib_id: node.lib_id,
  180. index_id: this.indexes.length + 1,
  181. source_id: ni.index_id,
  182. code: ni.code,
  183. name: ni.name,
  184. unit1: ni.unit1,
  185. unit2: ni.unit2,
  186. rule: ni.rule,
  187. calc_rule: ni.calc_rule,
  188. parse_rule: ni.parse_rule,
  189. index_type: ni.index_type,
  190. }
  191. this.indexes.push(newIndex);
  192. }
  193. }
  194. /**
  195. * 匹配指标节点
  196. * @param node
  197. * @private
  198. */
  199. _matchNode(node) {
  200. if (!node) { return; }
  201. const matchedBills = this._filterBills(node);
  202. for (const mb of matchedBills) {
  203. const newNode = {
  204. node_id: this.nodes.length + 1,
  205. lib_id: mb.lib_id,
  206. source_id: node.node_id,
  207. code: node.code,
  208. name: node.name,
  209. match_type: node.match_type,
  210. match_key: node.match_key,
  211. bills_id: mb.n_id,
  212. }
  213. this.nodes.push(newNode);
  214. this._syncNodeParam(newNode.source_id, newNode.node_id, mb);
  215. this._syncNodeIndex(newNode);
  216. mb.match_node = newNode.node_id;
  217. }
  218. }
  219. /**
  220. *
  221. * @param bills
  222. * @returns {Promise<void>}
  223. */
  224. async matchBills (bills) {
  225. this._init(bills);
  226. // 获取指标模板全部数据
  227. await this._getTemplateData(1);
  228. // 同步全局指标参数
  229. this._syncNodeParam(paramConst.globalParamNodeId, paramConst.globalParamNodeId, this.bills[0]);
  230. // 遍历模板中所有指标节点,匹配清单
  231. for (const node of this.templateNodes) {
  232. this._matchNode(node);
  233. }
  234. // 计算全部指标节点
  235. const globalParams = this.params.filter(function (p) {
  236. return p.node_id === 0;
  237. });
  238. for (const node of this.nodes) {
  239. const nodeParams = this.params.filter(function (p) {
  240. return p.node_id === node.node_id;
  241. });
  242. const nodeIndexes = this.indexes.filter(function (i) {
  243. return i.node_id === node.node_id;
  244. });
  245. this.ctx.service.indexCalc.calculate(nodeIndexes, globalParams, nodeParams);
  246. }
  247. }
  248. };
  249. return Match;
  250. }