基于Python的运动计费管理系统

动机

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

技术路线规划

模块名 语言 备注
管理核心 Python 使用JSON存储信息
Web后端 Python Flask框架
Web前端 HTML Jinja框架渲染

实现

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

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

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

需要的方法有:

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

代码如下

# -*- 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存在则读取状态,否则创建

    def UserExsist(self, UserID):
        return os.path.exists("./Users/%s.json" % UserID)

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

    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文件

    def LoadUserInfo(self, UserID):
        with open("./Users/%s.json" % UserID, "r") as jsonfile:
            return json.load(jsonfile)

从JSON文件中载入用户状态

    def PlayOneTime(self, Pay):
        self.UserInfo["num"] += 1
        self.UserInfo["balance"] = self.UserInfo["balance"] - Pay

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

    def Recharge(self, Pay):
        self.UserInfo["balance"] += Pay

充值,费用加上指定值

    def DeleteUser(self):
        os.remove("./Users/%s.json" % self.UserInfo["id"])

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

    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框架构造,代码如下

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():返回已经存在的用户状态列表
@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关系相同
app.run(host="0.0.0.0")

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

Web前端

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

  • index界面



    index


    

羽毛球运动管理系统

{% for user_id in user_list -%} {%- endfor %}
用户 次数 余额
{{user_list[user_id]["name"]}} {{user_list[user_id]["num"]}} {{user_list[user_id]["balance"]}}

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

    


超链接部分,用于导航

  • register界面



    register


    

羽毛球运动管理系统--注册

name id
back to index

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

  • recharge界面



    recharge


    

羽毛球运动管理系统--充值

recharge¥
back to index

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

  • pay界面



    pay


    

羽毛球运动管理系统--消费

{%for userid in user_list%} {{user_list[userid]["name"]}}
{% endfor %}
pay¥
back to index

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

  • back界面



    back


    back to index


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

你可能感兴趣的:(基于Python的运动计费管理系统)