match.js 8.8 KB

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