一直以来,本人有个痛点,就是手持太多vps。有月付的,年付的,半年的,季付的。 各种结算货币。完全无统一标准。导致财务管理困难。所以就诞生了这个工具
简单易用,只需要把如下代码保存到任意.py文件并且在cmd运行
即可。
python xx.py
程序会自动在相同目录创建vps_cost_config.json文件用作数据存储。
感谢:chatgpt
import 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()
评论 (0)