1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
| import csv import os import pandas as pd import matplotlib.pyplot as plt from datetime import datetime
RECORD_FILE = "my_accounts.csv" CATEGORY_RULES = { "餐饮": ["吃饭", "外卖", "餐厅", "咖啡", "奶茶", "快餐", "食堂", "美食"], "交通": ["打车", "地铁", "公交", "滴滴", "加油", "停车", "高铁", "机票"], "购物": ["淘宝", "京东", "拼多多", "购物", "衣服", "鞋子", "包包", "化妆品"], "娱乐": ["电影", "游戏", "KTV", "演唱会", "旅游", "门票", "健身", "会员"], "生活缴费": ["水电费", "电费", "水费", "燃气", "话费", "网费", "房租", "物业"], "人情往来": ["红包", "礼物", "礼金", "请客", "聚餐", "随礼"], "医疗保健": ["医院", "药店", "看病", "体检", "买药", "医疗"], "学习提升": ["买书", "课程", "培训", "学习", "考试", "资料"], "工资收入": ["工资", "薪水", "薪资", "奖金"], "其他收入": ["红包", "转账", "退款", "副业"] }
MONTHLY_BUDGET = { "餐饮": 2000, "交通": 800, "购物": 1500, "娱乐": 1000, "生活缴费": 1500, "人情往来": 800, "医疗保健": 500, "学习提升": 500, "其他支出": 500 }
def init_file(): if not os.path.exists(RECORD_FILE): with open(RECORD_FILE, 'w', newline='', encoding='utf-8') as f: csv.writer(f).writerow(['日期', '类型', '分类', '金额', '备注']) print("📁 初始化记账文件...")
def auto_category(note, trans_type): note = note.lower() if trans_type == "收入": check_cats = {"工资收入": CATEGORY_RULES["工资收入"], "其他收入": CATEGORY_RULES["其他收入"]} else: check_cats = {k: v for k, v in CATEGORY_RULES.items() if "收入" not in k} for cat, keywords in check_cats.items(): for kw in keywords: if kw in note: return cat return "其他支出" if trans_type == "支出" else "其他收入"
def add_record(): print("\n" + "=" * 40) print("📝 添加新记录") print("=" * 40) while True: t = input("类型(1-收入,2-支出): ").strip() if t in ["1", "2"]: trans_type = "收入" if t == "1" else "支出" break print("请输入1或2!") while True: try: amount = float(input("金额: ").strip()) if amount > 0: break print("金额必须大于0!") except: print("请输入数字!") note = input("备注(如:午饭外卖): ").strip() category = auto_category(note, trans_type) print(f"📌 自动分类: {category}") with open(RECORD_FILE, 'a', newline='', encoding='utf-8') as f: csv.writer(f).writerow([ datetime.now().strftime('%Y-%m-%d'), trans_type, category, amount, note ]) print("✅ 保存成功!") if trans_type == "支出": input("\n按回车键查看预算使用情况...") check_budget()
def view_records(): """查看历史记录""" print("\n" + "=" * 40) print("📋 历史记录") print("=" * 40) try: df = pd.read_csv(RECORD_FILE, encoding='utf-8') df['日期'] = pd.to_datetime(df['日期']) df = df.sort_values('日期', ascending=False) print(f"\n{'日期':<12} {'类型':<4} {'分类':<8} {'金额':>8} {'备注'}") print("-" * 60) for _, r in df.iterrows(): print(f"{r['日期'].strftime('%m-%d'):<12} {r['类型']:<4} {r['分类']:<8} ¥{r['金额']:>7.2f} {r['备注']}") except: print("暂无记录!")
def check_budget(): """检查预算""" try: df = pd.read_csv(RECORD_FILE, encoding='utf-8') df['日期'] = pd.to_datetime(df['日期']) df_this_month = df[df['日期'].dt.strftime('%Y-%m') == datetime.now().strftime('%Y-%m')] df_expense = df_this_month[df_this_month['类型'] == '支出'] expense_by_cat = df_expense.groupby('分类')['金额'].sum() print("\n💰 本月预算使用情况:\n") for cat, budget in MONTHLY_BUDGET.items(): spent = expense_by_cat.get(cat, 0) rate = (spent / budget * 100) if budget else 0 bar = "█" * int(min(rate, 100) / 5) + "░" * (20 - int(min(rate, 100) / 5)) print(f"{cat:>8}: [{bar}] {rate:>5.1f}% (¥{spent:.0f}/¥{budget:.0f})") except Exception as e: print(f"检查失败: {e}")
def report(): """生成报表""" try: df = pd.read_csv(RECORD_FILE, encoding='utf-8') df['日期'] = pd.to_datetime(df['日期']) current_month = datetime.now().strftime('%Y-%m') df_this = df[df['日期'].dt.strftime('%Y-%m') == current_month] if df_this.empty: print("本月暂无数据!") return income = df_this[df_this['类型'] == '收入']['金额'].sum() expense = df_this[df_this['类型'] == '支出']['金额'].sum() balance = income - expense print("\n" + "=" * 40) print(f"📊 {current_month} 收支总览") print("=" * 40) print(f"总收入: ¥{income:10,.2f}") print(f"总支出: ¥{expense:10,.2f}") print(f"净结余: ¥{balance:10,.2f}") expense_by_cat = df_this[df_this['类型'] == '支出'].groupby('分类')['金额'].sum() if not expense_by_cat.empty: plt.figure(figsize=(12, 5)) plt.subplot(1, 2, 1) plt.pie(expense_by_cat.values, labels=expense_by_cat.index, autopct='%1.1f%%') plt.title('支出分类') plt.subplot(1, 2, 2) daily = df_this[df_this['类型'] == '支出'].groupby(df['日期'].dt.day)['金额'].sum() plt.plot(daily.index, daily.values, marker='o') plt.title('每日支出趋势') plt.xlabel('日期') plt.ylabel('金额') plt.grid(True) plt.tight_layout() plt.savefig(f'{current_month}_report.png', dpi=150, bbox_inches='tight') print(f"\n✅ 图表已保存: {current_month}_report.png") plt.show() except Exception as e: print(f"生成报表失败: {e}")
def main(): """主菜单""" init_file() while True: print("\n" + "=" * 50) print("智能记账本") print("=" * 50) print("1. 添加新记录") print("2. 查看历史记录") print("3. 预算使用情况") print("4. 生成本月报表") print("5. 退出") print("=" * 50) choice = input("请选择功能(1-5): ").strip() if choice == "1": add_record() elif choice == "2": view_records() elif choice == "3": check_budget() elif choice == "4": report() elif choice == "5": print("👋 感谢使用,再见!") break else: print("请输入1-5之间的数字!")
if __name__ == "__main__": main()
|