一直以来，本人有个痛点，就是手持太多vps。有月付的，年付的，半年的，季付的。 各种结算货币。完全无统一标准。导致财务管理困难。所以就诞生了这个工具简单易用，只需要把如下代码保存到任意.py文件并且在cmd运行即可。python xx.py程序会自动在相同目录创建vps_cost_config.json文件用作数据存储。感谢：chatgptimport tkinter as tk from tkinter import messagebox, ttk # 引入 ttk 组件，界面更美观 import json # =============== 配置文件相关 =============== CONFIG_FILE_PATH = "vps_cost_config.json" default_exchange_rates = {'USD': 1, 'CNY': 7.1, 'EUR': 0.85} def load_config(): try: with open(CONFIG_FILE_PATH, 'r') as file: return json.load(file) except FileNotFoundError: return {'exchange_rates': default_exchange_rates, 'vps_list': []} def save_config(config): with open(CONFIG_FILE_PATH, 'w') as file: json.dump(config, file, indent=4) # =============== 功能函数 =============== def update_exchange_rates(): try: exchange_rates = {currency: float(var.get()) for currency, var in currency_rate_vars.items()} config['exchange_rates'] = exchange_rates save_config(config) update_vps_list() update_monthly_costs() messagebox.showinfo("成功", "汇率已更新并保存。") except ValueError: messagebox.showerror("错误", "请输入有效的数字汇率。") def add_vps(): try: name = vps_name_var.get() amount = float(amount_var.get()) vps = { 'name': name, 'payment_cycle': payment_cycle_var.get(), 'amount': amount, 'currency': currency_var.get() } config['vps_list'].append(vps) save_config(config) update_vps_list() clear_vps_fields() update_monthly_costs() except ValueError: messagebox.showerror("错误", "请输入有效的费用。") def delete_vps(): selected = vps_listbox.curselection() if not selected: messagebox.showerror("错误", "请选择一个 VPS 项目删除。") return selected_name = vps_listbox.get(selected).split(' ')[0] config['vps_list'] = [v for v in config['vps_list'] if v['name'] != selected_name] save_config(config) update_vps_list() update_monthly_costs() def update_vps_list(): vps_listbox.delete(0, tk.END) for vps in config['vps_list']: vps_listbox.insert(tk.END, f"{vps['name']} ({vps['payment_cycle']}) - {vps['amount']} {vps['currency']}") def update_monthly_costs(): monthly_costs, total_cost = calculate_monthly_cost(config['vps_list'], config['exchange_rates']) monthly_cost_display.config(state="normal") monthly_cost_display.delete("1.0", tk.END) max_name_length = max(len(name) for name in monthly_costs.keys()) # 获取最长名字长度 separator = '-' * 40 # 分隔符 for name, cost in monthly_costs.items(): # 价格右对齐，名字用固定宽度 formatted_line = f"{name.ljust(max_name_length)} | {str(cost).rjust(8)} CNY\n" monthly_cost_display.insert(tk.END, formatted_line) monthly_cost_display.insert(tk.END, f"{separator}\n") monthly_cost_display.insert(tk.END, f"{'月度总成本'.ljust(max_name_length)} | {str(total_cost).rjust(8)} CNY") monthly_cost_display.config(state="disabled") def calculate_monthly_cost(vps_list, rates): total_cost = 0.0 costs = {} for vps in vps_list: amount = vps['amount'] / {'annual': 12, 'semi-annual': 6, 'quarterly': 3, 'monthly': 1}[vps['payment_cycle']] cost = round(amount * rates.get(vps['currency'], 1), 2) costs[vps['name']] = cost total_cost += cost return costs, round(total_cost, 2) def clear_vps_fields(): vps_name_var.set("") amount_var.set("") payment_cycle_var.set("annual") currency_var.set("USD") # =============== 主窗口与布局 =============== root = tk.Tk() root.title("VPS 成本管理") root.geometry("900x600") # 窗口大小 config = load_config() # =========== 左侧：汇率设置 =========== left_frame = tk.LabelFrame(root, text="汇率设置", padx=10, pady=10) left_frame.pack(fill="y", side="left", padx=10, pady=10) currency_rate_vars = {} for idx, (currency, rate) in enumerate(config['exchange_rates'].items()): tk.Label(left_frame, text=f"{currency} 汇率:").grid(row=idx, column=0, sticky="e", pady=5) rate_var = tk.StringVar(value=str(rate)) currency_rate_vars[currency] = rate_var tk.Entry(left_frame, textvariable=rate_var, width=10).grid(row=idx, column=1, pady=5) tk.Button(left_frame, text="更新汇率", command=update_exchange_rates).grid(columnspan=2, pady=10) # =========== 中间：VPS 管理 =========== middle_frame = tk.LabelFrame(root, text="VPS 管理", padx=10, pady=10) middle_frame.pack(fill="both", expand=True, side="left", padx=10, pady=10) vps_name_var, amount_var = tk.StringVar(), tk.StringVar() payment_cycle_var, currency_var = tk.StringVar(value="annual"), tk.StringVar(value="USD") # 输入框 tk.Label(middle_frame, text="名称:").grid(row=0, column=0, sticky="e") tk.Entry(middle_frame, textvariable=vps_name_var).grid(row=0, column=1, pady=5) tk.Label(middle_frame, text="费用:").grid(row=1, column=0, sticky="e") tk.Entry(middle_frame, textvariable=amount_var).grid(row=1, column=1, pady=5) tk.Label(middle_frame, text="周期:").grid(row=2, column=0, sticky="e") ttk.Combobox(middle_frame, textvariable=payment_cycle_var, values=["annual", "semi-annual", "quarterly", "monthly"]).grid(row=2, column=1) tk.Label(middle_frame, text="货币:").grid(row=3, column=0, sticky="e") ttk.Combobox(middle_frame, textvariable=currency_var, values=["USD", "CNY", "EUR"]).grid(row=3, column=1) tk.Button(middle_frame, text="添加 VPS", command=add_vps).grid(columnspan=2, pady=10) # 列表框 vps_listbox = tk.Listbox(middle_frame, width=45, height=15) vps_listbox.grid(row=5, columnspan=2, pady=10) tk.Button(middle_frame, text="删除选中", command=delete_vps).grid(columnspan=2, pady=5) # =========== 右侧：成本展示 =========== right_frame = tk.LabelFrame(root, text="每月成本", padx=10, pady=10) right_frame.pack(fill="y", side="right", padx=10, pady=10) monthly_cost_display = tk.Text(right_frame, width=42, height=40, state="disabled") monthly_cost_display.pack() # 初始化显示 update_vps_list() update_monthly_costs() root.mainloop()