matchSign.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. 'use strict';
  2. const { CrudService } = require('naf-framework-mongoose-free/lib/service');
  3. const { BusinessError, ErrorCode } = require('naf-core').Error;
  4. const _ = require('lodash');
  5. const assert = require('assert');
  6. //
  7. class MatchSignService extends CrudService {
  8. constructor(ctx) {
  9. super(ctx, 'matchsign');
  10. this.model = this.ctx.model.Race.MatchSign;
  11. this.matchModel = this.ctx.model.Race.Match;
  12. this.matchGroupModel = this.ctx.model.Race.MatchGroup;
  13. this.matchProjectModel = this.ctx.model.Race.MatchProject;
  14. }
  15. /**
  16. * 检查是否已经有该赛事,该组别,该项目的报名
  17. * @param {Object} body 参数体
  18. */
  19. async beforeCreate(body) {
  20. await this.checkHas(body);
  21. return body;
  22. }
  23. /**
  24. * 检查有没有报过名
  25. * @param {Object} body 参数体
  26. * @return {Boolean} true 可以继续进行
  27. */
  28. async checkHas(body) {
  29. const { match_id, group_id, project_id, user_id } = body;
  30. const query = { match_id, group_id, project_id, user_id, pay_status: [ '0', '1' ] };
  31. const num = await this.model.query(query);
  32. if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '您已报名');
  33. return true;
  34. }
  35. async checkFit(body) {
  36. const { match_id, group_id, project_id, user_id, card = '22010319950601161X' } = body;
  37. await this.checkHas(body);
  38. const { pass, msg, gender: cardGender, age: cardAge } = this.idCodeValid(card);
  39. if (!pass) throw new BusinessError(ErrorCode.SERVICE_FAULT, msg);
  40. // 1.看 match 状态 是否为报名中
  41. const mnum = await this.matchModel.count({ _id: match_id, status: '1' });
  42. if (mnum <= 0) throw new BusinessError(ErrorCode.DATA_INVALID, '当前赛事不处于报名期');
  43. // 2.看matchGroup 年龄限制是否符合要求
  44. const matchGroup = await this.matchGroupModel.findById(group_id);
  45. if (!matchGroup) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到当前组别');
  46. const { age } = matchGroup;
  47. let next = this.checkAgeInRange(age, cardAge);
  48. // 3.看 matchProject 年龄限制和性别限制,人数限制
  49. if (!next) throw new BusinessError(ErrorCode.DATA_INVALID, '年龄不符合组别条件');
  50. const matchProject = await this.matchProjectModel.findById(project_id);
  51. if (!matchProject) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到组别项目');
  52. const { age: projectAge, gender } = matchProject;
  53. next = this.checkAgeInRange(projectAge, cardAge);
  54. if (!next) throw new BusinessError(ErrorCode.DATA_INVALID, '年龄不符合组别项目条件');
  55. if (gender !== '2') {
  56. if (gender !== cardGender) throw new BusinessError(ErrorCode.DATA_INVALID, '性别不符合组别条件');
  57. }
  58. return true;
  59. }
  60. checkAgeInRange(age, cardAge) {
  61. let next = true;
  62. if (_.isString(age) && age.indexOf('-') > -1) {
  63. const arr = age.split('-');
  64. console.log(arr);
  65. const start = parseInt(_.head(arr));
  66. const end = parseInt(_.last(arr));
  67. // inRange 是左闭右开区间,所以加1,形成闭区间
  68. const r = _.inRange(cardAge, start, end + 1);
  69. next = r;
  70. } else if (!age || age === '不限') next = true;
  71. return next;
  72. }
  73. // 身份证验证
  74. idCodeValid(code) {
  75. // 身份证号合法性验证
  76. // 支持15位和18位身份证号
  77. // 支持地址编码、出生日期、校验位验证
  78. const city = {
  79. 11: '北京',
  80. 12: '天津',
  81. 13: '河北',
  82. 14: '山西',
  83. 15: '内蒙古',
  84. 21: '辽宁',
  85. 22: '吉林',
  86. 23: '黑龙江 ',
  87. 31: '上海',
  88. 32: '江苏',
  89. 33: '浙江',
  90. 34: '安徽',
  91. 35: '福建',
  92. 36: '江西',
  93. 37: '山东',
  94. 41: '河南',
  95. 42: '湖北 ',
  96. 43: '湖南',
  97. 44: '广东',
  98. 45: '广西',
  99. 46: '海南',
  100. 50: '重庆',
  101. 51: '四川',
  102. 52: '贵州',
  103. 53: '云南',
  104. 54: '西藏 ',
  105. 61: '陕西',
  106. 62: '甘肃',
  107. 63: '青海',
  108. 64: '宁夏',
  109. 65: '新疆',
  110. 71: '台湾',
  111. 81: '香港',
  112. 82: '澳门',
  113. 91: '国外 ',
  114. };
  115. let row = {
  116. pass: true,
  117. msg: '验证成功',
  118. };
  119. if (!code || !/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|[xX])$/.test(code)) {
  120. row = {
  121. pass: false,
  122. msg: '身份证号格式错误',
  123. };
  124. } else if (!city[code.substr(0, 2)]) {
  125. row = {
  126. pass: false,
  127. msg: '身份证号地址编码错误',
  128. };
  129. } else {
  130. // 18位身份证需要验证最后一位校验位
  131. if (code.length === 18) {
  132. code = code.split('');
  133. // ∑(ai×Wi)(mod 11)
  134. // 加权因子
  135. const factor = [ 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 ];
  136. // 校验位
  137. const parity = [ 1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2 ];
  138. let sum = 0;
  139. let ai = 0;
  140. let wi = 0;
  141. for (let i = 0; i < 17; i++) {
  142. ai = code[i];
  143. wi = factor[i];
  144. sum += ai * wi;
  145. }
  146. if (parity[sum % 11] !== code[17].toUpperCase()) {
  147. row = {
  148. pass: false,
  149. msg: '身份证号校验位错误',
  150. };
  151. }
  152. }
  153. }
  154. if (row.pass) {
  155. row.gender = this.maleOrFemalByIdCard(code);
  156. row.age = this.getAge(code);
  157. }
  158. return row;
  159. }
  160. // 性别
  161. maleOrFemalByIdCard(idCard) {
  162. if (_.isArray) idCard = idCard.join('');
  163. idCard = _.trim(idCard.replace(/ /g, '')); // 对身份证号码做处理。包括字符间有空格。
  164. if (idCard.length === 15) {
  165. if (idCard.substring(14, 15) % 2 === 0) {
  166. return '1';
  167. }
  168. return '0';
  169. } else if (idCard.length === 18) {
  170. if (idCard.substring(14, 17) % 2 === 0) {
  171. return '1';
  172. }
  173. return '0';
  174. }
  175. return null;
  176. }
  177. // 年龄
  178. getAge(idCard) {
  179. if (_.isArray) idCard = idCard.join('');
  180. const ageDate = new Date();
  181. const month = ageDate.getMonth() + 1;
  182. const day = ageDate.getDate();
  183. let age = ageDate.getFullYear() - idCard.substring(6, 10) - 1;
  184. if (idCard.substring(10, 12) < month || (idCard.substring(10, 12) === month && idCard.substring(12, 14) <= day)) {
  185. age++;
  186. }
  187. if (age <= 0) {
  188. age = 1;
  189. }
  190. return age;
  191. }
  192. }
  193. module.exports = MatchSignService;