modified: main.py

modified:   tools/zhangdan_flask.py
This commit is contained in:
2026-05-17 08:39:01 +08:00
parent 057cfc3292
commit ac548ae29d
2 changed files with 94 additions and 17 deletions
+10 -4
View File
@@ -173,17 +173,23 @@ class MyPlugin(Star):
self.sqllitaa.commit() self.sqllitaa.commit()
cur.close() cur.close()
self.sqllitaa.close() self.sqllitaa.close()
try:
# 删除源文件 # 删除源文件
file_list = os.listdir(f"{self.data_path}") file_list = os.listdir(f"{self.data_path}")
try:
for nam in file_list: for nam in file_list:
if "zhangdan" not in nam: if "zhangdan" not in nam:
os.remove(str(self.data_path)+"\\"+nam) os.remove(str(self.data_path)+"\\"+nam)
file_listaa = os.listdir(f"{self.data_path}/zhangdan/") file_listaa = os.listdir(f"{self.data_path}/zhangdan/")
for namaa in file_listaa: for namaa in file_listaa:
os.remove(str(self.data_path)+"\\zhangdan\\"+namaa) os.remove(str(self.data_path)+"\\zhangdan\\"+namaa)
except IOError as e: except Exception as e:
logger.error(f"文件删除失败 原因{e}") for nam in file_list:
if "zhangdan" not in nam:
os.remove(str(self.data_path)+"/"+nam)
file_listaa = os.listdir(f"{self.data_path}/zhangdan/")
for namaa in file_listaa:
os.remove(str(self.data_path)+"/zhangdan/"+namaa)
yield event.plain_result("保存完成__使用/chazhang 查询最后10条记录") yield event.plain_result("保存完成__使用/chazhang 查询最后10条记录")
except Exception as e: except Exception as e:
yield event.plain_result(f"保存失败{e}") yield event.plain_result(f"保存失败{e}")
@@ -217,7 +223,7 @@ class MyPlugin(Star):
yuju = [] yuju = []
try: try:
if ".csv" in filename: if ".csv" in filename:
ata = pd.read_csv(filename, encoding='GB2312', on_bad_lines='skip',header=22) ata = pd.read_csv(filename, encoding='gb18030', on_bad_lines='skip',header=22)
# 读取表格数据 # 读取表格数据
for biao in range(10): for biao in range(10):
# 暂存当行数据 # 暂存当行数据
+83 -12
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
账单查询服务 - Flask版 账单查询服务 - Flask版
@@ -6,13 +7,17 @@
import sqlite3 import sqlite3
import os import os
import sys
import signal
import hashlib
import secrets import secrets
import threading import threading
import time
from urllib.request import urlopen
from urllib.error import URLError
from flask import Flask, render_template_string, jsonify, request, session, redirect, url_for from flask import Flask, render_template_string, jsonify, request, session, redirect, url_for
from flask_cors import CORS from flask_cors import CORS
# ===== 🔧 常量 ===== # ===== 🔧 常量 =====
PORT = 5001 PORT = 5001
PID_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".flask.pid") PID_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".flask.pid")
@@ -34,7 +39,7 @@ def runwebui(web_port,web_passwd,datadb):
print(e) print(e)
def start_server(host, port, debug): def start_server(host="0.0.0.0", port=PORT, debug=False):
"""在子线程中启动 Flask 服务,主线程不受影响""" """在子线程中启动 Flask 服务,主线程不受影响"""
global _server, _server_thread global _server, _server_thread
@@ -59,7 +64,6 @@ def start_server(host, port, debug):
def stop_server(): def stop_server():
"""只关闭 Flask 子线程,主线程继续运行""" """只关闭 Flask 子线程,主线程继续运行"""
global _server, _server_thread global _server, _server_thread
if _server: if _server:
@@ -93,6 +97,7 @@ def server_status():
app = Flask(__name__) app = Flask(__name__)
app.secret_key = secrets.token_hex(32) app.secret_key = secrets.token_hex(32)
CORS(app) CORS(app)
def check_auth(): def check_auth():
"""检查是否已登录""" """检查是否已登录"""
return session.get("authenticated") is True return session.get("authenticated") is True
@@ -303,12 +308,24 @@ def api_summary():
""", params) """, params)
by_wallet = [dict(r) for r in cur.fetchall()] by_wallet = [dict(r) for r in cur.fetchall()]
# 按交易名称汇总
cur.execute(f"""
SELECT payname, payto,
COUNT(*) as count,
SUM(CAST(paysize AS REAL)) as total
FROM zhangdan {where}
GROUP BY payname, payto
ORDER BY total DESC
""", params)
by_name = [dict(r) for r in cur.fetchall()]
conn.close() conn.close()
return jsonify({ return jsonify({
"overview": overview, "overview": overview,
"by_type": by_type, "by_type": by_type,
"by_channel": by_channel, "by_channel": by_channel,
"by_wallet": by_wallet, "by_wallet": by_wallet,
"by_name": by_name,
}) })
@@ -609,8 +626,12 @@ HTML_TEMPLATE = r"""<!DOCTYPE html>
} }
.summary-item.income { border-left-color: #4ade80; } .summary-item.income { border-left-color: #4ade80; }
.summary-item.expense { border-left-color: #f87171; } .summary-item.expense { border-left-color: #f87171; }
.summary-item .s-label { font-size: 0.9em; } .summary-item .s-left { flex: 1; min-width: 0; }
.summary-item .s-right { text-align: right; flex-shrink: 0; margin-left: 12px; }
.summary-item .s-label { font-size: 0.9em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.summary-item .s-meta { font-size: 0.75em; color: #888; } .summary-item .s-meta { font-size: 0.75em; color: #888; }
.summary-item .s-count { font-size: 1.1em; font-weight: 700; color: #60a5fa; }
.summary-item .s-count span { font-size: 0.7em; font-weight: 400; color: #888; }
.summary-item .s-value { font-weight: 700; font-size: 1.05em; } .summary-item .s-value { font-weight: 700; font-size: 1.05em; }
/* 表格 */ /* 表格 */
@@ -735,6 +756,7 @@ HTML_TEMPLATE = r"""<!DOCTYPE html>
} }
.summary-item { padding: 10px 12px; border-radius: 8px; } .summary-item { padding: 10px 12px; border-radius: 8px; }
.summary-item .s-label { font-size: 0.85em; } .summary-item .s-label { font-size: 0.85em; }
.summary-item .s-count { font-size: 0.95em; }
.summary-item .s-value { font-size: 0.95em; } .summary-item .s-value { font-size: 0.95em; }
/* 表格 */ /* 表格 */
@@ -776,6 +798,7 @@ HTML_TEMPLATE = r"""<!DOCTYPE html>
<div class="tab active" data-tab="type" onclick="switchTab('type')">按类型</div> <div class="tab active" data-tab="type" onclick="switchTab('type')">按类型</div>
<div class="tab" data-tab="channel" onclick="switchTab('channel')">按渠道</div> <div class="tab" data-tab="channel" onclick="switchTab('channel')">按渠道</div>
<div class="tab" data-tab="wallet" onclick="switchTab('wallet')">按钱包</div> <div class="tab" data-tab="wallet" onclick="switchTab('wallet')">按钱包</div>
<div class="tab" data-tab="name" onclick="switchTab('name')">按名称</div>
</div> </div>
<div class="summary-grid" id="summaryGrid"></div> <div class="summary-grid" id="summaryGrid"></div>
@@ -1019,17 +1042,20 @@ function renderSummary(tab) {
let items = []; let items = [];
if (tab === "type") items = summaryData.by_type || []; if (tab === "type") items = summaryData.by_type || [];
else if (tab === "channel") items = summaryData.by_channel || []; else if (tab === "channel") items = summaryData.by_channel || [];
else items = summaryData.by_wallet || []; else if (tab === "wallet") items = summaryData.by_wallet || [];
else if (tab === "name") items = summaryData.by_name || [];
grid.innerHTML = items.map(r => { grid.innerHTML = items.map(r => {
const isIn = r.payto === "收入"; const isIn = r.payto === "收入";
const label = r.paytype || r.payqd || r.paybox || r.payname || "未知";
return `<div class="summary-item ${isIn ? 'income' : 'expense'}"> return `<div class="summary-item ${isIn ? 'income' : 'expense'}">
<div> <div class="s-left">
<div class="s-label">${r.paytype || r.payqd || r.paybox || "未知"}</div> <div class="s-label">${label}</div>
<div class="s-meta">${r.count} 笔 · ${r.payto}</div> <div class="s-meta">${r.payto}</div>
</div> </div>
<div class="s-value" style="color:${isIn ? '#4ade80' : '#f87171'}"> <div class="s-right">
¥${Number(r.total).toFixed(2)} <div class="s-count">${r.count} <span>笔</span></div>
<div class="s-value" style="color:${isIn ? '#4ade80' : '#f87171'}">¥${Number(r.total).toFixed(2)}</div>
</div> </div>
</div>`; </div>`;
}).join(""); }).join("");
@@ -1052,7 +1078,7 @@ function shutdown() {
</div> </div>
</div>`; </div>`;
}) })
.catch(() => alert("关闭失败,请重试")); .catch(() => alert("关闭程序已启动"));
} }
init(); init();
@@ -1060,3 +1086,48 @@ init();
</body> </body>
</html> </html>
""" """
# if __name__ == "__main__":
# command = sys.argv[1] if len(sys.argv) > 1 else "start"
# # ---------- stop ----------
# if command == "stop":
# # 尝试通过 HTTP 调 shutdown 接口
# try:
# urlopen(f"http://localhost:{PORT}/shutdown?token={SHUTDOWN_TOKEN}", timeout=3)
# print("🛑 已发送关闭指令")
# except URLError:
# print("⚠️ 服务未运行或无法连接")
# sys.exit(0)
# # ---------- status ----------
# elif command == "status":
# info = server_status()
# if info["running"]:
# print(f"✅ Flask 服务运行中 → http://localhost:{info['port']}")
# else:
# print("❌ Flask 服务未运行")
# sys.exit(0)
# # ---------- restart ----------
# elif command == "restart":
# stop_server()
# time.sleep(0.5)
# print("🔄 正在重启...")
# # ---------- start (默认) ----------
# elif command != "start":
# print(f"用法: python3 {sys.argv[0]} [start|stop|restart|status]")
# sys.exit(1)
# # 启动 Flask 子线程
# start_server(host="0.0.0.0", port=PORT, debug=True)
# # 主线程继续做其他事(不会被 Flask 阻塞)
# print("📌 主线程继续运行中... (Ctrl+C 退出)")
# try:
# while True:
# time.sleep(1)
# except KeyboardInterrupt:
# print("\n👋 主线程退出")
# stop_server()