From 339f8211e4824a1c0c9c0619d12e61a0910ef2fc Mon Sep 17 00:00:00 2001 From: houhuan Date: Sun, 7 Dec 2025 23:55:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BB=8A=E6=97=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 +++++++++++ app.log | 1 + backend/app.py | 29 +++++++++++++++++++++++++---- data/data.db | 0 instance/data.db | Bin 61440 -> 65536 bytes 5 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 app.log create mode 100644 data/data.db 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 256e248a6d20a75c45a5e16a8520c8dcd4018050..49d7409dde51198d0e0a36c22f38c5ae2024a4ab 100644 GIT binary patch delta 444 zcmZp8z}(QlGC`V^kAZes=l{U}ivP)G34!DM zia=4$JRrf_7zre~8})#sKqE7dWb*|Qtm>N-7!^4A&oZbper90&JekYEmvbtk6~ldo z7KWCIjVha41acXpA{fIMIT;k$9XTDP8H@~!Omz*7bPdcM7F|pO0fdNxp@EfwrIn$v zp0TBcxv3eljH#8OiIuU5o`s2tiJ5V7eo;|sa>-_Ip(b7ypi7J=U-UQTQ)6mjVE({7 zmD!5vK2ytNjsU04ApwR=n_C5rGj8??*`Y0^$l}Vtewn?3U6$<-TRIyL>qgcvmftK3 zSX?J_H0W&hYWTyvIXU1Z^Je{ytM1Gi%zBgAFZeSt>uqej#uOFam<{pP&Pu3f+4~?Muz6bn>#L7$guMQJtE4{I+?ve Xg?%QcEyqKS){Tw99Gf>cRI>vBuF-n6 delta 212 zcmZo@U}<>3JVBb3hk=2Cf1-jtBhSW!CHx|+{7--a4E+4R`M>dh;D5#cgg0QbgurqB z$@l$PWq>lgjgdf-yHO8FayBvpNwx?e!K$-Kfl+}I$kJhGVcdWVr_E$+`jRT+APsr!reH-Dhgq91>v2v^k^gIOArYkR94A+61^