如何用vue+免费的webdb 实现一个世界杯足球竞猜系统

一、前言
最近世界杯在如火如荼的进行。我们都知道,中国也派出了我们的一支强大的队伍:中国建筑队,全程参与了世界杯的所有比赛。

哈哈开个玩笑,不过说到世界杯,还真有不少朋友,不仅仅是看球,还切身参与了。比如足彩,世界杯竞猜等等活动。

那么今天我们就通过kintone来自己实现一个世界杯竞猜系统吧!

二、视频学习
开始学习前,可以先来看看本文的视频“如何用vue+免费的web db,来实现一个世界杯足球竞猜系统”,可以帮助你更好的理解本文的思路,更能提高学习的效率。配合着视频我们快来学习吧!

三、功能梳理
想要实现的功能如下:

用户竞猜前台:

1 每个人拥有自己独立的积分

2 有比赛列表,赔付率信息。能实现各自投票。

3 有个人信息界面,列出我的积分,往期竞猜信息及结果。

竞猜系统后台:

1 可以录入比赛信息,赔付率信息。可以到期进行开奖。

2 可以查询用户的竞猜信息。

3 用户的积分变化有迹可查。

四、效果图

五、如何实现?
效果看完了,那这个世界杯竞猜系统是如何通过kintone实现的呢?

1、应用准备
这个世界杯竞猜系统可以简单通过以下应用进行搭建

1 球队信息应用:

记录球队名,球队国旗等。

2 比赛信息应用:

记录比赛的两支球队,场次,该场比分,赔付率等。

3 用户竞猜信息应用:

记录用户id,他的竞猜的比赛场次,胜负,竞猜使用的积分等。

4 积分变更履历应用:

记录用户积分变化的履历,每个场次押注所获得或者付出的积分。

5 轮播图应用

记录一些比赛精彩图片,美化页面。

2、系统开发
接下来分享下这个系统是如何开发的。

整个投注系统使用Vue3框架来实现。

引入根节点

首先通过kintone的 JS API来获取门户上方的空白部分的元素 kintone.portal.getContentSpaceElement(),将其作为根节点。这样就能把Vue产生的页面挂载到这个根结点上。同时可以引入Pinia作为集中式状态管理,Element UI 作为我们的UI框架。

1
2
3
4
5
6
7
8
9
10
11
12
13
import { createApp } from "vue";
import App from "./App.vue";
import installElementPlus from "@/libs/element";
import { createPinia } from "pinia";
/* eslint-disable */
kintone.events.on("portal.show", (event) => {
    const myContainer = kintone.portal.getContentSpaceElement();
    const app = createApp(App);
    installElementPlus(app);
    app.use(createPinia());
    app.mount(myContainer);
    return event;
});

准备数据源,获取数据

然后通过kintone的REST API就能将kintone各个应用中的数据取出来,并在页面上进行展示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { KintoneRestAPIClient } from "@kintone/rest-api-client";
const client = new KintoneRestAPIClient();
 
