feat: 完善项目架构并增强分析页面功能
- 新增项目文档和 Docker 配置 - 添加 README.md 和 TODO.md 项目文档 - 为各服务添加 Dockerfile 和 docker-compose 配置 - 重构后端架构 - 新增 adapter 层(HTTP/Python 适配器) - 新增 repository 层(数据访问抽象) - 新增 router 模块统一管理路由 - 新增账单处理 handler - 扩展前端 UI 组件库 - 新增 Calendar、DateRangePicker、Drawer、Popover 等组件 - 集成 shadcn-svelte 组件库 - 增强分析页面功能 - 添加时间范围筛选器(支持本月默认值) - 修复 DateRangePicker 默认值显示问题 - 优化数据获取和展示逻辑 - 完善分析器服务 - 新增 FastAPI 服务接口 - 改进账单清理器实现
This commit is contained in:
@@ -60,6 +60,8 @@ class AlipayCleaner(BaseCleaner):
|
||||
print(f"\n处理结果:")
|
||||
print(f" 全额退款删除: {self.stats['fully_refunded']} 条")
|
||||
print(f" 部分退款调整: {self.stats['partially_refunded']} 条")
|
||||
if self.stats.get("zero_amount", 0) > 0:
|
||||
print(f" 0元记录过滤: {self.stats['zero_amount']} 条")
|
||||
print(f" 最终保留行数: {len(final_rows)}")
|
||||
|
||||
# 第五步:重新分类并添加"需复核"标注
|
||||
@@ -134,7 +136,11 @@ class AlipayCleaner(BaseCleaner):
|
||||
self.stats["partially_refunded"] += 1
|
||||
print(f" 部分退款: {row[0]} | {row[2]} | 原{expense_amount}元 -> {format_amount(remaining)}元")
|
||||
else:
|
||||
final_rows.append(row)
|
||||
# 过滤掉金额为 0 的记录(预下单/加购物车等无效记录)
|
||||
if expense_amount > 0:
|
||||
final_rows.append(row)
|
||||
else:
|
||||
self.stats["zero_amount"] = self.stats.get("zero_amount", 0) + 1
|
||||
else:
|
||||
final_rows.append(row)
|
||||
|
||||
|
||||
@@ -85,6 +85,58 @@ def compute_date_range(args) -> tuple[date | None, date | None]:
|
||||
return start_date, end_date
|
||||
|
||||
|
||||
def compute_date_range_from_values(
|
||||
year: str = None,
|
||||
month: str = None,
|
||||
start: str = None,
|
||||
end: str = None
|
||||
) -> tuple[date | None, date | None]:
|
||||
"""
|
||||
根据参数值计算日期范围(不依赖 argparse)
|
||||
供 HTTP API 调用使用
|
||||
|
||||
Returns:
|
||||
(start_date, end_date) 或 (None, None) 表示不筛选
|
||||
"""
|
||||
start_date = None
|
||||
end_date = None
|
||||
|
||||
# 1. 根据年份设置范围
|
||||
if year:
|
||||
y = int(year)
|
||||
start_date = date(y, 1, 1)
|
||||
end_date = date(y, 12, 31)
|
||||
|
||||
# 2. 根据月份进一步收窄
|
||||
if month:
|
||||
m = int(month)
|
||||
y = int(year) if year else datetime.now().year
|
||||
|
||||
if not start_date:
|
||||
start_date = date(y, 1, 1)
|
||||
end_date = date(y, 12, 31)
|
||||
|
||||
month_start = date(y, m, 1)
|
||||
if m == 12:
|
||||
month_end = date(y, 12, 31)
|
||||
else:
|
||||
month_end = date(y, m + 1, 1) - timedelta(days=1)
|
||||
|
||||
start_date = max(start_date, month_start) if start_date else month_start
|
||||
end_date = min(end_date, month_end) if end_date else month_end
|
||||
|
||||
# 3. 根据 start/end 参数进一步收窄
|
||||
if start:
|
||||
custom_start = parse_date(start)
|
||||
start_date = max(start_date, custom_start) if start_date else custom_start
|
||||
|
||||
if end:
|
||||
custom_end = parse_date(end)
|
||||
end_date = min(end_date, custom_end) if end_date else custom_end
|
||||
|
||||
return start_date, end_date
|
||||
|
||||
|
||||
def is_in_date_range(date_str: str, start_date: date | None, end_date: date | None) -> bool:
|
||||
"""检查日期字符串是否在指定范围内"""
|
||||
if start_date is None and end_date is None:
|
||||
|
||||
@@ -58,6 +58,8 @@ class WechatCleaner(BaseCleaner):
|
||||
print(f"\n处理结果:")
|
||||
print(f" 全额退款删除: {self.stats['fully_refunded']} 条")
|
||||
print(f" 部分退款调整: {self.stats['partially_refunded']} 条")
|
||||
if self.stats.get("zero_amount", 0) > 0:
|
||||
print(f" 0元记录过滤: {self.stats['zero_amount']} 条")
|
||||
print(f" 保留支出条目: {len(final_expense_rows)} 条")
|
||||
print(f" 保留收入条目: {len(income_rows)} 条")
|
||||
|
||||
@@ -177,7 +179,11 @@ class WechatCleaner(BaseCleaner):
|
||||
if merchant in transfer_refunds:
|
||||
del transfer_refunds[merchant]
|
||||
else:
|
||||
final_expense_rows.append((row, None))
|
||||
# 过滤掉金额为 0 的记录(预下单/加购物车等无效记录)
|
||||
if original_amount > 0:
|
||||
final_expense_rows.append((row, None))
|
||||
else:
|
||||
self.stats["zero_amount"] = self.stats.get("zero_amount", 0) + 1
|
||||
|
||||
return final_expense_rows, income_rows
|
||||
|
||||
|
||||
Reference in New Issue
Block a user