lrf 2 years ago
parent
commit
e562a3d9a6

+ 322 - 46
pages/eliminate/add.js

@@ -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: '保存成功',
+        })
     }
-})
+
+});

+ 7 - 2
pages/eliminate/add.json

@@ -1,6 +1,11 @@
 {
     "component": true,
     "usingComponents": {
-      "mobile-main": "/commpents/mobile-frame/index"
+        "mobile-main": "/commpents/mobile-frame/index",
+        "f6-tree": "/commpents/f6tree/index",
+        "van-popup": "@vant/weapp/popup/index",
+        "van-picker": "@vant/weapp/picker/index",
+        "f-picker": "/commpents/picker/index",
+        "f-time-picker": "/commpents/timePicker/index"
     }
-  }
+}

+ 0 - 1
pages/eliminate/add.less

@@ -4,7 +4,6 @@
     .zero {
         width: 96vw;
         margin: 0 0 2vw 0;
-        background-color: #ff0000;
     }
 
     .zero:last-child {

+ 29 - 1
pages/eliminate/add.wxml

@@ -1,7 +1,35 @@
 <mobile-main frameStyle="{{frameStyle}}" bind:back="back" bind:tabPath="tabPath">
     <view slot="info" class="container main">
         <view class="zero one">
-            赛程管理
+            <view wx:if="{{view==='graph'}}">
+                <view>
+                    <button bind:tap="toAutoInitData" wx:if="{{!arrangeData._id}}">自动生成</button>
+                    <button bind:tap="turnView" data-view="race">设置比赛</button>
+                    <!-- <button>保存</button> -->
+                </view>
+                <f6-tree list="{{data}}" arrange="{{arrangeList}}" bind:tapNode="nodeTap"></f6-tree>
+                <view>
+                    <van-popup show="{{ show }}" bind:close="toClose" position="bottom" custom-style="height: 40%;">
+                        <van-picker columns="{{ personList }}" bind:confirm="onChange" value-key="label" show-toolbar="{{true}}" bind:cancel="toClose" />
+                    </van-popup>
+                </view>
+            </view>
+            <view wx:if="{{view==='race'}}">
+                <view>
+                    <button bind:tap="turnView" data-view="graph">返回</button>
+                    <button bind:tap="toSubmit">保存</button>
+                </view>
+                <view>
+                    <view wx:for="{{raceList}}" wx:for-item="r" wx:key="node_one_id">
+                        {{r.player_name_one}} VS {{r.player_name_two}}
+                        <f-picker value="{{r.ground_id}}" label="场地" model="{{r.groundModelName}}" bind:selected="toSelected" columns="{{groundList}}" valueKey="_id" labelKey="name">
+                        </f-picker>
+                        <f-picker value="{{r.referee_id}}" label="裁判" model="{{r.refereeModelName}}" bind:selected="toSelected" columns="{{refereeList}}" valueKey="_id" labelKey="name">
+                        </f-picker>
+                        <f-time-picker label="比赛时间" model="{{r.timeModelName}}" value="{{r.match_time}}" bind:selected="toSelected" />
+                    </view>
+                </view>
+            </view>
         </view>
     </view>
 </mobile-main>

+ 0 - 1
pages/eliminate/add.wxss

@@ -4,7 +4,6 @@
 .main .zero {
   width: 96vw;
   margin: 0 0 2vw 0;
-  background-color: #ff0000;
 }
 .main .zero:last-child {
   margin: 0;

+ 7 - 5
pages/f6test/index.js

@@ -2,13 +2,13 @@ const app = getApp()
 
 Page({
     query: {
-        "grouping_id": "62e601c72dc7343e137fff6f",
-        "match_id": "62e388d4fd61d871861b80af",
-        "project_id": "62e5fff82dc7343e137ffef5"
+        // "grouping_id": "62e601c72dc7343e137fff6f",
+        // "match_id": "62e388d4fd61d871861b80af",
+        // "project_id": "62e5fff82dc7343e137ffef5"
     },
     data: {
         view: 'graph',
-        frameStyle: { useTop: true, name: '注册', leftArrow: false, useBar: false },
+        frameStyle: { useTop: true, name: '淘汰赛管理', leftArrow: false, useBar: false },
         canvasWidth: 375,
         canvasHeight: 600,
         pixelRatio: 1,
@@ -179,7 +179,9 @@ Page({
     },
 
 
-    async onLoad() {
+    async onLoad(options) {
+        const { match_id, grouping_id, project_id } = options
+        this.query = { match_id, grouping_id, project_id }
         await this.getTeams()
         // 设置初始的晋级图
         const data = this.computedTreeData();