//获取比赛列表
export const GetMatchList = async () => {
    const app = appList.matchInfo;
    import {appList,matchInfoField,usersField,userChipInField,picField} from "@/config";
    try {
        const params = {
            app,
        };
        const resp = await client.record.getRecords(params);
        if (resp.records.length > 0) {
        return resp.records.map((record) => {
            return dataConvert(record);
        });
        else {
            return null;
        }
    catch (err) {
        console.log(err);
    }
};

多语言开发

同时通过kintone.getLoginUser()我们可以获取到当前登陆用户的信息。其中包含了他的语言信息。根据语言信息,我们可以配置I18N做多语言的开发。

1
2
const { language } = kintone.getLoginUser();
//   'language': 'zh'

集中式状态管理

可以将用户的剩余积分,比赛下注信息等写入集中式状态管理,因为他可能会在多页面进行响应式变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import {
  GetLeftScore,
  GetChipInList,
  GetMatchList,
} from "@/services/kintoneApi";
import { defineStore } from "pinia";
 
export const useStore = defineStore("store", {
  state: () => {
    return {
      myScore: 0,
      chipInList: [],
    };
  },
 
  getters: {
    chipListShow(state) {
      return state.chipInList.map((record) => {
        if (record.Score_result == 0) {
          record.scoreWin = "--";
          record.teamInfo.Score = "--";
          record.type = "chip in";
        else if (record.Score_result < 0) {
          record.scoreWin = `--`;
          record.type = "loss";
        else {
          record.scoreWin = `+ ${record.Score_result}`;
          record.type = "win";
        }
        return record;
      });
    },
  },
 
  actions: {
    async init() {
      const initLeftScorePromise = this.getLeftScore();
      const initChipInListPromise = this.getChipInList();
      return Promise.all([initLeftScorePromise, initChipInListPromise]);
    },
 
    async getLeftScore() {
      this.myScore = await GetLeftScore();
    },
 
    async getChipInList() {
      const chipInList = await GetChipInList();
      const matches = await GetMatchList();
      const matchMapping = {};
      for (const item of matches) {
        matchMapping[item.Match_id] = {
          FlagA: item.FlagA,
          FlagB: item.FlagB,
          TeamA_name: item.TeamA_name,
          TeamB_name: item.TeamB_name,
          Score: `${item.ScoreA}:${item.ScoreB}`,
        };
      }
      chipInList.map((chip) => {
        chip.teamInfo = matchMapping[chip.Match_id];
        return chip;
      });
      this.chipInList = chipInList;
    },
  },
});

竞猜系统整体说明

首先是可以通过管理员给每个用户录入一些初始积分,用户有了积分可以进行比赛的胜负平的竞猜。比赛场次,胜负平赔付率可以通过取出后台数据后进行展示。

当用户进行竞猜后,会将记录写入用户竞猜信息应用。同时还可以计算出用户的剩余积分,用户的竞猜列表等。

开奖系统整体说明

开奖系统可以直接对比赛信息应用进行自定义开发。

当比赛结束出来结果后,管理员可以录入比分,自动计算出比赛结果。然后可以一键开奖,系统自动计算出哪些用户猜对了比赛,并且通过赔付率计算出他所获得的积分。并且写入到用户的积分履历中去。

开发上的注意点

因为这里没有后端系统,所以可能存在用户自行通过伪造请求等方式生成投票数据。这样就有可能出现:

1 帮别人投票,让别人无分可投

2 让自己的投票超出自己的积分

3 比赛结束后进行投票

等等一系列的问题。那这边如何一一化解呢?

1 伪造别人投票:可以通过应用的创建者字段来实现。因为这个字段是系统后端自动生成,所以不再有这个困扰。

2 让自己的投票超出自己的积分:为防止这种篡改积分的情况,这里将用户的竞猜列表和积分列表分开。竞猜列表用户有读写权限,但是积分列表用户只有读取权限。

通过kintone的权限设置,普通登录用户都是只读权限,没有修改权限。然后通过管理员用户的开奖系统对用户的竞猜进行审核。过滤后,由管理员进行修改(当然这些都是代码自动实现的。)

比如判断用户的投票时,会先计算出他当前没有开奖的投票总数是否大于他剩余的积分。这样就能防止他是否会进行伪造投票。

3 超过时间的投票:通过kintone自带的更新时间字段(这是用户无法自行修改的特点),判断用户该条投票记录的更新时间是否超过该场比赛的投票截止时间,就能过滤掉用户的超时伪造投票。

经过以上种种的判断,就能很好的避免了用户伪造的数据,让这次投票无需服务器,也能变得安全可靠了。

代码分享

参考:https://cybozudev.kf5.com/hc/kb/article/1588162/

视频参考:https://www.bilibili.com/video/BV1Q841157A3/

posted @ 2022-12-07 10:21  cybozu开发者  阅读(252)  评论(0编辑  收藏  举报