目录
一、技术栈说明(轻量易部署)
二、环境准备
三、完整代码实现
1. 后端主文件 app.py
2. 前端模板文件夹及文件
(1)登录页面 login.html
(2)计算器页面 calculator.html
四、代码核心部分解释
1. 登录验证逻辑
2. Web 版计算逻辑
3. 前端页面设计
五、运行与使用步骤
六、扩展建议(可选)
总结
基于 Python Flask 框架的带登录功能的 Web 版利率计算器,支持通过浏览器访问、登录验证,登录后可输入本金、利率、计息期数,选择单利 / 复利计算并实时显示结果。以下是完整的实现方案,包含前端页面(登录页 + 计算器页)和后端逻辑,代码可直接运行,适合新手部署和使用。
一、技术栈说明(轻量易部署)
- 后端:Python + Flask(轻量级 Web 框架,无需复杂配置,新手友好)
- 前端:HTML + 简单 CSS(无需前端框架,页面简洁易用)
- 登录验证:基于 Flask Session 的简单用户名密码验证(演示用,可扩展为数据库存储)
- 核心功能:复用单利 / 复利计算逻辑,适配 Web 表单提交
二、环境准备
首先安装 Flask 依赖(打开终端 / 命令行执行):
pip install flask三、完整代码实现
创建一个文件夹(如interest_calculator),在其中新建 2 个文件:
1. 后端主文件app.py
python
运行
from flask import Flask, render_template, request, session, redirect, url_for, flash import math # 初始化Flask应用 app = Flask(__name__) # 配置Session密钥(必须,用于登录状态保存) app.secret_key = "interest_calc_2026_secure_key" # 实际使用可替换为随机字符串 # 内置测试用户(演示用,实际可替换为数据库查询) VALID_USERS = { "admin": "123456", "user1": "user123" } # 登录验证装饰器(保护计算器页面,未登录则跳转到登录页) def login_required(f): def wrapper(*args, **kwargs): if "username" not in session: flash("请先登录后再使用计算器!", "warning") return redirect(url_for("login")) return f(*args, **kwargs) wrapper.__name__ = f.__name__ return wrapper # 利率计算核心函数 def calculate_interest(principal, rate, periods, interest_type="simple"): """ 计算单利/复利的利息和本息和 :param principal: 本金(元) :param rate: 年利率(百分比,如5表示5%) :param periods: 计息期数(年) :param interest_type: 计息方式(simple=单利,compound=复利) :return: 利息(保留2位小数)、本息和(保留2位小数) """ rate = rate / 100 # 转换为小数 if interest_type == "simple": total = principal * (1 + rate * periods) else: total = principal * math.pow((1 + rate), periods) interest = total - principal return round(interest, 2), round(total, 2) # 路由1:登录页面(GET请求显示页面,POST请求验证登录) @app.route("/login", methods=["GET", "POST"]) def login(): # 如果已登录,直接跳转到计算器页面 if "username" in session: return redirect(url_for("calculator")) if request.method == "POST": username = request.form.get("username") password = request.form.get("password") # 验证用户名密码 if username in VALID_USERS and VALID_USERS[username] == password: session["username"] = username # 保存登录状态到Session flash(f"登录成功!欢迎 {username}", "success") return redirect(url_for("calculator")) else: flash("用户名或密码错误,请重新输入!", "danger") # GET请求显示登录页面 return render_template("login.html") # 路由2:计算器页面(需登录才能访问) @app.route("/calculator", methods=["GET", "POST"]) @login_required def calculator(): result = None # 存储计算结果 if request.method == "POST": try: # 获取表单输入 principal = float(request.form.get("principal")) rate = float(request.form.get("rate")) periods = int(request.form.get("periods")) interest_type = request.form.get("interest_type") # 校验输入合法性 if principal <= 0: flash("本金金额必须大于0!", "danger") elif rate < 0 or rate > 100: flash("年利率需在0-100之间(如5表示5%)!", "danger") elif periods <= 0: flash("计息期数必须大于0!", "danger") else: # 计算利息 interest, total = calculate_interest(principal, rate, periods, interest_type) # 组装结果数据 result = { "principal": round(principal, 2), "rate": rate * 100, # 转回百分比显示 "periods": periods, "interest_type": "单利" if interest_type == "simple" else "复利", "interest": interest, "total": total } flash("计算成功!", "success") except ValueError: flash("输入错误!请输入有效的数字!", "danger") # 渲染计算器页面,传递登录用户名和计算结果 return render_template("calculator.html", username=session["username"], result=result) # 路由3:退出登录 @app.route("/logout") @login_required def logout(): session.pop("username", None) # 清除登录状态 flash("已成功退出登录!", "success") return redirect(url_for("login")) # 路由4:首页(重定向到登录页) @app.route("/") def index(): return redirect(url_for("login")) # 启动应用 if __name__ == "__main__": app.run(debug=True, host="0.0.0.0", port=5000)2. 前端模板文件夹及文件
在interest_calculator文件夹下新建templates子文件夹,再在其中创建 2 个 HTML 文件:
(1)登录页面login.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>利率计算器 - 登录</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: Arial, sans-serif; } body { background-color: #f5f5f5; display: flex; justify-content: center; align-items: center; min-height: 100vh; } .login-box { background: white; padding: 30px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); width: 400px; } .login-box h2 { text-align: center; margin-bottom: 20px; color: #333; } .form-group { margin-bottom: 15px; } .form-group label { display: block; margin-bottom: 5px; color: #666; } .form-group input { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; } .btn { width: 100%; padding: 10px; background-color: #007bff; color: white; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; } .btn:hover { background-color: #0056b3; } .alert { padding: 10px; margin-bottom: 15px; border-radius: 4px; font-size: 14px; } .alert-danger { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } </style> </head> <body> <div class="login-box"> <h2>利率计算器 - 用户登录</h2> <!-- 显示提示信息 --> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} <div class="alert alert-{{ category }}">{{ message }}</div> {% endfor %} {% endif %} {% endwith %} <!-- 登录表单 --> <form method="POST"> <div class="form-group"> <label for="username">用户名</label> <input type="text" id="username" name="username" required placeholder="请输入用户名(测试:admin)"> </div> <div class="form-group"> <label for="password">密码</label> <input type="password" id="password" name="password" required placeholder="请输入密码(测试:123456)"> </div> <button type="submit" class="btn">登录</button> </form> </div> </body> </html>(2)计算器页面calculator.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>利率计算器 - 主页</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: Arial, sans-serif; } body { background-color: #f5f5f5; padding: 20px; } .container { max-width: 600px; margin: 0 auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .header h2 { color: #333; } .header a { color: #dc3545; text-decoration: none; font-size: 14px; } .form-group { margin-bottom: 15px; } .form-group label { display: block; margin-bottom: 5px; color: #666; } .form-group input, .form-group select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; } .btn { padding: 10px 20px; background-color: #007bff; color: white; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; } .btn:hover { background-color: #0056b3; } .alert { padding: 10px; margin-bottom: 15px; border-radius: 4px; font-size: 14px; } .alert-success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .alert-danger { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .alert-warning { background-color: #fff3cd; color: #856404; border: 1px solid #ffeeba; } .result { margin-top: 20px; padding: 20px; background-color: #e9f7fe; border-radius: 4px; display: none; } .result.show { display: block; } .result h3 { margin-bottom: 10px; color: #333; } .result p { margin: 5px 0; font-size: 16px; color: #666; } .result p span { font-weight: bold; color: #007bff; } </style> </head> <body> <div class="container"> <div class="header"> <h2>欢迎 {{ username }} | 利率计算器</h2> <a href="/logout">退出登录</a> </div> <!-- 显示提示信息 --> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} <div class="alert alert-{{ category }}">{{ message }}</div> {% endfor %} {% endif %} {% endwith %} <!-- 计算器表单 --> <form method="POST"> <div class="form-group"> <label for="principal">本金金额(元)</label> <input type="number" id="principal" name="principal" step="0.01" required placeholder="请输入大于0的金额,如10000.00"> </div> <div class="form-group"> <label for="rate">年利率(%)</label> <input type="number" id="rate" name="rate" step="0.01" required placeholder="请输入0-100之间的数值,如4.5"> </div> <div class="form-group"> <label for="periods">计息期数(年)</label> <input type="number" id="periods" name="periods" min="1" required placeholder="请输入大于0的整数,如3"> </div> <div class="form-group"> <label for="interest_type">计息方式</label> <select id="interest_type" name="interest_type" required> <option value="simple">单利</option> <option value="compound">复利</option> </select> </div> <button type="submit" class="btn">计算</button> </form> <!-- 计算结果展示 --> {% if result %} <div class="result show"> <h3>计算结果</h3> <p>本金:<span>{{ result.principal }}</span> 元</p> <p>年利率:<span>{{ result.rate }}</span> %</p> <p>计息期数:<span>{{ result.periods }}</span> 年</p> <p>计息方式:<span>{{ result.interest_type }}</span></p> <p>到期利息:<span>{{ result.interest }}</span> 元</p> <p>到期本息和:<span>{{ result.total }}</span> 元</p> </div> {% endif %} </div> </body> </html>四、代码核心部分解释
1. 登录验证逻辑
- 用
Flask Session保存登录状态,login_required装饰器确保未登录用户无法访问计算器页面; - 内置测试用户(
admin/123456、user1/user123),实际使用可替换为数据库(如 SQLite/MySQL)查询; - 登录失败 / 成功通过
flash提示用户,提升交互体验。
2. Web 版计算逻辑
- 复用之前的单利 / 复利计算函数,适配 Web 表单的 POST 提交方式;
- 前端表单添加
required属性强制输入,后端额外校验数值合法性(如本金 > 0、利率 0-100); - 计算结果通过模板变量传递到前端,格式化显示(保留 2 位小数)。
3. 前端页面设计
- 登录页 / 计算器页均做了简单样式优化,适配浏览器显示;
- 提示信息分类展示(成功 / 危险 / 警告),结果区域仅在计算后显示,界面更整洁。
五、运行与使用步骤
- 确保文件结构正确:
plaintext
interest_calculator/ ├── app.py └── templates/ ├── login.html └── calculator.html- 运行
app.py(终端执行):
python app.py- 打开浏览器,访问
http://localhost:5000(或http://你的IP:5000,局域网内其他设备也可访问); - 登录:输入测试用户名
admin,密码123456,点击 “登录”; - 使用计算器:输入本金(如 10000)、年利率(如 4.5)、期数(如 3),选择计息方式,点击 “计算”,即可看到结果。
六、扩展建议(可选)
- 持久化用户:将用户信息存入 SQLite/MySQL 数据库,替代内置字典;
- 记住登录状态:添加 “记住我” 功能,延长 Session 有效期;
- 更多计息方式:支持按月 / 按日计息,增加 “计息周期” 选择项;
- 数据导出:将计算结果导出为 Excel/CSV 文件;
- 样式优化:使用 Bootstrap 框架美化页面,适配手机端。
总结
- 核心功能:实现了浏览器登录验证 + 利率计算,支持单利 / 复利,输入合法性校验,结果清晰展示;
- 易用性:基于 Flask 的轻量级架构,代码结构清晰,新手可快速部署和修改;
- 扩展性:预留了扩展接口(如数据库、更多计息方式),可根据需求升级。
整个应用无需复杂的服务器配置,本地运行即可满足个人 / 小团队使用,完全适配 “浏览器登录 + 利率计算” 的核心需求。