Skip to content

最终结果

| 这是最终的结果,后面当我们学完使用pip,你就可以跑跑看了

python

import json
import os
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
from collections import defaultdict

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

class PersonalFinanceSystem:
    def __init__(self, data_file="personal_finance.json"):
        self.data_file = data_file
        self.data = self.load_data()
    
    def load_data(self):
        """加载数据"""
        if os.path.exists(self.data_file):
            try:
                with open(self.data_file, 'r', encoding='utf-8') as f:
                    return json.load(f)
            except Exception as e:
                print(f"加载数据失败: {e}")
        
        # 返回默认数据结构
        return {
            "transactions": [],
            "categories": {
                "income": ["工资", "兼职", "投资", "奖金", "其他收入"],
                "expense": ["住房", "餐饮", "交通", "娱乐", "购物", "医疗", "教育", "其他支出"]
            },
            "budgets": {},
            "savings_goal": 10000,
            "created_date": datetime.now().isoformat()
        }
    
    def save_data(self):
        """保存数据"""
        try:
            with open(self.data_file, 'w', encoding='utf-8') as f:
                json.dump(self.data, f, ensure_ascii=False, indent=2)
            return True
        except Exception as e:
            print(f"保存数据失败: {e}")
            return False
    
    def add_transaction(self, amount, category, description, transaction_type):
        """添加交易记录"""
        transaction = {
            "id": len(self.data["transactions"]) + 1,
            "amount": float(amount),
            "category": category,
            "description": description,
            "type": transaction_type,
            "date": datetime.now().isoformat()
        }
        
        self.data["transactions"].append(transaction)
        if self.save_data():
            print(f"✓ 成功添加{transaction_type}记录")
            return True
        return False
    
    def get_financial_summary(self):
        """获取财务摘要"""
        total_income = sum(t["amount"] for t in self.data["transactions"] if t["type"] == "income")
        total_expense = sum(t["amount"] for t in self.data["transactions"] if t["type"] == "expense")
        balance = total_income - total_expense
        
        return {
            "total_income": total_income,
            "total_expense": total_expense,
            "balance": balance,
            "savings_rate": (balance / total_income * 100) if total_income > 0 else 0
        }
    
    def analyze_spending_by_category(self):
        """按类别分析支出"""
        category_spending = defaultdict(float)
        for transaction in self.data["transactions"]:
            if transaction["type"] == "expense":
                category_spending[transaction["category"]] += transaction["amount"]
        
        return dict(category_spending)
    
    def generate_visual_report(self):
        """生成可视化报告"""
        summary = self.get_financial_summary()
        spending_by_category = self.analyze_spending_by_category()
        
        # 创建多个子图
        fig, axes = plt.subplots(2, 2, figsize=(15, 12))
        fig.suptitle('个人财务分析报告', fontsize=16, fontweight='bold')
        
        # 1. 收支对比饼图
        if summary["total_income"] > 0:
            income_vs_expense = [summary["total_income"], summary["total_expense"]]
            axes[0,0].pie(income_vs_expense, 
                         labels=['收入', '支出'], 
                         autopct='%1.1f%%', 
                         colors=['#4CAF50', '#F44336'])
            axes[0,0].set_title('收入 vs 支出比例')
        
        # 2. 支出分类饼图
        if spending_by_category:
            categories = list(spending_by_category.keys())
            amounts = list(spending_by_category.values())
            axes[0,1].pie(amounts, labels=categories, autopct='%1.1f%%')
            axes[0,1].set_title('支出分类')
        
        # 3. 财务概览柱状图
        metrics = ['总收入', '总支出', '余额']
        values = [summary["total_income"], summary["total_expense"], summary["balance"]]
        colors = ['green', 'red', 'blue']
        bars = axes[1,0].bar(metrics, values, color=colors, alpha=0.7)
        axes[1,0].set_title('财务概览')
        axes[1,0].set_ylabel('金额 (元)')
        
        # 在柱子上添加数值标签
        for bar, value in zip(bars, values):
            axes[1,0].text(bar.get_x() + bar.get_width()/2, bar.get_height() + 50,
                          f'{value:.0f}元', ha='center', va='bottom')
        
        # 4. 储蓄进度
        savings_goal = self.data.get("savings_goal", 10000)
        current_savings = max(0, summary["balance"])
        progress = min(current_savings / savings_goal * 100, 100)
        
        axes[1,1].barh(['储蓄进度'], [progress], color='lightgreen')
        axes[1,1].set_xlim(0, 100)
        axes[1,1].set_xlabel('完成百分比 (%)')
        axes[1,1].set_title(f'储蓄目标: {savings_goal}\n当前进度: {progress:.1f}%')
        axes[1,1].text(progress/2, 0, f'{current_savings:.0f}元', 
                      ha='center', va='center', fontweight='bold')
        
        plt.tight_layout()
        plt.savefig('financial_analysis_report.png', dpi=300, bbox_inches='tight')
        plt.show()
    
    def display_menu(self):
        """显示主菜单"""
        print("\n" + "="*50)
        print("           个人财务分析系统")
        print("="*50)
        print("1. 添加收入记录")
        print("2. 添加支出记录")
        print("3. 查看财务摘要")
        print("4. 查看支出分类")
        print("5. 生成可视化报告")
        print("6. 查看所有交易")
        print("7. 退出系统")
        print("="*50)
    
    def run(self):
        """运行系统"""
        print("欢迎使用个人财务分析系统!")
        
        while True:
            self.display_menu()
            choice = input("请选择操作 (1-7): ").strip()
            
            if choice == '1':
                self.add_income()
            elif choice == '2':
                self.add_expense()
            elif choice == '3':
                self.show_summary()
            elif choice == '4':
                self.show_spending_by_category()
            elif choice == '5':
                self.generate_visual_report()
            elif choice == '6':
                self.show_all_transactions()
            elif choice == '7':
                print("感谢使用个人财务分析系统!")
                break
            else:
                print("无效选择,请重新输入!")
    
    def add_income(self):
        """添加收入"""
        print("\n--- 添加收入记录 ---")
        amount = input("收入金额: ")
        print("收入类别:")
        for i, category in enumerate(self.data["categories"]["income"], 1):
            print(f"  {i}. {category}")
        
        cat_choice = input("选择类别编号: ")
        try:
            category = self.data["categories"]["income"][int(cat_choice)-1]
        except (ValueError, IndexError):
            category = input("输入自定义类别: ")
        
        description = input("收入说明: ")
        
        if self.add_transaction(amount, category, description, "income"):
            print("✓ 收入记录添加成功!")
    
    def add_expense(self):
        """添加支出"""
        print("\n--- 添加支出记录 ---")
        amount = input("支出金额: ")
        print("支出类别:")
        for i, category in enumerate(self.data["categories"]["expense"], 1):
            print(f"  {i}. {category}")
        
        cat_choice = input("选择类别编号: ")
        try:
            category = self.data["categories"]["expense"][int(cat_choice)-1]
        except (ValueError, IndexError):
            category = input("输入自定义类别: ")
        
        description = input("支出说明: ")
        
        if self.add_transaction(amount, category, description, "expense"):
            print("✓ 支出记录添加成功!")
    
    def show_summary(self):
        """显示财务摘要"""
        summary = self.get_financial_summary()
        
        print("\n" + "="*40)
        print("          财务摘要")
        print("="*40)
        print(f"总收入:   {summary['total_income']:>10.2f} 元")
        print(f"总支出:   {summary['total_expense']:>10.2f} 元")
        print(f"当前余额: {summary['balance']:>10.2f} 元")
        print(f"储蓄率:   {summary['savings_rate']:>9.1f} %")
        print("="*40)
        
        if summary['balance'] > 0:
            print("财务状况: 良好 ✓")
        else:
            print("财务状况: 需要关注 ⚠")
    
    def show_spending_by_category(self):
        """显示支出分类"""
        spending = self.analyze_spending_by_category()
        
        if not spending:
            print("暂无支出记录")
            return
        
        print("\n--- 支出分类统计 ---")
        total_spending = sum(spending.values())
        for category, amount in sorted(spending.items(), key=lambda x: x[1], reverse=True):
            percentage = (amount / total_spending * 100) if total_spending > 0 else 0
            print(f"{category:<8}: {amount:>8.2f} 元 ({percentage:>5.1f}%)")
    
    def show_all_transactions(self):
        """显示所有交易"""
        if not self.data["transactions"]:
            print("暂无交易记录")
            return
        
        print("\n--- 所有交易记录 ---")
        for transaction in self.data["transactions"]:
            date = datetime.fromisoformat(transaction["date"]).strftime("%Y-%m-%d")
            type_icon = "↑" if transaction["type"] == "income" else "↓"
            color = "32" if transaction["type"] == "income" else "31"  # 绿色/红色
            print(f"\033[{color}m{type_icon} [{date}] {transaction['category']}: {transaction['amount']:.2f}元 - {transaction['description']}\033[0m")

# 运行系统
if __name__ == "__main__":
    system = PersonalFinanceSystem()
    system.run()

Released under the MIT License.