|
@@ -9,14 +9,193 @@ class MatchSignService extends CrudService {
|
|
|
constructor(ctx) {
|
|
|
super(ctx, 'matchsign');
|
|
|
this.model = this.ctx.model.Race.MatchSign;
|
|
|
+ this.matchModel = this.ctx.model.Race.Match;
|
|
|
+ this.matchGroupModel = this.ctx.model.Race.MatchGroup;
|
|
|
+ this.matchProjectModel = this.ctx.model.Race.MatchProject;
|
|
|
}
|
|
|
/**
|
|
|
* 检查是否已经有该赛事,该组别,该项目的报名
|
|
|
* @param {Object} body 参数体
|
|
|
*/
|
|
|
async beforeCreate(body) {
|
|
|
+ await this.checkHas(body);
|
|
|
return body;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查有没有报过名
|
|
|
+ * @param {Object} body 参数体
|
|
|
+ * @return {Boolean} true 可以继续进行
|
|
|
+ */
|
|
|
+ async checkHas(body) {
|
|
|
+ const { match_id, group_id, project_id, user_id } = body;
|
|
|
+ const query = { match_id, group_id, project_id, user_id, pay_status: [ '0', '1' ] };
|
|
|
+ const num = await this.model.query(query);
|
|
|
+ if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '您已报名');
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ async checkFit(body) {
|
|
|
+ const { match_id, group_id, project_id, user_id, card = '22010319950601161X' } = body;
|
|
|
+ const { pass, msg, gender: cardGender, age: cardAge } = this.idCodeValid(card);
|
|
|
+ if (!pass) throw new BusinessError(ErrorCode.SERVICE_FAULT, msg);
|
|
|
+ // 1.看 match 状态 是否为报名中
|
|
|
+ const mnum = await this.matchModel.count({ _id: match_id, status: '1' });
|
|
|
+ if (mnum <= 0) throw new BusinessError(ErrorCode.DATA_INVALID, '当前赛事不处于报名期');
|
|
|
+ // 2.看matchGroup 年龄限制是否符合要求
|
|
|
+ const matchGroup = await this.matchGroupModel.findById(group_id);
|
|
|
+ if (!matchGroup) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到当前组别');
|
|
|
+ const { age } = matchGroup;
|
|
|
+ let next = this.checkAgeInRange(age, cardAge);
|
|
|
+ // 3.看 matchProject 年龄限制和性别限制,人数限制
|
|
|
+ if (!next) throw new BusinessError(ErrorCode.DATA_INVALID, '年龄不符合组别条件');
|
|
|
+ const matchProject = await this.matchProjectModel.findById(project_id);
|
|
|
+ if (!matchProject) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到组别项目');
|
|
|
+ const { age: projectAge, gender } = matchProject;
|
|
|
+ next = this.checkAgeInRange(projectAge, cardAge);
|
|
|
+ if (!next) throw new BusinessError(ErrorCode.DATA_INVALID, '年龄不符合组别项目条件');
|
|
|
+ if (gender !== '2') {
|
|
|
+ if (gender !== cardGender) throw new BusinessError(ErrorCode.DATA_INVALID, '性别不符合组别条件');
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ checkAgeInRange(age, cardAge) {
|
|
|
+ let next = true;
|
|
|
+ if (_.isString(age) && age.include('-')) {
|
|
|
+ const arr = age.split('-');
|
|
|
+ const start = parseInt(_.head(arr));
|
|
|
+ const end = parseInt(_.last(arr));
|
|
|
+ // inRange 是左闭右开区间,所以加1,形成闭区间
|
|
|
+ const r = _.inRange(cardAge, start, end + 1);
|
|
|
+ next = r;
|
|
|
+ } else if (!age || age === '不限') next = true;
|
|
|
+ return next;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 身份证验证
|
|
|
+ idCodeValid(code) {
|
|
|
+ // 身份证号合法性验证
|
|
|
+ // 支持15位和18位身份证号
|
|
|
+ // 支持地址编码、出生日期、校验位验证
|
|
|
+ const city = {
|
|
|
+ 11: '北京',
|
|
|
+ 12: '天津',
|
|
|
+ 13: '河北',
|
|
|
+ 14: '山西',
|
|
|
+ 15: '内蒙古',
|
|
|
+ 21: '辽宁',
|
|
|
+ 22: '吉林',
|
|
|
+ 23: '黑龙江 ',
|
|
|
+ 31: '上海',
|
|
|
+ 32: '江苏',
|
|
|
+ 33: '浙江',
|
|
|
+ 34: '安徽',
|
|
|
+ 35: '福建',
|
|
|
+ 36: '江西',
|
|
|
+ 37: '山东',
|
|
|
+ 41: '河南',
|
|
|
+ 42: '湖北 ',
|
|
|
+ 43: '湖南',
|
|
|
+ 44: '广东',
|
|
|
+ 45: '广西',
|
|
|
+ 46: '海南',
|
|
|
+ 50: '重庆',
|
|
|
+ 51: '四川',
|
|
|
+ 52: '贵州',
|
|
|
+ 53: '云南',
|
|
|
+ 54: '西藏 ',
|
|
|
+ 61: '陕西',
|
|
|
+ 62: '甘肃',
|
|
|
+ 63: '青海',
|
|
|
+ 64: '宁夏',
|
|
|
+ 65: '新疆',
|
|
|
+ 71: '台湾',
|
|
|
+ 81: '香港',
|
|
|
+ 82: '澳门',
|
|
|
+ 91: '国外 ',
|
|
|
+ };
|
|
|
+ let row = {
|
|
|
+ pass: true,
|
|
|
+ msg: '验证成功',
|
|
|
+ };
|
|
|
+ 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)) {
|
|
|
+ row = {
|
|
|
+ pass: false,
|
|
|
+ msg: '身份证号格式错误',
|
|
|
+ };
|
|
|
+ } else if (!city[code.substr(0, 2)]) {
|
|
|
+ row = {
|
|
|
+ pass: false,
|
|
|
+ msg: '身份证号地址编码错误',
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ // 18位身份证需要验证最后一位校验位
|
|
|
+ if (code.length === 18) {
|
|
|
+ code = code.split('');
|
|
|
+ // ∑(ai×Wi)(mod 11)
|
|
|
+ // 加权因子
|
|
|
+ const factor = [ 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 ];
|
|
|
+ // 校验位
|
|
|
+ const parity = [ 1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2 ];
|
|
|
+ let sum = 0;
|
|
|
+ let ai = 0;
|
|
|
+ let wi = 0;
|
|
|
+ for (let i = 0; i < 17; i++) {
|
|
|
+ ai = code[i];
|
|
|
+ wi = factor[i];
|
|
|
+ sum += ai * wi;
|
|
|
+ }
|
|
|
+ if (parity[sum % 11] !== code[17].toUpperCase()) {
|
|
|
+ row = {
|
|
|
+ pass: false,
|
|
|
+ msg: '身份证号校验位错误',
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (row.pass) {
|
|
|
+ row.gender = this.maleOrFemalByIdCard(code);
|
|
|
+ row.age = this.getAge(code);
|
|
|
+ }
|
|
|
+ return row;
|
|
|
+ }
|
|
|
+ // 性别
|
|
|
+ maleOrFemalByIdCard(idCard) {
|
|
|
+ if (_.isArray) idCard = idCard.join('');
|
|
|
+ idCard = _.trim(idCard.replace(/ /g, '')); // 对身份证号码做处理。包括字符间有空格。
|
|
|
+ if (idCard.length === 15) {
|
|
|
+ if (idCard.substring(14, 15) % 2 === 0) {
|
|
|
+ return '1';
|
|
|
+ }
|
|
|
+ return '0';
|
|
|
+
|
|
|
+ } else if (idCard.length === 18) {
|
|
|
+ if (idCard.substring(14, 17) % 2 === 0) {
|
|
|
+ return '1';
|
|
|
+ }
|
|
|
+ return '0';
|
|
|
+
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+
|
|
|
+ }
|
|
|
+ // 年龄
|
|
|
+ getAge(idCard) {
|
|
|
+ if (_.isArray) idCard = idCard.join('');
|
|
|
+ const ageDate = new Date();
|
|
|
+ const month = ageDate.getMonth() + 1;
|
|
|
+ const day = ageDate.getDate();
|
|
|
+ let age = ageDate.getFullYear() - idCard.substring(6, 10) - 1;
|
|
|
+ if (idCard.substring(10, 12) < month || (idCard.substring(10, 12) === month && idCard.substring(12, 14) <= day)) {
|
|
|
+ age++;
|
|
|
+ }
|
|
|
+ if (age <= 0) {
|
|
|
+ age = 1;
|
|
|
+ }
|
|
|
+ return age;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
module.exports = MatchSignService;
|