add.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. const app = getApp()
  2. Page({
  3. query: {},
  4. data: {
  5. view: 'graph',
  6. frameStyle: { useTop: true, name: '赛程管理', leftArrow: true, useBar: false },
  7. canvasWidth: 375,
  8. canvasHeight: 600,
  9. pixelRatio: 1,
  10. forceMini: false,
  11. // 数据
  12. data: undefined,
  13. riseList: [],
  14. arrangeList: [],
  15. raceList: [],
  16. groundList: [],
  17. refereeList: [],
  18. arrangeData: {},
  19. // picker
  20. show: false,
  21. personList: [],
  22. selectNode: undefined
  23. },
  24. // 计算晋级图
  25. computedTreeData() {
  26. const getWinnerNumList = this.data.riseList; // 将每个小组取多少人收到1个纯数字的数组中
  27. const getWinnerNum = getWinnerNumList.reduce((p, n) => p + n, 0); // 小组赛选取人数: 应该是该比赛项目的 各组选取人数加和
  28. let level = 1;
  29. let loop = true;
  30. while (loop) {
  31. const needUserNum = 2 ** (level - 1);
  32. // 相等,说明已经计算出结果
  33. if (needUserNum === getWinnerNum) loop = false;
  34. // 小于,说明还可以继续往后计算
  35. else if (needUserNum < getWinnerNum) level++;
  36. else {
  37. // 大于,说明不符合淘汰赛安排,需要手动定位
  38. loop = false;
  39. level = NaN
  40. }
  41. }
  42. if (!level) {
  43. console.log('不继续,返回了,编不了数据')
  44. return;
  45. }
  46. const levelList = [];
  47. // 1:16;2:8;3:4;4:2
  48. for (let i = 0; i < level - 1; i++) {
  49. const t = level - i - 1;
  50. // 计算:该层的位置数量
  51. const number = 2 ** t;
  52. const arr = [];
  53. for (let j = 1; j <= number; j++) {
  54. const obj = { id: `${i}-${j}`, num: `${i}-${j}`, pos: [i, j] }
  55. arr.push(obj);
  56. }
  57. levelList.push(arr)
  58. }
  59. // 进行数据组合,从最少的入手,依次取回,然后将取出来的数据删除掉
  60. let getLevelIndex = levelList.length - 1;
  61. const data = this.resetData(levelList, getLevelIndex)
  62. let obj = { id: `${levelList.length}`, num: `${levelList.length}`, children: data }
  63. return obj;
  64. },
  65. resetData(dataList, index = 0) {
  66. const thisLevelList = dataList[index]
  67. // 取出2条数据
  68. const p1 = thisLevelList[0]
  69. const p2 = thisLevelList[1]
  70. // 删除取出的2条数据
  71. dataList[index].shift()
  72. dataList[index].shift()
  73. if (index - 1 < 0) return [p1, p2]
  74. const p1c = this.resetData(dataList, index - 1)
  75. const p2c = this.resetData(dataList, index - 1)
  76. p1.children = p1c
  77. p2.children = p2c;
  78. return [p1, p2]
  79. },
  80. // 点击节点事件
  81. nodeTap(e) {
  82. const node = e.detail;
  83. if (!node) return;
  84. this.setData({ selectNode: node })
  85. this.toOpen();
  86. },
  87. // 获取最基础的那一层节点数据
  88. getFirstLevelNodes(node) {
  89. if (!node.children) return node;
  90. const res = [];
  91. const nodes = node.children;
  92. for (const node of nodes) {
  93. if (node?.children) {
  94. let list = this.getFirstLevelNodes(node);
  95. res.push(list);
  96. } else {
  97. res.push(node)
  98. }
  99. }
  100. return res.flat();
  101. },
  102. // 选择人员的处理
  103. selectChange(changeNode, selectNode) {
  104. const obj = { player_name: changeNode.label, player_id: changeNode.value, node_id: selectNode.id, label: 'player_name', pos: selectNode.pos }
  105. const arrangeList = this.data.arrangeList;
  106. const i = arrangeList.findIndex(f => f.player_id === obj.player_id && f.pos && obj.pos && f.pos[0] === obj.pos[0])
  107. if (i >= 0) arrangeList.splice(i, 1)
  108. arrangeList.push(obj)
  109. this.setData({ arrangeList })
  110. // 并非使用数据重组的方式,将选择的数据放入创建晋级图的数据中心,而是使用一维数组,以节点id对应的方式进行数据更新,更为灵活
  111. // 接下来需要生成比赛信息的数据
  112. this.getRaceList();
  113. },
  114. // 设置比赛数据
  115. getRaceList() {
  116. const arrangeList = this.data.arrangeList;
  117. arrangeList.sort((a, b) => {
  118. if (!a.pos) return b - a
  119. else if (!b.pos) return a - b
  120. else {
  121. // 根据 晋级节点位置,小组内节点位置进行排序
  122. const a1 = a.pos[0]
  123. const b1 = b.pos[0]
  124. if (a1 - b1 !== 0) return a1 - b1
  125. else {
  126. const a2 = a.pos[1]
  127. const b2 = b.pos[1]
  128. return a2 - b2
  129. }
  130. }
  131. })
  132. const raceList = [];
  133. for (let i = 0; i < arrangeList.length; i += 2) {
  134. const d1 = arrangeList[i]
  135. const d2 = arrangeList[i + 1]
  136. // 前后缺项,没法比赛
  137. if (!(d1 && d2)) continue;
  138. const { pos: d1pos } = d1
  139. const { pos: d2pos } = d2;
  140. // 前后两项的层级不一样,不能形成比赛
  141. if (d1pos[0] !== d2pos[0]) continue
  142. // 前后两项层级一样,但是不是连续的数字,例如:1-1与1-3,不能进行比赛,必须是 前+1=后
  143. if (d1pos[1] + 1 !== d2pos[1]) continue
  144. const { player_id: player_one, player_name: player_one_name, node_id: node_id_one } = d1
  145. const { player_id: player_two, player_name: player_two_name, node_id: node_id_two } = d2
  146. raceList.push({ player_one, player_one_name, node_id_one, player_two, player_two_name, node_id_two })
  147. }
  148. // 因为是数组,所以需要将model特殊处理下,按照一定规则处理可以正常赋值
  149. for (let i = 0; i < raceList.length; i++) {
  150. const d = raceList[i];
  151. d.groundModelName = `ground_id-${i}`;
  152. d.refereeModelName = `referee_id-${i}`;
  153. d.timeModelName = `match_time-${i}`;
  154. }
  155. const oRaceList = this.data.raceList;
  156. for (const race of raceList) {
  157. const { node_id_one, node_id_two } = race;
  158. const r = oRaceList.find(f => f.node_id_one === node_id_one && f.node_id_two === node_id_two)
  159. if (r) {
  160. const ri = oRaceList.findIndex(f => f.node_id_one === node_id_one && f.node_id_two === node_id_two)
  161. const { groundModelName, refereeModelName, timeModelName } = race
  162. r = { ...r, groundModelName, refereeModelName, timeModelName }
  163. oRaceList.splice(ri, 1, r)
  164. } else {
  165. oRaceList.push(race)
  166. }
  167. }
  168. this.setData({ raceList: oRaceList })
  169. },
  170. async onLoad(options) {
  171. const { match_id, grouping_id, project_id } = options
  172. this.query = { match_id, grouping_id, project_id }
  173. await this.getTeams()
  174. // 设置初始的晋级图
  175. const data = this.computedTreeData();
  176. this.setData({ data })
  177. // 请求 小组赛的 胜者列表
  178. await this.searchWinnerList();
  179. await this.search();
  180. await this.searchOthers()
  181. },
  182. // 查询已安排的数据
  183. async search() {
  184. let res = await app.$get(`/newCourt/api/eliminatArrange/getOne`, this.query)
  185. if (app.$checkRes(res)) {
  186. if (res.data) { const { arrange } = res.data; this.setData({ arrangeData: res.data, arrangeList: arrange }) }
  187. }
  188. res = await app.$get(`/newCourt/api/eliminateRace`, this.query)
  189. if (app.$checkRes(res)) {
  190. this.setData({
  191. raceList: res.data
  192. })
  193. }
  194. // 数据本地化处理下
  195. this.getRaceList();
  196. },
  197. // 获取该项目的小组,形成晋级图
  198. async getTeams() {
  199. const res = await app.$get(`/newCourt/api/raceTeam`, this.query)
  200. if (app.$checkRes(res)) {
  201. const { data } = res
  202. const riseList = data.map(i => i.rise)
  203. this.setData({ riseList })
  204. }
  205. },
  206. // 获取小组赛胜者名单
  207. async searchWinnerList() {
  208. const res = await app.$post(`/newCourt/api/race/getWinnerList`, this.query)
  209. if (app.$checkRes(res)) {
  210. const { data } = res;
  211. const arr = [];
  212. for (const i of data) {
  213. const { personList, name } = i;
  214. for (const person of personList) {
  215. // person.player_name += `(${name})`;
  216. const obj = { label: person.player_name, value: person.player_id }
  217. arr.push(obj)
  218. }
  219. }
  220. this.setData({
  221. personList: arr
  222. })
  223. }
  224. },
  225. /**自动排列最底层,挨个放 */
  226. toAutoInitData() {
  227. const personList = this.data.personList;
  228. const data = this.data.data
  229. const getBaseList = data => {
  230. if (!data.children) return data;
  231. const arr = [];
  232. for (const d of data.children) {
  233. const r = getBaseList(d)
  234. arr.push(r);
  235. }
  236. return arr.flat();
  237. }
  238. const firstList = getBaseList(data);
  239. for (let i = 0; i < firstList.length; i++) {
  240. const f = firstList[i];
  241. const p = personList[i];
  242. this.selectChange(p, f);
  243. }
  244. },
  245. /**查询选项的数据 */
  246. async searchOthers() {
  247. let res;
  248. res = await app.$get(`/newCourt/api/ground`)
  249. if (app.$checkRes(res)) {
  250. this.setData({ groundList: res.data })
  251. }
  252. res = await app.$get(`/newCourt/api/user`, { type: '1' })
  253. if (app.$checkRes(res)) {
  254. this.setData({ refereeList: res.data })
  255. }
  256. },
  257. turnView(e) {
  258. const view = e?.target?.dataset?.view || 'graph';
  259. this.setData({ view })
  260. },
  261. //picker
  262. onChange(event) {
  263. const obj = event?.detail?.value;
  264. this.selectChange(obj, this.data.selectNode);
  265. this.toClose();
  266. },
  267. toOpen() {
  268. this.setData({ show: true })
  269. },
  270. toClose() {
  271. this.setData({ show: false, selectNode: undefined })
  272. },
  273. toSelected(event) {
  274. const data = event?.detail;
  275. const { value, model } = data;
  276. if (!model) return;
  277. const arr = model.split('-')
  278. const modelName = arr[0]
  279. const index = arr[1]
  280. const raceList = this.data.raceList;
  281. raceList[index][modelName] = value;
  282. if (modelName === 'ground_id') {
  283. const ground = this.data.groundList.find(f => f._id === value)
  284. if (ground && ground.referee_id) raceList[index]['referee_id'] = ground.referee_id
  285. }
  286. this.setData({ raceList })
  287. },
  288. // 跳转菜单
  289. back(e) {
  290. wx.navigateBack({
  291. delta: 1,
  292. })
  293. },
  294. async toSubmit() {
  295. // 生成的比赛信息
  296. let raceList = this.data.raceList;
  297. // 安排信息
  298. let arrangeList = this.data.arrangeList;
  299. // arrangeList:需要将match_id,grouping_id,project_id 也放入,确定是这个项目的淘汰赛
  300. let arrange = this.data.arrangeData;
  301. if (!arrange._id) {
  302. arrange = { arrange: arrangeList, ...this.query }
  303. }
  304. // raceList:淘汰赛的比赛赛程
  305. raceList = raceList.map(i => {
  306. const { groundModelName, refereeModelName, timeModelName, ...others } = i
  307. return { ...others, ...this.query }
  308. })
  309. // 创建安排
  310. let res
  311. if (arrange._id) {
  312. res = await app.$post(`/newCourt/api/eliminatArrange/${arrange._id}`, arrange)
  313. if (app.$checkRes(res)) {
  314. console.log('淘汰赛安排创建成功')
  315. }
  316. } else {
  317. res = await app.$post(`/newCourt/api/eliminatArrange`, arrange)
  318. if (app.$checkRes(res)) {
  319. console.log('淘汰赛安排创建成功')
  320. }
  321. }
  322. res = await app.$post('/newCourt/api/eliminateRace/saveAll', raceList)
  323. wx.showToast({
  324. title: '保存成功',
  325. })
  326. }
  327. });