更新配置修改页面

This commit is contained in:
ahao 2025-03-21 18:25:47 +08:00
parent ddcc65c9fd
commit 98d5b36996
9 changed files with 302 additions and 3 deletions

View File

@ -4,6 +4,7 @@
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="table_game" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="bootstrap" level="application" />
</component>
<component name="PyNamespacePackagesService">
<option name="namespacePackageFolders">

View File

@ -2,7 +2,7 @@ screen -S backend
conda activate tabel_game_admin
uvicorn backend.app.main:app --reload --host 127.0.0.1
uvicorn backend.app.main:app --reload --host 127.0.0.1 --reload-include backend/config.conf

View File

@ -21,6 +21,7 @@ from .routers import admin_message
from .routers import user_messages
from .routers import bell
from .routers import admin_strategy
from .routers import admin_congif
@ -64,6 +65,9 @@ app.include_router(admin_message.router, prefix="/admin", tags=["Admin-Message"]
app.include_router(admin_strategy.router, prefix="/admin", tags=["Admin-Strategy"])
app.include_router(admin_congif.router, prefix="/admin", tags=["Admin-Config"])

View File

@ -0,0 +1,59 @@
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from ..services.admin_config_service import (
get_price_config,
get_night_config,
update_points_rate,
update_get_points_rate,
update_night_start,
update_night_end,
update_price_minutes
)
from ..services.admin_table_service import _verify_admin_permission
router = APIRouter()
class UpdatePointsRateRequest(BaseModel):
token: str
points_rate: float
class UpdateNightTimeRequest(BaseModel):
token: str
time: str # 格式:"HH:MM:SS"
class UpdatePriceMinutesRequest(BaseModel):
token: str
price_minutes: int
@router.get("/config/price")
def get_price_config_api():
return get_price_config()
@router.get("/config/night")
def get_night_config_api():
return get_night_config()
@router.post("/config/points-rate")
def update_points_rate_api(request: UpdatePointsRateRequest):
_verify_admin_permission(request.token)
return update_points_rate(request.points_rate)
@router.post("/config/get-points-rate")
def update_get_points_rate_api(request: UpdatePointsRateRequest):
_verify_admin_permission(request.token)
return update_get_points_rate(request.points_rate)
@router.post("/config/night-start")
def update_night_start_api(request: UpdateNightTimeRequest):
_verify_admin_permission(request.token)
return update_night_start(request.time)
@router.post("/config/night-end")
def update_night_end_api(request: UpdateNightTimeRequest):
_verify_admin_permission(request.token)
return update_night_end(request.time)
@router.post("/config/price-minutes")
def update_price_minutes_api(request: UpdatePriceMinutesRequest):
_verify_admin_permission(request.token)
return update_price_minutes(request.price_minutes)

View File

@ -0,0 +1,80 @@
import configparser
from pathlib import Path
from fastapi import HTTPException
config_path = Path("backend/config.conf")
def _save_config(config):
try:
with open(config_path, 'w') as configfile:
config.write(configfile)
except Exception as e:
raise HTTPException(500, f"配置保存失败: {str(e)}")
def get_price_config():
config = configparser.ConfigParser()
config.read(config_path)
return {
"points_rate": float(config.get("price", "points_rate")),
"get_points_rate": float(config.get("price", "get_points_rate"))
}
def get_night_config():
config = configparser.ConfigParser()
config.read(config_path)
return {
"start_time": config.get("stay_up_late", "start_time"),
"end_time": config.get("stay_up_late", "end_time"),
"price_minutes": int(config.get("stay_up_late", "price_minutes"))
}
def update_points_rate(new_rate: float):
config = configparser.ConfigParser()
config.read(config_path)
config.set("price", "points_rate", str(new_rate))
_save_config(config)
return {"message": "积分抵扣率更新成功"}
def update_get_points_rate(new_rate: float):
config = configparser.ConfigParser()
config.read(config_path)
config.set("price", "get_points_rate", str(new_rate))
_save_config(config)
return {"message": "积分获取率更新成功"}
def update_night_start(new_time: str):
# 添加时间格式验证
try:
from datetime import datetime
datetime.strptime(new_time, "%H:%M:%S")
except ValueError:
raise HTTPException(400, "时间格式应为 HH:MM:SS")
config = configparser.ConfigParser()
config.read(config_path)
config.set("stay_up_late", "start_time", new_time)
_save_config(config)
return {"message": "晚场开始时间更新成功"}
def update_night_end(new_time: str):
# 同样添加时间验证
try:
from datetime import datetime
datetime.strptime(new_time, "%H:%M:%S")
except ValueError:
raise HTTPException(400, "时间格式应为 HH:MM:SS")
config = configparser.ConfigParser()
config.read(config_path)
config.set("stay_up_late", "end_time", new_time)
_save_config(config)
return {"message": "晚场结束时间更新成功"}
def update_price_minutes(minutes: int):
if minutes <= 0:
raise HTTPException(400, "分钟数必须大于0")
config = configparser.ConfigParser()
config.read(config_path)
config.set("stay_up_late", "price_minutes", str(minutes))
_save_config(config)
return {"message": "计费分钟间隔更新成功"}

View File

@ -20,6 +20,7 @@ def create_app():
from frontend.routes.coupons import coupons_bp
from frontend.routes.messages import messages_bp
from frontend.routes.strategies import strategies_bp
from frontend.routes.config import config_bp
app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False
toolbar = DebugToolbarExtension(app)
@ -36,6 +37,7 @@ def create_app():
app.register_blueprint(coupons_bp)
app.register_blueprint(messages_bp)
app.register_blueprint(strategies_bp)
app.register_blueprint(config_bp)
# 添加自定义过滤器
@app.template_filter('datetime')

58
frontend/routes/config.py Normal file
View File

@ -0,0 +1,58 @@
from flask import Blueprint, render_template, session, redirect, url_for, flash, request
import requests
from frontend.config import Config
config_bp = Blueprint('config', __name__, url_prefix='/admin/config')
@config_bp.route('/manage', methods=['GET', 'POST'])
def manage_config():
if not session.get('token'):
return redirect(url_for('auth.login'))
# 获取所有配置
price_resp = requests.get(f"{Config.BASE_API_URL}/admin/config/price")
night_resp = requests.get(f"{Config.BASE_API_URL}/admin/config/night")
config = {
'price': price_resp.json() if price_resp.status_code == 200 else {},
'night': night_resp.json() if night_resp.status_code == 200 else {}
}
print(config)
if request.method == 'POST':
field = request.form.get('field')
value = request.form.get('value')
# 定义所有配置项的API端点映射
endpoints = {
'points_rate': '/points-rate',
'get_points_rate': '/get-points-rate',
'start_time': '/night-start',
'end_time': '/night-end',
'price_minutes': '/price-minutes'
}
# 构建请求参数
json_data = {"token": session['token']}
if field in ['points_rate', 'get_points_rate']:
json_data[field] = float(value)
elif field in ['start_time', 'end_time']:
json_data['time' if field in ['start_time', 'end_time'] else field] = value
else:
json_data[field] = int(value)
resp = requests.post(
f"{Config.BASE_API_URL}/admin/config{endpoints[field]}",
json=json_data
)
if resp.status_code == 200:
flash("配置更新成功", "success")
else:
error_detail = resp.json().get('detail', '未知错误')
flash(f"更新失败: {error_detail}", "danger")
return redirect(url_for('config.manage_config'))
return render_template('config/manage.html', config=config)

View File

@ -4,7 +4,7 @@
<meta charset="utf-8">
<title>{% block title %}桌游厅点单系统管理后台{% endblock %}</title>
<!-- Bootstrap CSS -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.2/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
font-family: Arial, sans-serif;
@ -78,6 +78,13 @@
<li class="nav-item">
<a class="nav-link" href="{{ url_for('strategies.list_strategies') }}">策略管理</a>
</li>
<!-- 修改导航项为单个入口 -->
<li class="nav-item">
<a class="nav-link" href="{{ url_for('config.manage_config') }}">
<i class="fas fa-cog"></i> 系统配置
</a>
</li>
{% endif %}
</ul>
{% if session.token %}
@ -109,7 +116,7 @@
<script>
// 建立全局WebSocket连接
const adminWS = new WebSocket(`ws://192.168.5.16:8000/bell/ws/admin`);
const adminWS = new WebSocket(`ws://127.0.0.1:8000/bell/ws/admin`); // 修复WebSocket地址
// 处理接收到的消息
adminWS.onmessage = function (event) {

View File

@ -0,0 +1,88 @@
{% extends "base.html" %}
{% block title %}系统配置管理{% endblock %}
{% block content %}
<div class="container mt-4">
<div class="row">
<!-- 价格配置 -->
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header bg-primary text-white">价格配置</div>
<div class="card-body">
<form method="post">
<div class="form-group">
<label>积分获取</label>
<div class="form-text text-muted" style="font-size: 0.9em;">
订单价格乘以该数后保留整数位为获取的积分值
</div>
<input type="number" step="0.01" name="value"
value="{{ config.price.points_rate }}"
class="form-control" required>
<input type="hidden" name="field" value="points_rate">
</div>
<button type="submit" class="btn btn-primary btn-block">更新</button>
</form>
<hr>
<form method="post">
<div class="form-group">
<label>每个积分可以抵扣价格</label>
<input type="number" step="0.01" name="value"
value="{{ config.price.get_points_rate }}"
class="form-control" required>
<input type="hidden" name="field" value="get_points_rate">
</div>
<button type="submit" class="btn btn-primary btn-block">更新</button>
</form>
</div>
</div>
</div>
<!-- 晚场配置 -->
<div class="col-md-6">
<div class="card mb-4">
<div class="card-header bg-info text-white">晚场配置</div>
<div class="card-body">
<form method="post">
<div class="form-group">
<label>开始时间</label>
<input type="time" step="1" name="value"
value="{{ config.night.start_time }}"
class="form-control" required>
<input type="hidden" name="field" value="start_time">
</div>
<button type="submit" class="btn btn-info btn-block">更新</button>
</form>
<hr>
<form method="post">
<div class="form-group">
<label>结束时间</label>
<input type="time" step="1" name="value"
value="{{ config.night.end_time }}"
class="form-control" required>
<input type="hidden" name="field" value="end_time">
</div>
<button type="submit" class="btn btn-info btn-block">更新</button>
</form>
<hr>
<form method="post">
<div class="form-group">
<label>每小时收取</label>
<input type="number" name="value"
value="{{ config.night.price_minutes }}"
class="form-control" min="1" required>
<input type="hidden" name="field" value="price_minutes">
</div>
<button type="submit" class="btn btn-info btn-block">更新</button>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}