matchSmallGroupSchedule.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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 } = await 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. // async getRefMods() {
  195. // const mod = await this.getModel();
  196. // const refMods = [];
  197. // const populate = [];
  198. // for (const key in mod) {
  199. // const { ref, refPath } = mod[key];
  200. // if (!ref && !refPath) continue;
  201. // const obj = { col: key, prop: mod[key].getProp, type: mod[key].type.name };
  202. // refMods.push(obj);
  203. // // 检查ref/refPath是否还有嵌套
  204. // if (ref) {
  205. // // 递归查找ref的关系,构造ref关系树图
  206. // const res = this.checkSchema(ref);
  207. // // console.log(res);
  208. // }
  209. // }
  210. // return { refMods, populate };
  211. // }
  212. // 组成子 populate => {path,model}
  213. checkSchema(thisRef, path) {
  214. const { schema } = this.findModel(thisRef, path);
  215. for (const key in schema) {
  216. const { ref, refPath } = schema[key];
  217. if (!ref && !refPath) continue;
  218. const obj = {};
  219. if (ref) {
  220. const arr = ref.split('.').map(i => _.upperFirst(i));
  221. obj.ref = _.upperFirst(_.last(arr));
  222. let mpath = path;
  223. // 如果有path,就应该不会有arr.length>0的情况
  224. if (arr.length > 0) {
  225. // 说明是有路径的,需要将路径也填充
  226. arr.pop();
  227. mpath = arr.join('.');
  228. }
  229. // 递归寻找ref
  230. const { schema: sch } = this.checkSchema(obj.ref, mpath);
  231. console.log(key, ref);
  232. console.log(sch);
  233. // for (const key in sch) {
  234. // const obj = sch[key];
  235. // const populate = this.dealSchema(obj);
  236. // }
  237. }
  238. }
  239. return schema;
  240. }
  241. // dealSchema(schema) {
  242. // }
  243. findModel(modelName, path = this.defaultModule) {
  244. // 有没有默认路径,将路径整合进去
  245. const modelPath = [];
  246. if (path) modelPath.push(...path.split('.'));
  247. modelPath.push(_.upperFirst(modelName));
  248. const modelPathStr = modelPath.join('.');
  249. const m = _.get(this.ctx.model, modelPathStr);
  250. if (m) return { schema: _.get(m, 'prototype.schema.obj'), path: modelPathStr };
  251. let returnData;
  252. // 去掉要找到的目标model
  253. modelPath.pop();
  254. const dir = modelPath.join('.');
  255. const rootModel = _.get(this.ctx.model, dir, this.ctx.model);
  256. for (const mn in rootModel) {
  257. const type = typeof rootModel[mn];
  258. if (type === 'object') {
  259. // rootModel[mn] 是目录,要进入目录里面找内容
  260. returnData = this.findModel(modelName, mn);
  261. }
  262. // 没有 else 的原因是,对于model来说;路径是object类型,model是function类型,而model在 上面 有关m变量 部分已经处理完,不会有其他形式
  263. }
  264. return returnData;
  265. }
  266. }
  267. module.exports = MatchSmallGroupScheduleService;