|
@@ -1,73 +1,349 @@
|
|
|
const app = getApp()
|
|
|
-Page({
|
|
|
|
|
|
- /**
|
|
|
- * 页面的初始数据
|
|
|
- */
|
|
|
+Page({
|
|
|
+ query: {},
|
|
|
data: {
|
|
|
+ view: 'graph',
|
|
|
frameStyle: { useTop: true, name: '赛程管理', leftArrow: true, useBar: false },
|
|
|
+ canvasWidth: 375,
|
|
|
+ canvasHeight: 600,
|
|
|
+ pixelRatio: 1,
|
|
|
+ forceMini: false,
|
|
|
+
|
|
|
+ // 数据
|
|
|
+ data: undefined,
|
|
|
+ riseList: [],
|
|
|
+ arrangeList: [],
|
|
|
+ raceList: [],
|
|
|
+ groundList: [],
|
|
|
+ refereeList: [],
|
|
|
+
|
|
|
+ arrangeData: {},
|
|
|
+
|
|
|
+ // picker
|
|
|
+ show: false,
|
|
|
+ personList: [],
|
|
|
+ selectNode: undefined
|
|
|
+
|
|
|
},
|
|
|
- // 跳转菜单
|
|
|
- back(e) {
|
|
|
- wx.navigateBack({
|
|
|
- delta: 1,
|
|
|
+ // 计算晋级图
|
|
|
+ computedTreeData() {
|
|
|
+ const getWinnerNumList = this.data.riseList; // 将每个小组取多少人收到1个纯数字的数组中
|
|
|
+ const getWinnerNum = getWinnerNumList.reduce((p, n) => p + n, 0); // 小组赛选取人数: 应该是该比赛项目的 各组选取人数加和
|
|
|
+ let level = 1;
|
|
|
+ let loop = true;
|
|
|
+ while (loop) {
|
|
|
+ const needUserNum = 2 ** (level - 1);
|
|
|
+ // 相等,说明已经计算出结果
|
|
|
+ if (needUserNum === getWinnerNum) loop = false;
|
|
|
+ // 小于,说明还可以继续往后计算
|
|
|
+ else if (needUserNum < getWinnerNum) level++;
|
|
|
+ else {
|
|
|
+ // 大于,说明不符合淘汰赛安排,需要手动定位
|
|
|
+ loop = false;
|
|
|
+ level = NaN
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!level) {
|
|
|
+ console.log('不继续,返回了,编不了数据')
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const levelList = [];
|
|
|
+ // 1:16;2:8;3:4;4:2
|
|
|
+ for (let i = 0; i < level - 1; i++) {
|
|
|
+ const t = level - i - 1;
|
|
|
+ // 计算:该层的位置数量
|
|
|
+ const number = 2 ** t;
|
|
|
+ const arr = [];
|
|
|
+ for (let j = 1; j <= number; j++) {
|
|
|
+ const obj = { id: `${i}-${j}`, num: `${i}-${j}`, pos: [i, j] }
|
|
|
+ arr.push(obj);
|
|
|
+ }
|
|
|
+ levelList.push(arr)
|
|
|
+ }
|
|
|
+ // 进行数据组合,从最少的入手,依次取回,然后将取出来的数据删除掉
|
|
|
+ let getLevelIndex = levelList.length - 1;
|
|
|
+ const data = this.resetData(levelList, getLevelIndex)
|
|
|
+ let obj = { id: `${levelList.length}`, num: `${levelList.length}`, children: data }
|
|
|
+ return obj;
|
|
|
+ },
|
|
|
+ resetData(dataList, index = 0) {
|
|
|
+ const thisLevelList = dataList[index]
|
|
|
+ // 取出2条数据
|
|
|
+ const p1 = thisLevelList[0]
|
|
|
+ const p2 = thisLevelList[1]
|
|
|
+ // 删除取出的2条数据
|
|
|
+ dataList[index].shift()
|
|
|
+ dataList[index].shift()
|
|
|
+ if (index - 1 < 0) return [p1, p2]
|
|
|
+ const p1c = this.resetData(dataList, index - 1)
|
|
|
+ const p2c = this.resetData(dataList, index - 1)
|
|
|
+ p1.children = p1c
|
|
|
+ p2.children = p2c;
|
|
|
+ return [p1, p2]
|
|
|
+ },
|
|
|
+ // 点击节点事件
|
|
|
+ nodeTap(e) {
|
|
|
+ const node = e.detail;
|
|
|
+ if (!node) return;
|
|
|
+ this.setData({ selectNode: node })
|
|
|
+ this.toOpen();
|
|
|
+ },
|
|
|
+ // 获取最基础的那一层节点数据
|
|
|
+ getFirstLevelNodes(node) {
|
|
|
+ if (!node.children) return node;
|
|
|
+ const res = [];
|
|
|
+ const nodes = node.children;
|
|
|
+ for (const node of nodes) {
|
|
|
+ if (node?.children) {
|
|
|
+ let list = this.getFirstLevelNodes(node);
|
|
|
+ res.push(list);
|
|
|
+ } else {
|
|
|
+ res.push(node)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return res.flat();
|
|
|
+ },
|
|
|
+
|
|
|
+ // 选择人员的处理
|
|
|
+ selectChange(changeNode, selectNode) {
|
|
|
+ const obj = { player_name: changeNode.label, player_id: changeNode.value, node_id: selectNode.id, label: 'player_name', pos: selectNode.pos }
|
|
|
+ const arrangeList = this.data.arrangeList;
|
|
|
+ const i = arrangeList.findIndex(f => f.player_id === obj.player_id && f.pos && obj.pos && f.pos[0] === obj.pos[0])
|
|
|
+ if (i >= 0) arrangeList.splice(i, 1)
|
|
|
+ arrangeList.push(obj)
|
|
|
+ this.setData({ arrangeList })
|
|
|
+ // 并非使用数据重组的方式,将选择的数据放入创建晋级图的数据中心,而是使用一维数组,以节点id对应的方式进行数据更新,更为灵活
|
|
|
+ // 接下来需要生成比赛信息的数据
|
|
|
+ this.getRaceList();
|
|
|
+ },
|
|
|
+ // 设置比赛数据
|
|
|
+ getRaceList() {
|
|
|
+ const arrangeList = this.data.arrangeList;
|
|
|
+ arrangeList.sort((a, b) => {
|
|
|
+ if (!a.pos) return b - a
|
|
|
+ else if (!b.pos) return a - b
|
|
|
+ else {
|
|
|
+ // 根据 晋级节点位置,小组内节点位置进行排序
|
|
|
+ const a1 = a.pos[0]
|
|
|
+ const b1 = b.pos[0]
|
|
|
+ if (a1 - b1 !== 0) return a1 - b1
|
|
|
+ else {
|
|
|
+ const a2 = a.pos[1]
|
|
|
+ const b2 = b.pos[1]
|
|
|
+ return a2 - b2
|
|
|
+ }
|
|
|
+ }
|
|
|
})
|
|
|
+ const raceList = [];
|
|
|
+ for (let i = 0; i < arrangeList.length; i += 2) {
|
|
|
+ const d1 = arrangeList[i]
|
|
|
+ const d2 = arrangeList[i + 1]
|
|
|
+ // 前后缺项,没法比赛
|
|
|
+ if (!(d1 && d2)) continue;
|
|
|
+ const { pos: d1pos } = d1
|
|
|
+ const { pos: d2pos } = d2;
|
|
|
+ // 前后两项的层级不一样,不能形成比赛
|
|
|
+ if (d1pos[0] !== d2pos[0]) continue
|
|
|
+ // 前后两项层级一样,但是不是连续的数字,例如:1-1与1-3,不能进行比赛,必须是 前+1=后
|
|
|
+ if (d1pos[1] + 1 !== d2pos[1]) continue
|
|
|
+ const { player_id: player_one, player_name: player_name_one, node_id: node_id_one } = d1
|
|
|
+ const { player_id: player_two, player_name: player_name_two, node_id: node_id_two } = d2
|
|
|
+ raceList.push({ player_one, player_name_one, node_id_one, player_two, player_name_two, node_id_two })
|
|
|
+ }
|
|
|
+ // 因为是数组,所以需要将model特殊处理下,按照一定规则处理可以正常赋值
|
|
|
+ for (let i = 0; i < raceList.length; i++) {
|
|
|
+ const d = raceList[i];
|
|
|
+ d.groundModelName = `ground_id-${i}`;
|
|
|
+ d.refereeModelName = `referee_id-${i}`;
|
|
|
+ d.timeModelName = `match_time-${i}`;
|
|
|
+ }
|
|
|
+ const oRaceList = this.data.raceList;
|
|
|
+ for (const race of raceList) {
|
|
|
+ const { node_id_one, node_id_two } = race;
|
|
|
+ const r = oRaceList.find(f => f.node_id_one === node_id_one && f.node_id_two === node_id_two)
|
|
|
+ if (r) {
|
|
|
+ const ri = oRaceList.findIndex(f => f.node_id_one === node_id_one && f.node_id_two === node_id_two)
|
|
|
+ const { groundModelName, refereeModelName, timeModelName } = race
|
|
|
+ r = { ...r, groundModelName, refereeModelName, timeModelName }
|
|
|
+ oRaceList.splice(ri, 1, r)
|
|
|
+ } else {
|
|
|
+ oRaceList.push(race)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.setData({ raceList: oRaceList })
|
|
|
},
|
|
|
|
|
|
- /**
|
|
|
- * 生命周期函数--监听页面加载
|
|
|
- */
|
|
|
- onLoad: function (options) {
|
|
|
- const that = this;
|
|
|
- console.log(options);
|
|
|
|
|
|
+ async onLoad(options) {
|
|
|
+ console.log(options);
|
|
|
+ const { match_id, grouping_id, project_id } = options
|
|
|
+ this.query = { match_id, grouping_id, project_id }
|
|
|
+ await this.getTeams()
|
|
|
+ // 设置初始的晋级图
|
|
|
+ const data = this.computedTreeData();
|
|
|
+ this.setData({ data })
|
|
|
+ // 请求 小组赛的 胜者列表
|
|
|
+ await this.searchWinnerList();
|
|
|
+ await this.search();
|
|
|
+ await this.searchOthers()
|
|
|
},
|
|
|
- /**
|
|
|
- * 生命周期函数--监听页面初次渲染完成
|
|
|
- */
|
|
|
- onReady: function () {
|
|
|
-
|
|
|
+ // 查询已安排的数据
|
|
|
+ async search() {
|
|
|
+ let res = await app.$get(`/newCourt/api/eliminatArrange/getOne`, this.query)
|
|
|
+ if (app.$checkRes(res)) {
|
|
|
+ const { arrange } = res.data;
|
|
|
+ this.setData({
|
|
|
+ arrangeData: res.data,
|
|
|
+ arrangeList: arrange
|
|
|
+ })
|
|
|
+ }
|
|
|
+ res = await app.$get(`/newCourt/api/eliminateRace`, this.query)
|
|
|
+ if (app.$checkRes(res)) {
|
|
|
+ this.setData({
|
|
|
+ raceList: res.data
|
|
|
+ })
|
|
|
+ }
|
|
|
+ // 数据本地化处理下
|
|
|
+ this.getRaceList();
|
|
|
},
|
|
|
|
|
|
- /**
|
|
|
- * 生命周期函数--监听页面显示
|
|
|
- */
|
|
|
- onShow: function () {
|
|
|
-
|
|
|
+ // 获取该项目的小组,形成晋级图
|
|
|
+ async getTeams() {
|
|
|
+ const res = await app.$get(`/newCourt/api/raceTeam`, this.query)
|
|
|
+ if (app.$checkRes(res)) {
|
|
|
+ const { data } = res
|
|
|
+ const riseList = data.map(i => i.rise)
|
|
|
+ this.setData({ riseList })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 获取小组赛胜者名单
|
|
|
+ async searchWinnerList() {
|
|
|
+ const res = await app.$post(`/newCourt/api/race/getWinnerList`, this.query)
|
|
|
+ if (app.$checkRes(res)) {
|
|
|
+ const { data } = res;
|
|
|
+ const arr = [];
|
|
|
+ for (const i of data) {
|
|
|
+ const { personList, name } = i;
|
|
|
+ for (const person of personList) {
|
|
|
+ // person.player_name += `(${name})`;
|
|
|
+ const obj = { label: person.player_name, value: person.player_id }
|
|
|
+ arr.push(obj)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.setData({
|
|
|
+ personList: arr
|
|
|
+ })
|
|
|
+ }
|
|
|
},
|
|
|
|
|
|
- /**
|
|
|
- * 生命周期函数--监听页面隐藏
|
|
|
- */
|
|
|
- onHide: function () {
|
|
|
+ /**自动排列最底层,挨个放 */
|
|
|
+ toAutoInitData() {
|
|
|
+ const personList = this.data.personList;
|
|
|
+ const data = this.data.data
|
|
|
+ const getBaseList = data => {
|
|
|
+ if (!data.children) return data;
|
|
|
+ const arr = [];
|
|
|
+ for (const d of data.children) {
|
|
|
+ const r = getBaseList(d)
|
|
|
+ arr.push(r);
|
|
|
+ }
|
|
|
+ return arr.flat();
|
|
|
|
|
|
+ }
|
|
|
+ const firstList = getBaseList(data);
|
|
|
+ for (let i = 0; i < firstList.length; i++) {
|
|
|
+ const f = firstList[i];
|
|
|
+ const p = personList[i];
|
|
|
+ this.selectChange(p, f);
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ /**查询选项的数据 */
|
|
|
+ async searchOthers() {
|
|
|
+ let res;
|
|
|
+ res = await app.$get(`/newCourt/api/ground`)
|
|
|
+ if (app.$checkRes(res)) {
|
|
|
+ this.setData({ groundList: res.data })
|
|
|
+ }
|
|
|
+ res = await app.$get(`/newCourt/api/user`, { type: '1' })
|
|
|
+ if (app.$checkRes(res)) {
|
|
|
+ this.setData({ refereeList: res.data })
|
|
|
+ }
|
|
|
},
|
|
|
|
|
|
- /**
|
|
|
- * 生命周期函数--监听页面卸载
|
|
|
- */
|
|
|
- onUnload: function () {
|
|
|
|
|
|
+ turnView(e) {
|
|
|
+ const view = e?.target?.dataset?.view || 'graph';
|
|
|
+ this.setData({ view })
|
|
|
},
|
|
|
|
|
|
- /**
|
|
|
- * 页面相关事件处理函数--监听用户下拉动作
|
|
|
- */
|
|
|
- onPullDownRefresh: function () {
|
|
|
-
|
|
|
+ //picker
|
|
|
+ onChange(event) {
|
|
|
+ const obj = event?.detail?.value;
|
|
|
+ this.selectChange(obj, this.data.selectNode);
|
|
|
+ this.toClose();
|
|
|
+ },
|
|
|
+ toOpen() {
|
|
|
+ this.setData({ show: true })
|
|
|
},
|
|
|
+ toClose() {
|
|
|
+ this.setData({ show: false, selectNode: undefined })
|
|
|
+ },
|
|
|
+ toSelected(event) {
|
|
|
+ const data = event?.detail;
|
|
|
+ const { value, model } = data;
|
|
|
+ if (!model) return;
|
|
|
+ const arr = model.split('-')
|
|
|
+ const modelName = arr[0]
|
|
|
+ const index = arr[1]
|
|
|
+ const raceList = this.data.raceList;
|
|
|
+ raceList[index][modelName] = value;
|
|
|
+ this.setData({ raceList })
|
|
|
|
|
|
- /**
|
|
|
- * 页面上拉触底事件的处理函数
|
|
|
- */
|
|
|
- onReachBottom: function () {
|
|
|
+ },
|
|
|
|
|
|
+ // 跳转菜单
|
|
|
+ back(e) {
|
|
|
+ wx.navigateBack({
|
|
|
+ delta: 1,
|
|
|
+ })
|
|
|
},
|
|
|
|
|
|
- /**
|
|
|
- * 用户点击右上角分享
|
|
|
- */
|
|
|
- onShareAppMessage: function () {
|
|
|
+ async toSubmit() {
|
|
|
+ // 生成的比赛信息
|
|
|
+ let raceList = this.data.raceList;
|
|
|
+ // 安排信息
|
|
|
+ let arrangeList = this.data.arrangeList;
|
|
|
|
|
|
+ // arrangeList:需要将match_id,grouping_id,project_id 也放入,确定是这个项目的淘汰赛
|
|
|
+ let arrange = this.data.arrangeData;
|
|
|
+ if (!arrange._id) {
|
|
|
+ arrange = { arrange: arrangeList, ...this.query }
|
|
|
+ }
|
|
|
+ // raceList:淘汰赛的比赛赛程
|
|
|
+ raceList = raceList.map(i => {
|
|
|
+ const { groundModelName, refereeModelName, timeModelName, ...others } = i
|
|
|
+ return { ...others, ...this.query }
|
|
|
+ })
|
|
|
+ // 创建安排
|
|
|
+ let res
|
|
|
+ if (arrange._id) {
|
|
|
+ res = await app.$post(`/newCourt/api/eliminatArrange/${arrange._id}`, arrange)
|
|
|
+ if (app.$checkRes(res)) {
|
|
|
+ console.log('淘汰赛安排创建成功')
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ res = await app.$post(`/newCourt/api/eliminatArrange`, arrange)
|
|
|
+ if (app.$checkRes(res)) {
|
|
|
+ console.log('淘汰赛安排创建成功')
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ res = await app.$post('/newCourt/api/eliminateRace/saveAll', raceList)
|
|
|
+ wx.showToast({
|
|
|
+ title: '保存成功',
|
|
|
+ })
|
|
|
}
|
|
|
-})
|
|
|
+
|
|
|
+});
|