matchSmallGroupSchedule.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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. const { ObjectId } = require('mongoose').Types;
  7. //
  8. class MatchSmallGroupScheduleService extends CrudService {
  9. constructor(ctx) {
  10. super(ctx, 'matchsmallgroupschedule');
  11. this.model = this.ctx.model.Race.MatchSmallGroupSchedule;
  12. this.baseUserModel = this.ctx.model.Base.User;
  13. this.userModel = this.ctx.model.Race.User;
  14. this.teamApplyModel = this.ctx.model.Race.TeamApply;
  15. // 加入框架
  16. this.defaultModule = this.app.config.defaultModel || 'Race';
  17. }
  18. async result({ match_id, group_id, project_id }) {
  19. const { refMods, populate } = this.getRefMods();
  20. let list = await this.model.find({ match_id, group_id, project_id }).populate({
  21. path: 'team_id',
  22. model: this.ctx.model.Race.MatchTeamGroup,
  23. select: 'name',
  24. });
  25. if (list.length <= 0) return;
  26. list = JSON.parse(JSON.stringify(list));
  27. list = list.map(i => {
  28. const { winner, player_one, player_one_score, player_two, player_two_score } = i;
  29. if (winner) return i;
  30. if (player_one_score > player_two_score) i.winner = player_one;
  31. else i.winner = player_two;
  32. i.team_name = _.get(i, 'team_id.name');
  33. i.team_id = _.get(i, 'team_id._id');
  34. return i;
  35. });
  36. const newArr = [];
  37. for (const i of list) {
  38. const d = await this.getPlayerName(i);
  39. newArr.push(d);
  40. }
  41. list = _.groupBy(newArr, 'team_id');
  42. const arr = [];
  43. for (const team_id in list) {
  44. const groups = list[team_id];
  45. const team_name = _.get(_.head(groups), 'team_name');
  46. const obj = { team_name, team_id };
  47. let players = [];
  48. const p1s = groups.map(i => ({ player: i.player_one, player_name: i.player_one_name }));
  49. const p2s = groups.map(i => ({ player: i.player_two, player_name: i.player_two_name }));
  50. players.push(...p1s, ...p2s);
  51. players = _.uniqBy(players, 'player');
  52. // 转换成object[], player:选手; win: 胜场; score:净胜球
  53. players = players.map(i => ({ player: i.player, player_name: i.player_name, win: 0, score: 0 }));
  54. for (const g of groups) {
  55. const { winner, player_one, player_one_score, player_two, player_two_score } = g;
  56. const p1RoundScore = this.getScore(player_one_score, player_two_score);
  57. const p2RoundScore = this.getScore(player_two_score, player_one_score);
  58. const p1 = players.find(f => f.player === player_one);
  59. const p2 = players.find(f => f.player === player_two);
  60. // p1,p2谁没有就不行
  61. if (!p1 || !p2) continue;
  62. p1.score = p1.score + p1RoundScore || 0;
  63. p2.score = p2.score + p2RoundScore || 0;
  64. if (winner === player_one) p1.win += 1;
  65. else p2.win += 1;
  66. }
  67. players = _.orderBy(players, [ 'win', 'score' ], [ 'desc', 'desc' ]);
  68. obj.score = players;
  69. const playerArr = players.map(i => i.player_name);
  70. const scoreList = [];
  71. for (const p1 of players) {
  72. // 每列的第一个位置是选手
  73. const marr = [ p1.player_name ];
  74. for (const p2 of players) {
  75. // 循环表头的选手, 自己和自己没分
  76. if (p1.player === p2.player) {
  77. marr.push(null);
  78. continue;
  79. }
  80. const r = groups.find(f => (f.player_one === p1.player && f.player_two === p2.player) || (f.player_one === p2.player && f.player_two === p1.player));
  81. if (!r) marr.push(null);
  82. else {
  83. const { player_one_score, player_two_score } = r;
  84. marr.push(`${player_one_score || 0}:${player_two_score || 0}`);
  85. }
  86. }
  87. scoreList.push(marr);
  88. }
  89. obj.table = [ playerArr, ...scoreList ];
  90. arr.push(obj);
  91. }
  92. return arr;
  93. }
  94. /**
  95. * 计算净胜分
  96. * @param {String|Number} s1 分数1
  97. * @param {String|Number} s2 分数2
  98. * @return {Number} 净胜分
  99. */
  100. getScore(s1, s2) {
  101. return (parseInt(s1) || 0) - (parseInt(s2) || 0);
  102. }
  103. // 换选手名称
  104. async getPlayerName(data) {
  105. if (!data) return data;
  106. data = JSON.parse(JSON.stringify(data));
  107. const { player_type, player_one, player_two } = data;
  108. if (!player_type) return data;
  109. // 人处理
  110. if (player_type === 'Race.User') {
  111. if (player_one) {
  112. const p1 = await this.userModel.findById(player_one, { user_id: 1 }).populate({ path: 'user_id', model: this.baseUserModel, select: 'name' });
  113. data.player_one_name = _.get(p1, 'user_id.name');
  114. }
  115. if (player_two) {
  116. const p2 = await this.userModel.findById(player_two, { user_id: 1 }).populate({ path: 'user_id', model: this.baseUserModel, select: 'name' });
  117. data.player_two_name = _.get(p2, 'user_id.name');
  118. }
  119. } else if (player_type === 'Race.TeamApply') {
  120. if (player_one) {
  121. const p1 = await this.teamApplyModel.findById(player_one, { one_member_name: 1, two_member_name: 1 });
  122. data.player_one_name = `${_.get(p1, 'one_member_name')}-${_.get(p1, 'two_member_name')}`;
  123. }
  124. if (player_two) {
  125. const p2 = await this.teamApplyModel.findById(player_two, { one_member_name: 1, two_member_name: 1 });
  126. data.player_two_name = `${_.get(p2, 'one_member_name')}-${_.get(p2, 'two_member_name')}`;
  127. }
  128. }
  129. return data;
  130. }
  131. async saveAll(data) {
  132. for (const i of data) {
  133. const { _id } = i;
  134. if (!_id) {
  135. // TODO: 创建前:需要检查这些人员是否出现在这个项目中的别的组中
  136. await this.model.create(i);
  137. } else {
  138. await this.model.updateOne({ _id }, i);
  139. }
  140. }
  141. }
  142. async beforeCreate(body) {
  143. // 检查数据是否有重复,如果符合检查重复条件,就把之前的删了,用新来的
  144. const { match_id, group_id, project_id, team_id, player_one, player_two } = body;
  145. const query = {
  146. match_id,
  147. group_id,
  148. project_id,
  149. team_id,
  150. $or: [
  151. { player_one, player_two },
  152. { player_one: player_two, player_two: player_one },
  153. ],
  154. };
  155. const d = await this.model.findOne(query);
  156. if (d) await this.model.deleteOne(query);
  157. return body;
  158. }
  159. async beforeQuery(filter) {
  160. // 可查询自己的赛程-user_id / 某人的赛程
  161. // const { user_id, user_name } = filter;
  162. const user_name = _.get(filter, 'user_name');
  163. let user_id = _.get(filter, 'user_id');
  164. // 没有user_id就不需要处理查询条件
  165. if (!user_id && !user_name) return filter;
  166. const usualCondition = _.pick(filter, [ 'match_id', 'group_id', 'project_id' ]);
  167. if (user_name) {
  168. // 要先找比赛用户模块的数据id
  169. const baseUser = await this.baseUserModel.findOne({ name: new RegExp(user_name) }, { _id: 1 });
  170. if (!baseUser) delete filter.user_name;
  171. delete filter.user_name;
  172. const baseUserId = baseUser._id;
  173. const raceUser = await this.userModel.findOne({ user_id: baseUserId, type: '0' });
  174. if (raceUser) user_id = raceUser._id;
  175. }
  176. if (user_id) {
  177. // 需要查:该用户是 单打 和 双打 的情况
  178. // 单打,直接user_id 为player_one/two 就可以,双打需要查teamApply
  179. // 所以先把user_id添加进查询范围里
  180. let probablyList = [ user_id ];
  181. // 尽可能的缩小查询范围
  182. // 接着找组队申请中和该用户有关的人
  183. const teamApplyList = await this.teamApplyModel.find({ ...usualCondition, status: '1', $or: [{ one_member_id: user_id }, { two_member_id: user_id }] }, { _id: 1 });
  184. const teamApplyIds = teamApplyList.map(i => i._id);
  185. probablyList.push(...teamApplyIds);
  186. // 删除user_id.会造成错误
  187. delete filter.user_id;
  188. // 添加该用户正确的范围条件
  189. probablyList = probablyList.map(i => ObjectId(i).toString());
  190. filter.$or = [{ player_one: { $in: probablyList } }, { player_two: { $in: probablyList } }];
  191. }
  192. return filter;
  193. }
  194. async afterQuery(filter, data) {
  195. data = JSON.parse(JSON.stringify(data));
  196. for (const d of data) {
  197. const { player_type, player_one, player_two, referee_id } = d;
  198. if (player_type === 'Race.User') {
  199. const p1 = await this.userModel.findById(player_one, { user_id: 1 }).populate({ path: 'user_id', model: this.baseUserModel, select: 'name' });
  200. const p2 = await this.userModel.findById(player_two, { user_id: 1 }).populate({ path: 'user_id', model: this.baseUserModel, select: 'name' });
  201. d.player_one_name = _.get(p1, 'user_id.name');
  202. d.player_two_name = _.get(p2, 'user_id.name');
  203. } else if (player_type === 'Race.TeamApply') {
  204. const p1 = await this.teamApplyModel.findById(player_one, { one_member_name: 1, two_member_name: 1 });
  205. const p2 = await this.teamApplyModel.findById(player_two, { one_member_name: 1, two_member_name: 1 });
  206. d.player_one_name = `${_.get(p1, 'one_member_name')}-${_.get(p1, 'two_member_name')}`;
  207. d.player_two_name = `${_.get(p2, 'one_member_name')}-${_.get(p2, 'two_member_name')}`;
  208. }
  209. const referee = await this.userModel.findById(referee_id).populate({
  210. path: 'user_id',
  211. model: this.baseUserModel,
  212. });
  213. d.referee_id_name = _.get(referee, 'user_id.name');
  214. }
  215. return data;
  216. }
  217. async fetch(filter, { sort, desc, projection } = {}) {
  218. assert(filter);
  219. filter = await this.beforeFetch(filter);
  220. const { _id, id } = filter;
  221. if (_id || id) filter = { _id: ObjectId(_id || id) };
  222. // 处理排序
  223. if (sort && _.isString(sort)) {
  224. sort = { [sort]: desc ? -1 : 1 };
  225. } else if (sort && _.isArray(sort)) {
  226. sort = sort.map(f => ({ [f]: desc ? -1 : 1 })).reduce((p, c) => ({ ...p, ...c }), {});
  227. }
  228. const { refMods, populate } = this.getRefMods();
  229. let res = await this.model.findOne(filter, projection).populate(populate).exec();
  230. res = JSON.parse(JSON.stringify(res));
  231. for (const obj of refMods) {
  232. const { col, prop, type } = obj;
  233. if (!prop) continue;
  234. if (_.isArray(prop)) {
  235. for (const p of prop) {
  236. if (type === 'String') res[`${col}_${p}`] = _.get(res, `${col}.${p}`);
  237. if (type === 'Array') {
  238. const list = [];
  239. const oList = _.get(res, `${col}`);
  240. for (const d of oList) {
  241. const obj = { _id: d._id };
  242. obj[p] = _.get(d, p);
  243. list.push(obj);
  244. }
  245. res[`${col}_${p}`] = list;
  246. }
  247. }
  248. res[col] = _.get(res, `${col}._id`);
  249. }
  250. }
  251. res = await this.afterFetch(filter, res);
  252. return res;
  253. }
  254. async afterFetch(filter, d) {
  255. const { player_type, player_one, player_two, referee_id } = d;
  256. if (player_type === 'Race.User') {
  257. const p1 = await this.userModel.findById(player_one, { user_id: 1 }).populate({ path: 'user_id', model: this.baseUserModel, select: 'name' });
  258. const p2 = await this.userModel.findById(player_two, { user_id: 1 }).populate({ path: 'user_id', model: this.baseUserModel, select: 'name' });
  259. d.player_one_name = _.get(p1, 'user_id.name');
  260. d.player_two_name = _.get(p2, 'user_id.name');
  261. } else if (player_type === 'Race.TeamApply') {
  262. const p1 = await this.teamApplyModel.findById(player_one, { one_member_name: 1, two_member_name: 1 });
  263. const p2 = await this.teamApplyModel.findById(player_two, { one_member_name: 1, two_member_name: 1 });
  264. d.player_one_name = `${_.get(p1, 'one_member_name')}-${_.get(p1, 'two_member_name')}`;
  265. d.player_two_name = `${_.get(p2, 'one_member_name')}-${_.get(p2, 'two_member_name')}`;
  266. }
  267. const referee = await this.userModel.findById(referee_id).populate({
  268. path: 'user_id',
  269. model: this.baseUserModel,
  270. });
  271. d.referee_id_name = _.get(referee, 'user_id.name');
  272. return d;
  273. }
  274. }
  275. module.exports = MatchSmallGroupScheduleService;