diff --git a/README.md b/README.md index ad2af7f..7bd96ee 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,17 @@ curl -X PUT http://localhost:5000/api/admin/turnover \ --data-binary @revenue.csv ``` +## 本地运行(默认数据库路径) +- 默认数据库:`sqlite:///data/data.db`(项目根目录下的 `data/data.db`) +- 启动: + ```powershell + $env:PORT=57778; $env:ADMIN_TOKEN="<你的口令>"; python backend/app.py + ``` +- 自定义路径(Windows 绝对路径示例): + ```powershell + $env:DATABASE_URL="sqlite:////e:/2025Code/python/YixuanYingye/data/data.db"; python backend/app.py + ``` + ## 环境优化(最优解) - 基础镜像切换为 `python:3.11-alpine`,构建更快、体积更小 - 依赖安装走腾讯云 PyPI 镜像:`PIP_INDEX_URL=https://mirrors.cloud.tencent.com/pypi/simple` diff --git a/app.log b/app.log new file mode 100644 index 0000000..9f3c858 --- /dev/null +++ b/app.log @@ -0,0 +1 @@ +准备发送消息: 【益选便利店】2025-12-07的营业额:2408.7 diff --git a/backend/app.py b/backend/app.py index d42336d..6a4d52f 100644 --- a/backend/app.py +++ b/backend/app.py @@ -18,13 +18,21 @@ import io load_dotenv() app = Flask(__name__, static_folder="../frontend", static_url_path="/static") CORS(app) -app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("DATABASE_URL", "sqlite:///data.db") +app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("DATABASE_URL", "sqlite:///data/data.db") def _ensure_sqlite_dir(url): if not url.startswith('sqlite:'): return p = url if p.startswith('sqlite:////'): - db_path = p.replace('sqlite:////', '/') + db_path = p.replace('sqlite:////', '') + if db_path[1:3] == ':/' or db_path[1:3] == ':\\': + # path like 'E:/...' with a leading slash + pass + elif db_path[0:2] == ':/': + # unlikely + db_path = db_path[1:] + # Normalize Windows backslashes + db_path = db_path.replace('/', os.sep) elif p.startswith('sqlite:///'): db_path = os.path.join(os.getcwd(), p.replace('sqlite:///', '')) else: @@ -95,13 +103,24 @@ def daily_job(): existing.source = existing.source or 'generator' db.session.commit() return - amount = generate_mock_revenue() + amount = gen_amount_for_date(today, cfg) rev = DailyRevenue(date=today, amount=amount, is_final=True, source='generator') db.session.add(rev) db.session.add(AuditLog(date=today, old_amount=None, new_amount=amount, reason='daily_generate', actor='system', type='generate')) db.session.commit() _append_log_line(today.isoformat(), amount, shop_name) +def settle_today_if_due(): + cfg = load_config() + cutoff = cfg.get("cutoff_hour", 23) + try: + cutoff = int(cutoff) + except Exception: + cutoff = 23 + if datetime.now().hour < cutoff: + return + daily_job() + # ---- 日志解析与聚合 ---- def load_config(): cfg_path = os.path.join(os.path.dirname(__file__), "..", "config.json") @@ -349,6 +368,7 @@ if __name__ == "__main__": with app.app_context(): sync_log_to_db() auto_import_csv_on_start() + settle_today_if_due() app.run(host="0.0.0.0", port=int(os.getenv("PORT", "5000"))) @app.route('/api/events') @@ -358,7 +378,8 @@ def sse_events(): now = datetime.now() payload = {"type": "tick", "server_now": now.isoformat(timespec='seconds')} yield f"data: {json.dumps(payload)}\n\n" - if now.hour == 23 and now.minute == 1: + if now.minute in (0, 1): + settle_today_if_due() yield "data: {\"type\": \"force_refresh\"}\n\n" time.sleep(30) return Response(stream_with_context(event_stream()), mimetype='text/event-stream') diff --git a/data/data.db b/data/data.db new file mode 100644 index 0000000..e69de29 diff --git a/instance/data.db b/instance/data.db index 256e248..49d7409 100644 Binary files a/instance/data.db and b/instance/data.db differ