前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于Python的运动计费管理系统动机技术路线规划实现

基于Python的运动计费管理系统动机技术路线规划实现

作者头像
月见樽
发布2018-04-27 11:35:02
8100
发布2018-04-27 11:35:02
举报

动机

小伙伴们最近迷恋上羽毛球,组织了个小群,办了公用的运动卡用于开场,考虑不是每次活动都是全员参与,需要一个计费的系统来计算每个人需要交的费用。商讨后决定采用“预充-扣费”的方式,则需要一个系统进行计费和扣费。

技术路线规划

模块名

语言

备注

管理核心

Python

使用JSON存储信息

Web后端

Python

Flask框架

Web前端

HTML

Jinja框架渲染

实现

核心模块——用户状态管理

该部分是整个计费系统的核心,用于管理每个用户的余额。使用一个类表示用户,需要的属性为

  • 状态列表(用户名,ID,使用次数,余额)

需要的方法有:

  • 创建用户(创建新的JSON文件)
  • 读取用户状态(从已有的JSON文件中)
  • 扣费(使用次数增加1,余额减小)
  • 充值(余额增加)
  • 保存状态(将现有的状态写入JSON文件)

代码如下

代码语言:javascript
复制
# -*- coding: utf-8 -*-
import json
import os


class UserHanlde(object):
    """docstring for UserHanlde"""

    def __init__(self, UserID, UserName=""):
        super(UserHanlde, self).__init__()
        if self.UserExsist(UserID):
            self.UserInfo = self.LoadUserInfo(UserID)
        else:
            self.UserInfo = self.CreateNewUser(UserName, UserID)

构造函数,若该用户ID存在则读取状态,否则创建

代码语言:javascript
复制
    def UserExsist(self, UserID):
        return os.path.exists("./Users/%s.json" % UserID)

判断该ID的JSON文件是否存在

代码语言:javascript
复制
    def CreateNewUser(self, UserName, UserID):
        UserInfo = {
            "name": UserName,
            "id": UserID,
            "num": 0,
            "balance": 50
        }
        with open("./Users/%s.json" % UserID, "w") as jsonfile:
            json.dump(UserInfo, jsonfile, ensure_ascii=False, indent=4)
        return UserInfo

创建新用户,将初始余额设为50并保存JSON文件

代码语言:javascript
复制
    def LoadUserInfo(self, UserID):
        with open("./Users/%s.json" % UserID, "r") as jsonfile:
            return json.load(jsonfile)

从JSON文件中载入用户状态

代码语言:javascript
复制
    def PlayOneTime(self, Pay):
        self.UserInfo["num"] += 1
        self.UserInfo["balance"] = self.UserInfo["balance"] - Pay

扣费,扣除指定的费用并在将扣费次数+1

代码语言:javascript
复制
    def Recharge(self, Pay):
        self.UserInfo["balance"] += Pay

充值,费用加上指定值

代码语言:javascript
复制
    def DeleteUser(self):
        os.remove("./Users/%s.json" % self.UserInfo["id"])

删除用户,删除指定的JSON文件

代码语言:javascript
复制
    def SaveInfo(self):
        with open("./Users/%s.json" % self.UserInfo["id"], "w") as jsonfile:
            json.dump(self.UserInfo, jsonfile, ensure_ascii=False, indent=4)

保存状态,将当前状态写入对应的JSON文件

Web后端

web后端使用Python的Flask框架构造,代码如下

代码语言:javascript
复制
from flask import Flask, render_template, request
from UserHanlde import UserHanlde
import os
app = Flask(__name__)


def GetUserIDList():
    return [x[:-5] for x in os.listdir("./Users") if ".json" in x]

def GetUserInfoList():
    UserInfoList = dict()
    for UserID in GetUserIDList():
        UserData = UserHanlde(UserID)
        UserInfoList[UserID] = UserData.UserInfo
    return UserInfoList

常用部分的封装:

  • GetUserIDList():返回已经存在的用户ID列表
  • GetUserInfoList():返回已经存在的用户状态列表
代码语言:javascript
复制
@app.route("/index")
def ViewInfo():
    return render_template("index.html", user_list=GetUserInfoList())


@app.route("/recharge")
def GetReChargeInfo():
    return render_template("recharge.html", user_list=GetUserInfoList())


@app.route("/recharge_handle", methods=["GET", "POST"])
def Recharge():
    UserID = request.values.get("id")
    UserRecharge = request.values.get("pay")
    if UserRecharge.isdigit() is True:
        UserHanlder = UserHanlde(UserID)
        UserHanlder.Recharge(int(UserRecharge))
        UserHanlder.SaveInfo()
        return render_template("back.html")
    else:
        return "fail"


