matchSmallGroupSchedule.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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 saveAll(data) {
  19. for (const i of data) {
  20. const { _id } = i;
  21. if (!_id) {
  22. // TODO: 创建前:需要检查这些人员是否出现在这个项目中的别的组中
  23. await this.model.create(i);
  24. } else {
  25. await this.model.updateOne({ _id }, i);
  26. }
  27. }
  28. }
  29. async beforeCreate(body) {
  30. // 检查数据是否有重复,如果符合检查重复条件,就把之前的删了,用新来的
  31. const { match_id, group_id, project_id, team_id, player_one, player_two } = body;
  32. const query = {
  33. match_id,
  34. group_id,
  35. project_id,
  36. team_id,
  37. $or: [
  38. { player_one, player_two },
  39. { player_one: player_two, player_two: player_one },
  40. ],
  41. };
  42. const d = await this.model.findOne(query);
  43. if (d) await this.model.deleteOne(query);
  44. return body;
  45. }
  46. async beforeQuery(filter) {
  47. // 可查询自己的赛程-user_id / 某人的赛程
  48. // const { user_id, user_name } = filter;
  49. const user_name = _.get(filter, 'user_name');
  50. let user_id = _.get(filter, 'user_id');
  51. // 没有user_id就不需要处理查询条件
  52. if (!user_id && !user_name) return filter;
  53. const usualCondition = _.pick(filter, [ 'match_id', 'group_id', 'project_id' ]);
  54. if (user_name) {
  55. // 要先找比赛用户模块的数据id
  56. const baseUser = await this.baseUserModel.findOne({ name: new RegExp(user_name) }, { _id: 1 });
  57. if (!baseUser) delete filter.user_name;
  58. delete filter.user_name;
  59. const baseUserId = baseUser._id;
  60. const raceUser = await this.userModel.findOne({ user_id: baseUserId, type: '0' });
  61. if (raceUser) user_id = raceUser._id;
  62. }
  63. if (user_id) {
  64. // 需要查:该用户是 单打 和 双打 的情况
  65. // 单打,直接user_id 为player_one/two 就可以,双打需要查teamApply
  66. // 所以先把user_id添加进查询范围里
  67. let probablyList = [ user_id ];
  68. // 尽可能的缩小查询范围
  69. // 接着找组队申请中和该用户有关的人
  70. const teamApplyList = await this.teamApplyModel.find({ ...usualCondition, status: '1', $or: [{ one_member_id: user_id }, { two_member_id: user_id }] }, { _id: 1 });
  71. const teamApplyIds = teamApplyList.map(i => i._id);
  72. probablyList.push(...teamApplyIds);
  73. // 删除user_id.会造成错误
  74. delete filter.user_id;
  75. // 添加该用户正确的范围条件
  76. probablyList = probablyList.map(i => ObjectId(i).toString());
  77. filter.$or = [{ player_one: { $in: probablyList } }, { player_two: { $in: probablyList } }];
  78. }
  79. return filter;
  80. }
  81. turnFilter(filter) {
  82. const str = /^%\S*%$/;
  83. // $是mongodb固定条件,不用处理;大多为手写特殊处理过的条件
  84. let keys = Object.keys(filter).filter(f => !f.includes('$'));
  85. for (const key of keys) {
  86. const res = key.match(str);
  87. if (res) {
  88. const newKey = key.slice(1, key.length - 1);
  89. if (!ObjectId.isValid(filter[key])) filter[newKey] = new RegExp(filter[key]);
  90. delete filter[key];
  91. }
  92. }
  93. // 再次过滤数据,将数组的数据都变成{$in:value},因为查询变成了聚合查询
  94. // $是mongodb固定条件,不用处理;大多为手写特殊处理过的条件
  95. keys = Object.keys(filter).filter(f => !f.includes('$'));
  96. for (const key of keys) {
  97. if (_.isArray(filter[key])) {
  98. filter[key] = { $in: filter[key] };
  99. } else if (filter[key] === 'true' || filter[key] === 'false') {
  100. // 布尔类型的值检查,如果是布尔类型,则将字符串转为布尔
  101. filter[key] = filter[key] === 'true';
  102. }
  103. }
  104. return filter;
  105. }
  106. async afterQuery(filter, data) {
  107. data = JSON.parse(JSON.stringify(data));
  108. for (const d of data) {
  109. const { player_type, player_one, player_two, referee_id } = d;
  110. if (player_type === 'User') {
  111. const pouid = _.get(player_one, 'user_id');
  112. const user1 = await this.baseUserModel.findById(pouid);
  113. d.player_one_name = _.get(user1, 'name');
  114. d.player_one = _.get(d, 'player_one._id');
  115. const ptuid = _.get(player_two, 'user_id');
  116. const user2 = await this.baseUserModel.findById(ptuid);
  117. d.player_two_name = _.get(user2, 'name');
  118. d.player_two = _.get(d, 'player_two._id');
  119. } else if (player_type === 'TeamApply') {
  120. d.player_one_name = `${_.get(d, 'player_one.one_member_name')}-${_.get(d, 'player_one.two_member_name')}`;
  121. d.player_one = _.get(d, 'player_one._id');
  122. d.player_two_name = `${_.get(d, 'player_two.one_member_name')}-${_.get(d, 'player_two.two_member_name')}`;
  123. d.player_two = _.get(d, 'player_two._id');
  124. }
  125. const referee = await this.userModel.findById(referee_id).populate({
  126. path: 'user_id',
  127. model: this.baseUserModel,
  128. });
  129. d.referee_id_name = _.get(referee, 'user_id.name');
  130. }
  131. return data;
  132. }
  133. async fetch(filter, { sort, desc, projection } = {}) {
  134. assert(filter);
  135. filter = await this.beforeFetch(filter);
  136. const { _id, id } = filter;
  137. if (_id || id) filter = { _id: ObjectId(_id || id) };
  138. // 处理排序
  139. if (sort && _.isString(sort)) {
  140. sort = { [sort]: desc ? -1 : 1 };
  141. } else if (sort && _.isArray(sort)) {
  142. sort = sort.map(f => ({ [f]: desc ? -1 : 1 })).reduce((p, c) => ({ ...p, ...c }), {});
  143. }
  144. const { refMods, populate } = this.getRefMods();
  145. let res = await this.model.findOne(filter, projection).populate(populate).exec();
  146. res = JSON.parse(JSON.stringify(res));
  147. for (const obj of refMods) {
  148. const { col, prop, type } = obj;
  149. if (!prop) continue;
  150. if (_.isArray(prop)) {
  151. for (const p of prop) {
  152. if (type === 'String') res[`${col}_${p}`] = _.get(res, `${col}.${p}`);
  153. if (type === 'Array') {
  154. const list = [];
  155. const oList = _.get(res, `${col}`);
  156. for (const d of oList) {
  157. const obj = { _id: d._id };
  158. obj[p] = _.get(d, p);
  159. list.push(obj);
  160. }
  161. res[`${col}_${p}`] = list;
  162. }
  163. }
  164. res[col] = _.get(res, `${col}._id`);
  165. }
  166. }
  167. res = await this.afterFetch(filter, res);
  168. return res;
  169. }
  170. async afterFetch(filter, d) {
  171. const { player_type, player_one, player_two, referee_id } = d;
  172. if (player_type === 'User') {
  173. const pouid = _.get(player_one, 'user_id');
  174. const user1 = await this.baseUserModel.findById(pouid);
  175. d.player_one_name = _.get(user1, 'name');
  176. d.player_one = _.get(d, 'player_one._id');
  177. const ptuid = _.get(player_two, 'user_id');
  178. const user2 = await this.baseUserModel.findById(ptuid);
  179. d.player_two_name = _.get(user2, 'name');
  180. d.player_two = _.get(d, 'player_two._id');
  181. } else if (player_type === 'TeamApply') {
  182. d.player_one_name = `${_.get(d, 'player_one.one_member_name')}-${_.get(d, 'player_one.two_member_name')}`;
  183. d.player_one = _.get(d, 'player_one._id');
  184. d.player_two_name = `${_.get(d, 'player_two.one_member_name')}-${_.get(d, 'player_two.two_member_name')}`;
  185. d.player_two = _.get(d, 'player_two._id');
  186. }
  187. const referee = await this.userModel.findById(referee_id).populate({
  188. path: 'user_id',
  189. model: this.baseUserModel,
  190. });
  191. d.referee_id_name = _.get(referee, 'user_id.name');
  192. return d;
  193. }
  194. getRefMods() {
  195. // 找到该表的schema(表结构)
  196. const mod = this.getSchema();
  197. const populate = this.resetPopulate(mod);
  198. const refMods = [];
  199. for (const key in mod) {
  200. if (!mod[key].ref && !mod[key].refPath) continue;
  201. const obj = { col: key, prop: mod[key].getProp, type: mod[key].type.name };
  202. refMods.push(obj);
  203. }
  204. return { refMods, populate };
  205. }
  206. // 针对每个表进行检查
  207. resetPopulate(schema) {
  208. const arr = [];
  209. for (const key in schema) {
  210. const e = schema[key];
  211. const { ref } = e;
  212. if (!ref) continue;
  213. const obj = { path: key };
  214. const modelPath = this.formatModelPath(ref);
  215. const model = this.getModel(modelPath);
  216. obj.model = model;
  217. const msch = this.getSchema(modelPath);
  218. const popu = this.resetPopulate(msch);
  219. if (popu.length > 0) obj.populate = popu;
  220. arr.push(obj);
  221. }
  222. return arr;
  223. }
  224. // 格式化model路径
  225. formatModelPath(str) {
  226. let arr = str.split('.');
  227. arr = arr.map(i => _.upperFirst(i));
  228. const modelPath = arr.join('.');
  229. return modelPath;
  230. }
  231. // 获取model的模式
  232. getSchema(path) {
  233. const model = this.getModel(path);
  234. return _.get(model, 'prototype.schema.obj');
  235. }
  236. // 获取model实例
  237. getModel(path) {
  238. if (!path) return this.model;
  239. let model = _.get(this.ctx.model, path);
  240. const clients = this.app.mongooseDB.clients;
  241. if (clients && !model) {
  242. model = _.get(this.ctx.model, `${this.defaultModule}.${path}`);
  243. }
  244. return model;
  245. }
  246. }
  247. module.exports = MatchSmallGroupScheduleService;