@app.route("/register")
def GetRegisterInfo():
    return render_template("register.html")


@app.route("/register_handle", methods=["GET", "POST"])
def Register():
    UserID = request.values.get("id")
    UserName = request.values.get("name")
    UserHanlder = UserHanlde(UserID, UserName=UserName)
    return render_template("back.html")


@app.route("/pay")
def GetPayName():
    return render_template("pay.html", user_list=GetUserInfoList())


@app.route("/pay_handle", methods=["GET", "POST"])
def Pay():
    UserIDList = request.values.getlist("vehicle")
    UserIDPay = request.values.get("pay")
    if UserIDPay.isdigit() is True:
        PayNum = int(UserIDPay) / len(UserIDList)
        for UserID in UserIDList:
            UserHanlder = UserHanlde(UserID)
            UserHanlder.PlayOneTime(PayNum)
            UserHanlder.SaveInfo()
        return render_template("back.html")
    else:
        return "fail"

路由部分

  • /index:主页,包括导航和状态显示,所有用户的消费次数和余额将在这里显示
  • /recharge/recharge_handle:充值页面, /recharge为操作页面,用户在这里填写表单数据,随后表单数据被提交到/recharge_handle处理充值业务
  • /register/register_handle:注册页面,与/recharge/recharge_handle关系相同
  • /pay/pay_handle:扣费页面,与/recharge/recharge_handle关系相同
代码语言:javascript
复制
app.run(host="0.0.0.0")

运行,监听所有IP,这样在局域网就可以访问了

Web前端

Web使用HTML代码提供GUI,使用Jinja框架分离数据与模板

  • index界面
代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
    <title>index</title>
</head>
<body>
    <div>
        <h1>羽毛球运动管理系统</h1>
    </div>
    <div>
        <table border="1">
            <thead>
                <tr>
                    <th>用户</th>
                    <th>次数</th>
                    <th>余额</th>
                </tr>
            </thead>
            <tbody>
                {% for user_id in user_list -%}
                <tr>
                    <td>{{user_list[user_id]["name"]}}</td>
                    <td>{{user_list[user_id]["num"]}}</td>
                    <td>{{user_list[user_id]["balance"]}}</td>
                </tr>
                {%- endfor %}
            </tbody>
        </table>
    </div>

用户状态显示,使用for循环生成表格

代码语言:javascript
复制
    <div>
        <a href="register">register</a>
        <a href="recharge">recharge</a>
        <a href="pay">pay</a>
    </div>
</body>
</html>

超链接部分,用于导航

  • register界面
代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
    <title>register</title>
</head>
<body>
    <h1>羽毛球运动管理系统--注册</h1>
    <div>
        <form action="register_handle" method="post" accept-charset="utf-8">
            name<input type="text" name="name">
            id<input type="text" name="id">
            <input type="submit" name="Submit">
        </form>
    </div>
    <a href="/index">back to index</a>
</body>
</html>

使用两个文本输入框表单输入用户名与用户ID

  • recharge界面
代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
    <title>recharge</title>
</head>
<body>
    <div>
        <h1>羽毛球运动管理系统--充值</h1>
    </div>
    <div>
        <form action="recharge_handle" method="post" accept-charset="utf-8">
            <select name="id">
                {% for userid in user_list -%}
                <option value="{{userid}}">{{user_list[userid]["name"]}}</option>
                {%- endfor %}
            </select>
            recharge¥<input type="text" name="pay">
            <input type="submit" name="Submit">
        </form>
    </div>
    <a href="/index">back to index</a>
</body>
</html>

使用下拉菜单提供可供选择的用户名,文本输入充值金额

  • pay界面
代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
    <title>pay</title>
</head>
<body>
    <h1>羽毛球运动管理系统--消费</h1>
    <div>
        <form action="pay_handle" method="post" accept-charset="utf-8">
            <div>
                {%for userid in user_list%}
                <input type="checkbox" name="vehicle" value="{{userid}}">{{user_list[userid]["name"]}}<br>
                {% endfor %}
            </div>
            pay¥<input type="text" name="pay">
            <input type="submit" name="Submit">
        </form>
    </div>
    <a href="/index">back to index</a>
</body>
</html>

使用复选框列出所有用户提供选择,文本输入总输入金额,复选框这种表单数据在后端使用request.values.getlist("name")获取为一个列表

  • back界面
代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
    <title>back</title>
</head>
<body>
    <a href="/index">back to index</a>
</body>
</html>

用户完成充值/注册/消费时用于返回主页

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017.08.12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 动机
  • 技术路线规划
  • 实现
    • 核心模块——用户状态管理
      • Web后端
        • Web前端
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档