mirror of
https://github.com/goldenfishs/MRobot.git
synced 2026-02-04 18:00:19 +08:00
1309 lines
49 KiB
Python
1309 lines
49 KiB
Python
"""
|
||
财务做账应用主界面
|
||
包含做账、查询、导出三个功能标签页
|
||
"""
|
||
|
||
from typing import Optional
|
||
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QStackedLayout, QStackedWidget,
|
||
QFileDialog, QScrollArea, QFrame,
|
||
QDialog, QTableWidget, QTableWidgetItem, QHeaderView, QTreeWidget, QTreeWidgetItem)
|
||
from PyQt5.QtCore import Qt, QDate, pyqtSignal, QMimeData, QRect, QSize, QItemSelectionModel
|
||
from PyQt5.QtGui import QIcon, QPixmap, QDrag, QFont, QColor
|
||
from qfluentwidgets import (TitleLabel, BodyLabel, SubtitleLabel, StrongBodyLabel,
|
||
HorizontalSeparator, CardWidget, PushButton, LineEdit,
|
||
SpinBox, CheckBox, TextEdit, PrimaryPushButton,
|
||
InfoBar, InfoBarPosition, FluentIcon as FIF, ComboBox,
|
||
DoubleSpinBox, DateEdit, SearchLineEdit, StateToolTip,
|
||
Dialog, SegmentedWidget, TreeWidget)
|
||
from pathlib import Path
|
||
from datetime import datetime, timedelta
|
||
import json
|
||
import os
|
||
|
||
from .tools.finance_manager import FinanceManager, TransactionType, Transaction, Account
|
||
|
||
|
||
class CreateTransactionDialog(QDialog):
|
||
"""创建/编辑交易记录对话框"""
|
||
|
||
def __init__(self, parent=None, transaction: Optional[Transaction] = None, account_id: Optional[str] = None, finance_manager=None):
|
||
super().__init__(parent)
|
||
self.transaction = transaction
|
||
self.account_id = account_id
|
||
self.finance_manager = finance_manager if finance_manager else FinanceManager()
|
||
|
||
self.setWindowTitle("新建交易记录" if not transaction else "编辑交易记录")
|
||
self.setGeometry(100, 100, 600, 500)
|
||
self.init_ui()
|
||
|
||
if transaction:
|
||
self.load_transaction_data(transaction)
|
||
else:
|
||
# 新建时默认为"入账"
|
||
self.transaction_type_combo.setCurrentIndex(0)
|
||
|
||
def init_ui(self):
|
||
"""初始化UI"""
|
||
layout = QVBoxLayout(self)
|
||
layout.setContentsMargins(20, 20, 20, 20)
|
||
layout.setSpacing(15)
|
||
|
||
# 交易类型
|
||
type_layout = QHBoxLayout()
|
||
type_layout.addWidget(BodyLabel("交易类型:"))
|
||
self.transaction_type_combo = ComboBox()
|
||
self.transaction_type_combo.addItem("入账 (正数)")
|
||
self.transaction_type_combo.addItem("支出 (负数)")
|
||
self.transaction_type_combo.setMaximumWidth(200)
|
||
type_layout.addWidget(self.transaction_type_combo)
|
||
type_layout.addStretch()
|
||
layout.addLayout(type_layout)
|
||
|
||
# 分类
|
||
category_layout = QHBoxLayout()
|
||
category_layout.addWidget(BodyLabel("分类:"))
|
||
self.category_combo = ComboBox()
|
||
# 从财务管理器获取分类列表
|
||
categories = []
|
||
if self.account_id:
|
||
# 确保账户数据已加载
|
||
account = self.finance_manager.get_account(self.account_id)
|
||
if account:
|
||
categories = account.categories
|
||
|
||
# 如果没有分类,提示用户创建
|
||
if not categories:
|
||
self.category_combo.addItem("请先在做账页创建分类")
|
||
self.category_combo.setEnabled(False)
|
||
else:
|
||
for cat in categories:
|
||
self.category_combo.addItem(cat)
|
||
self.category_combo.setEnabled(True)
|
||
|
||
self.category_combo.setMaximumWidth(200)
|
||
category_layout.addWidget(self.category_combo)
|
||
category_layout.addStretch()
|
||
layout.addLayout(category_layout)
|
||
|
||
# 日期
|
||
date_layout = QHBoxLayout()
|
||
date_layout.addWidget(BodyLabel("日期:"))
|
||
self.date_edit = DateEdit()
|
||
self.date_edit.setDate(QDate.currentDate())
|
||
date_layout.addWidget(self.date_edit)
|
||
date_layout.addStretch()
|
||
layout.addLayout(date_layout)
|
||
|
||
# 金额
|
||
amount_layout = QHBoxLayout()
|
||
amount_layout.addWidget(BodyLabel("金额 (元):"))
|
||
self.amount_spin = DoubleSpinBox()
|
||
self.amount_spin.setRange(0, 999999999)
|
||
self.amount_spin.setDecimals(2)
|
||
amount_layout.addWidget(self.amount_spin)
|
||
amount_layout.addStretch()
|
||
layout.addLayout(amount_layout)
|
||
|
||
# 交易人
|
||
trader_layout = QHBoxLayout()
|
||
trader_layout.addWidget(BodyLabel("交易人:"))
|
||
self.trader_edit = LineEdit()
|
||
trader_layout.addWidget(self.trader_edit)
|
||
layout.addLayout(trader_layout)
|
||
|
||
# 备注
|
||
notes_layout = QHBoxLayout()
|
||
notes_layout.addWidget(BodyLabel("备注:"))
|
||
self.notes_edit = TextEdit()
|
||
self.notes_edit.setMaximumHeight(80)
|
||
notes_layout.addWidget(self.notes_edit)
|
||
layout.addLayout(notes_layout)
|
||
|
||
# 图片部分
|
||
layout.addWidget(HorizontalSeparator())
|
||
layout.addWidget(SubtitleLabel("相关文件 (可选)"))
|
||
|
||
# 发票
|
||
invoice_layout = QHBoxLayout()
|
||
invoice_layout.addWidget(BodyLabel("发票图片:"))
|
||
self.invoice_label = BodyLabel("未选择")
|
||
invoice_layout.addWidget(self.invoice_label)
|
||
invoice_btn = PushButton("选择")
|
||
invoice_btn.clicked.connect(lambda: self.select_image("invoice"))
|
||
invoice_layout.addWidget(invoice_btn)
|
||
layout.addLayout(invoice_layout)
|
||
|
||
# 支付记录
|
||
payment_layout = QHBoxLayout()
|
||
payment_layout.addWidget(BodyLabel("支付记录:"))
|
||
self.payment_label = BodyLabel("未选择")
|
||
payment_layout.addWidget(self.payment_label)
|
||
payment_btn = PushButton("选择")
|
||
payment_btn.clicked.connect(lambda: self.select_image("payment"))
|
||
payment_layout.addWidget(payment_btn)
|
||
layout.addLayout(payment_layout)
|
||
|
||
# 购买记录
|
||
purchase_layout = QHBoxLayout()
|
||
purchase_layout.addWidget(BodyLabel("购买记录:"))
|
||
self.purchase_label = BodyLabel("未选择")
|
||
purchase_layout.addWidget(self.purchase_label)
|
||
purchase_btn = PushButton("选择")
|
||
purchase_btn.clicked.connect(lambda: self.select_image("purchase"))
|
||
purchase_layout.addWidget(purchase_btn)
|
||
layout.addLayout(purchase_layout)
|
||
|
||
layout.addStretch()
|
||
|
||
# 按钮
|
||
btn_layout = QHBoxLayout()
|
||
btn_layout.addStretch()
|
||
|
||
cancel_btn = PushButton("取消")
|
||
cancel_btn.clicked.connect(self.reject)
|
||
btn_layout.addWidget(cancel_btn)
|
||
|
||
save_btn = PrimaryPushButton("保存")
|
||
save_btn.clicked.connect(self.save_transaction)
|
||
btn_layout.addWidget(save_btn)
|
||
|
||
layout.addLayout(btn_layout)
|
||
|
||
# 存储图片路径
|
||
self.selected_images: dict = {
|
||
'invoice': None,
|
||
'payment': None,
|
||
'purchase': None
|
||
}
|
||
|
||
def select_image(self, image_type: str):
|
||
"""选择图片"""
|
||
file_path, _ = QFileDialog.getOpenFileName(
|
||
self, f"选择{image_type}图片",
|
||
"", "图片文件 (*.png *.jpg *.jpeg *.bmp);;所有文件 (*)"
|
||
)
|
||
|
||
if file_path:
|
||
self.selected_images[image_type] = file_path
|
||
filename = Path(file_path).name
|
||
|
||
if image_type == 'invoice':
|
||
self.invoice_label.setText(filename)
|
||
elif image_type == 'payment':
|
||
self.payment_label.setText(filename)
|
||
elif image_type == 'purchase':
|
||
self.purchase_label.setText(filename)
|
||
|
||
def load_transaction_data(self, transaction: Transaction):
|
||
"""加载交易记录数据到表单"""
|
||
# 根据金额的正负设置交易类型
|
||
if transaction.amount >= 0:
|
||
self.transaction_type_combo.setCurrentIndex(0) # 入账
|
||
else:
|
||
self.transaction_type_combo.setCurrentIndex(1) # 支出
|
||
|
||
# 设置分类
|
||
category_index = self.category_combo.findText(transaction.category)
|
||
if category_index >= 0:
|
||
self.category_combo.setCurrentIndex(category_index)
|
||
else:
|
||
self.category_combo.setCurrentIndex(0) # 默认为第一个
|
||
|
||
self.date_edit.setDate(QDate.fromString(transaction.date, "yyyy-MM-dd"))
|
||
# 显示绝对值
|
||
self.amount_spin.setValue(abs(transaction.amount))
|
||
self.trader_edit.setText(transaction.trader)
|
||
self.notes_edit.setText(transaction.notes)
|
||
|
||
if transaction.invoice_path:
|
||
self.invoice_label.setText(Path(transaction.invoice_path).name)
|
||
if transaction.payment_path:
|
||
self.payment_label.setText(Path(transaction.payment_path).name)
|
||
if transaction.purchase_path:
|
||
self.purchase_label.setText(Path(transaction.purchase_path).name)
|
||
|
||
def save_transaction(self):
|
||
"""保存交易记录"""
|
||
if not self.account_id:
|
||
dialog = Dialog(
|
||
title="错误",
|
||
content="账户ID未设置",
|
||
parent=self
|
||
)
|
||
dialog.yesButton.setText("确定")
|
||
dialog.cancelButton.hide()
|
||
dialog.exec()
|
||
return
|
||
|
||
date_str = self.date_edit.date().toString("yyyy-MM-dd")
|
||
amount = self.amount_spin.value()
|
||
trader = self.trader_edit.text().strip()
|
||
notes = self.notes_edit.toPlainText().strip()
|
||
category = self.category_combo.currentText()
|
||
|
||
# 检查分类是否有效
|
||
if not category or category == "请先在做账页创建分类":
|
||
dialog = Dialog(
|
||
title="验证错误",
|
||
content="请先创建分类后再添加交易",
|
||
parent=self
|
||
)
|
||
dialog.yesButton.setText("确定")
|
||
dialog.cancelButton.hide()
|
||
dialog.exec()
|
||
return
|
||
|
||
if not trader:
|
||
dialog = Dialog(
|
||
title="验证错误",
|
||
content="请输入交易人",
|
||
parent=self
|
||
)
|
||
dialog.yesButton.setText("确定")
|
||
dialog.cancelButton.hide()
|
||
dialog.exec()
|
||
return
|
||
|
||
if amount <= 0:
|
||
dialog = Dialog(
|
||
title="验证错误",
|
||
content="金额必须大于0",
|
||
parent=self
|
||
)
|
||
dialog.yesButton.setText("确定")
|
||
dialog.cancelButton.hide()
|
||
dialog.exec()
|
||
return
|
||
|
||
# 根据交易类型设置金额符号:入账为正数,支出为负数
|
||
is_income = self.transaction_type_combo.currentIndex() == 0
|
||
final_amount = amount if is_income else -amount
|
||
|
||
if self.transaction:
|
||
# 编辑现有交易记录
|
||
trans_id = self.transaction.id
|
||
self.finance_manager.update_transaction(
|
||
self.account_id, trans_id,
|
||
date=date_str, amount=final_amount,
|
||
trader=trader, notes=notes, category=category
|
||
)
|
||
else:
|
||
# 创建新交易记录
|
||
transaction = Transaction(
|
||
date=date_str, amount=final_amount,
|
||
trader=trader, notes=notes, category=category
|
||
)
|
||
self.finance_manager.add_transaction(self.account_id, transaction)
|
||
trans_id = transaction.id
|
||
|
||
# 保存图片
|
||
for image_type_str, image_path in self.selected_images.items():
|
||
if image_path:
|
||
image_type = TransactionType[image_type_str.upper()]
|
||
relative_path = self.finance_manager.save_image_for_transaction(
|
||
self.account_id, trans_id, image_type, image_path
|
||
)
|
||
if relative_path:
|
||
self.finance_manager.update_transaction(
|
||
self.account_id, trans_id,
|
||
**{f"{image_type_str}_path": relative_path}
|
||
)
|
||
|
||
self.accept()
|
||
|
||
|
||
class RecordViewDialog(QDialog):
|
||
"""查看和编辑交易记录详情对话框"""
|
||
|
||
def __init__(self, parent=None, account_id: Optional[str] = None, transaction: Optional[Transaction] = None):
|
||
super().__init__(parent)
|
||
self.account_id = account_id
|
||
self.transaction = transaction
|
||
self.finance_manager = FinanceManager()
|
||
|
||
self.setWindowTitle("记录详情")
|
||
self.setGeometry(100, 100, 700, 600)
|
||
self.init_ui()
|
||
|
||
if transaction:
|
||
self.load_transaction_data()
|
||
|
||
def init_ui(self):
|
||
"""初始化UI"""
|
||
layout = QVBoxLayout(self)
|
||
layout.setContentsMargins(20, 20, 20, 20)
|
||
layout.setSpacing(15)
|
||
|
||
# 基本信息
|
||
info_layout = QVBoxLayout()
|
||
|
||
date_layout = QHBoxLayout()
|
||
date_layout.addWidget(BodyLabel("日期:"))
|
||
self.date_label = BodyLabel()
|
||
date_layout.addWidget(self.date_label)
|
||
date_layout.addStretch()
|
||
info_layout.addLayout(date_layout)
|
||
|
||
amount_layout = QHBoxLayout()
|
||
amount_layout.addWidget(BodyLabel("金额:"))
|
||
self.amount_label = BodyLabel()
|
||
amount_layout.addWidget(self.amount_label)
|
||
amount_layout.addStretch()
|
||
info_layout.addLayout(amount_layout)
|
||
|
||
trader_layout = QHBoxLayout()
|
||
trader_layout.addWidget(BodyLabel("交易人:"))
|
||
self.trader_label = BodyLabel()
|
||
trader_layout.addWidget(self.trader_label)
|
||
trader_layout.addStretch()
|
||
info_layout.addLayout(trader_layout)
|
||
|
||
notes_layout = QHBoxLayout()
|
||
notes_layout.addWidget(BodyLabel("备注:"))
|
||
self.notes_label = BodyLabel()
|
||
self.notes_label.setWordWrap(True)
|
||
notes_layout.addWidget(self.notes_label)
|
||
info_layout.addLayout(notes_layout)
|
||
|
||
layout.addLayout(info_layout)
|
||
layout.addWidget(HorizontalSeparator())
|
||
|
||
# 图片预览
|
||
layout.addWidget(SubtitleLabel("相关文件预览"))
|
||
|
||
preview_layout = QHBoxLayout()
|
||
|
||
# 发票
|
||
invoice_layout = QVBoxLayout()
|
||
invoice_layout.addWidget(BodyLabel("发票:"))
|
||
self.invoice_preview = BodyLabel("无")
|
||
self.invoice_preview.setMinimumSize(150, 150)
|
||
invoice_layout.addWidget(self.invoice_preview)
|
||
preview_layout.addLayout(invoice_layout)
|
||
|
||
# 支付记录
|
||
payment_layout = QVBoxLayout()
|
||
payment_layout.addWidget(BodyLabel("支付记录:"))
|
||
self.payment_preview = BodyLabel("无")
|
||
self.payment_preview.setMinimumSize(150, 150)
|
||
payment_layout.addWidget(self.payment_preview)
|
||
preview_layout.addLayout(payment_layout)
|
||
|
||
# 购买记录
|
||
purchase_layout = QVBoxLayout()
|
||
purchase_layout.addWidget(BodyLabel("购买记录:"))
|
||
self.purchase_preview = BodyLabel("无")
|
||
self.purchase_preview.setMinimumSize(150, 150)
|
||
purchase_layout.addWidget(self.purchase_preview)
|
||
preview_layout.addLayout(purchase_layout)
|
||
|
||
layout.addLayout(preview_layout)
|
||
layout.addStretch()
|
||
|
||
# 按钮
|
||
btn_layout = QHBoxLayout()
|
||
btn_layout.addStretch()
|
||
|
||
close_btn = PushButton("关闭")
|
||
close_btn.clicked.connect(self.reject)
|
||
btn_layout.addWidget(close_btn)
|
||
|
||
layout.addLayout(btn_layout)
|
||
|
||
def load_transaction_data(self):
|
||
"""加载交易记录数据"""
|
||
if not self.transaction:
|
||
return
|
||
|
||
self.date_label.setText(self.transaction.date)
|
||
self.amount_label.setText(f"¥ {self.transaction.amount:.2f}")
|
||
self.trader_label.setText(self.transaction.trader)
|
||
self.notes_label.setText(self.transaction.notes or "无")
|
||
|
||
# 加载图片预览
|
||
self._load_image_preview('invoice', self.transaction.invoice_path if self.transaction else None, self.invoice_preview)
|
||
self._load_image_preview('payment', self.transaction.payment_path if self.transaction else None, self.payment_preview)
|
||
self._load_image_preview('purchase', self.transaction.purchase_path if self.transaction else None, self.purchase_preview)
|
||
|
||
def _load_image_preview(self, image_type: str, relative_path: Optional[str], label: BodyLabel):
|
||
"""加载并显示图片预览"""
|
||
if not relative_path:
|
||
return
|
||
|
||
full_path = self.finance_manager.get_transaction_image_path(self.account_id or "", relative_path)
|
||
if full_path and full_path.exists():
|
||
pixmap = QPixmap(str(full_path))
|
||
scaled_pixmap = pixmap.scaledToWidth(150)
|
||
label.setPixmap(scaled_pixmap)
|
||
|
||
|
||
class FinanceInterface(QWidget):
|
||
"""财务做账主界面"""
|
||
|
||
def __init__(self, parent=None):
|
||
super().__init__(parent)
|
||
self.setObjectName("financeInterface")
|
||
self.finance_manager = FinanceManager()
|
||
|
||
self.layout_main = QVBoxLayout(self)
|
||
self.layout_main.setContentsMargins(0, 0, 0, 0)
|
||
self.layout_main.setSpacing(0)
|
||
|
||
self.init_ui()
|
||
|
||
def init_ui(self):
|
||
"""初始化UI"""
|
||
# 创建顶部标签切换器
|
||
top_layout = QHBoxLayout()
|
||
top_layout.addStretch()
|
||
self.segmented_widget = SegmentedWidget()
|
||
self.segmented_widget.insertItem(0, "bookkeeping", "做账")
|
||
self.segmented_widget.insertItem(1, "query", "查询")
|
||
self.segmented_widget.insertItem(2, "export", "导出")
|
||
self.segmented_widget.currentItemChanged.connect(self.on_tab_changed)
|
||
top_layout.addWidget(self.segmented_widget)
|
||
top_layout.addStretch()
|
||
self.layout_main.addLayout(top_layout)
|
||
|
||
# 内容堆叠
|
||
self.stacked_widget = QStackedWidget()
|
||
|
||
# 做账标签页
|
||
self.bookkeeping_tab = self.create_bookkeeping_tab()
|
||
self.stacked_widget.addWidget(self.bookkeeping_tab)
|
||
|
||
# 查询标签页
|
||
self.query_tab = self.create_query_tab()
|
||
self.stacked_widget.addWidget(self.query_tab)
|
||
|
||
# 导出标签页
|
||
self.export_tab = self.create_export_tab()
|
||
self.stacked_widget.addWidget(self.export_tab)
|
||
|
||
self.layout_main.addWidget(self.stacked_widget)
|
||
|
||
# 初始化时获取默认账户
|
||
self.init_default_account()
|
||
|
||
def on_tab_changed(self, route_key: str):
|
||
"""标签切换时更新显示"""
|
||
tab_index = {"bookkeeping": 0, "query": 1, "export": 2}
|
||
index = tab_index.get(route_key, 0)
|
||
self.stacked_widget.setCurrentIndex(index)
|
||
|
||
def create_bookkeeping_tab(self) -> QWidget:
|
||
"""创建做账标签页"""
|
||
widget = QWidget()
|
||
layout = QVBoxLayout(widget)
|
||
layout.setContentsMargins(20, 20, 20, 20)
|
||
layout.setSpacing(15)
|
||
|
||
# 标题和操作按钮
|
||
title_layout = QHBoxLayout()
|
||
title_layout.addWidget(SubtitleLabel("交易记录"))
|
||
|
||
# 新建分类按钮
|
||
new_category_btn = PushButton("新建分类")
|
||
new_category_btn.setFixedWidth(90)
|
||
new_category_btn.clicked.connect(self.on_create_category_clicked)
|
||
title_layout.addWidget(new_category_btn)
|
||
|
||
title_layout.addStretch()
|
||
|
||
new_record_btn = PrimaryPushButton("新建记录")
|
||
new_record_btn.clicked.connect(self.create_new_record)
|
||
title_layout.addWidget(new_record_btn)
|
||
|
||
layout.addLayout(title_layout)
|
||
|
||
# 记录表格 - 使用 TreeWidget 风格
|
||
self.records_table = TreeWidget()
|
||
self.records_table.setHeaderLabels(["日期", "交易人", "分类", "金额 (元)", "备注"])
|
||
self.records_table.setSelectionMode(self.records_table.SingleSelection)
|
||
self.records_table.setIndentation(0)
|
||
|
||
# 设置 TreeWidget 样式
|
||
header = self.records_table.header()
|
||
if header:
|
||
header.setStretchLastSection(False)
|
||
# 列宽自适应,可拖动调整
|
||
header.setSectionResizeMode(0, QHeaderView.ResizeToContents)
|
||
header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
|
||
header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
|
||
header.setSectionResizeMode(3, QHeaderView.ResizeToContents)
|
||
header.setSectionResizeMode(4, QHeaderView.Stretch)
|
||
# 启用列宽可拖动
|
||
header.setSectionsMovable(False)
|
||
header.setStretchLastSection(False)
|
||
|
||
self.records_table.setCheckedColor("#0078d4", "#2d7d9a")
|
||
self.records_table.setBorderRadius(8)
|
||
self.records_table.setBorderVisible(True)
|
||
self.records_table.itemSelectionChanged.connect(self.on_record_selection_changed)
|
||
|
||
layout.addWidget(self.records_table)
|
||
|
||
# 操作按钮区
|
||
btn_layout = QHBoxLayout()
|
||
btn_layout.addStretch()
|
||
|
||
self.view_record_btn = PushButton("查看详情")
|
||
self.view_record_btn.setFixedWidth(90)
|
||
self.view_record_btn.clicked.connect(self.on_view_record_clicked)
|
||
self.view_record_btn.setEnabled(False)
|
||
btn_layout.addWidget(self.view_record_btn)
|
||
|
||
self.edit_record_btn = PushButton("编辑")
|
||
self.edit_record_btn.setFixedWidth(75)
|
||
self.edit_record_btn.clicked.connect(self.on_edit_record_clicked)
|
||
self.edit_record_btn.setEnabled(False)
|
||
btn_layout.addWidget(self.edit_record_btn)
|
||
|
||
self.delete_record_btn = PushButton("删除")
|
||
self.delete_record_btn.setFixedWidth(75)
|
||
self.delete_record_btn.clicked.connect(self.on_delete_record_clicked)
|
||
self.delete_record_btn.setEnabled(False)
|
||
btn_layout.addWidget(self.delete_record_btn)
|
||
|
||
layout.addLayout(btn_layout)
|
||
|
||
# 统计信息卡片
|
||
stats_card = CardWidget()
|
||
stats_layout = QHBoxLayout(stats_card)
|
||
stats_layout.setContentsMargins(20, 15, 20, 15)
|
||
stats_layout.setSpacing(30)
|
||
|
||
stats_layout.addWidget(BodyLabel("总额:"))
|
||
self.total_amount_label = StrongBodyLabel("¥ 0.00")
|
||
self.total_amount_label.setStyleSheet("color: #d32f2f;")
|
||
stats_layout.addWidget(self.total_amount_label)
|
||
|
||
stats_layout.addSpacing(30)
|
||
stats_layout.addWidget(BodyLabel("记录数:"))
|
||
self.record_count_label = StrongBodyLabel("0")
|
||
stats_layout.addWidget(self.record_count_label)
|
||
|
||
stats_layout.addStretch()
|
||
layout.addWidget(stats_card)
|
||
|
||
return widget
|
||
|
||
def create_query_tab(self) -> QWidget:
|
||
"""创建查询标签页"""
|
||
widget = QWidget()
|
||
layout = QVBoxLayout(widget)
|
||
layout.setContentsMargins(20, 20, 20, 20)
|
||
layout.setSpacing(15)
|
||
|
||
# 搜索过滤区 - 卡片样式
|
||
filter_card = CardWidget()
|
||
filter_layout = QVBoxLayout(filter_card)
|
||
filter_layout.setContentsMargins(20, 15, 20, 15)
|
||
filter_layout.setSpacing(15) # 增加间距为15
|
||
|
||
# 第一行:日期范围
|
||
date_layout = QHBoxLayout()
|
||
date_layout.addWidget(BodyLabel("日期范围:"))
|
||
self.query_date_start = DateEdit()
|
||
self.query_date_start.setDate(QDate.currentDate().addMonths(-1))
|
||
date_layout.addWidget(self.query_date_start, 1)
|
||
date_layout.addWidget(BodyLabel("至"))
|
||
self.query_date_end = DateEdit()
|
||
self.query_date_end.setDate(QDate.currentDate())
|
||
date_layout.addWidget(self.query_date_end, 1)
|
||
filter_layout.addLayout(date_layout)
|
||
|
||
# 第二行:交易类型和分类
|
||
type_category_layout = QHBoxLayout()
|
||
type_category_layout.addWidget(BodyLabel("交易类型:"))
|
||
self.query_transaction_type = ComboBox()
|
||
self.query_transaction_type.addItem("全部")
|
||
self.query_transaction_type.addItem("收入 (正数)")
|
||
self.query_transaction_type.addItem("支出 (负数)")
|
||
type_category_layout.addWidget(self.query_transaction_type, 1)
|
||
|
||
type_category_layout.addWidget(BodyLabel("分类:"))
|
||
self.query_category = ComboBox()
|
||
self.query_category.addItem("全部")
|
||
# 初始化时加载现有分类
|
||
account_id = self.get_current_account_id()
|
||
if account_id:
|
||
account = self.finance_manager.get_account(account_id)
|
||
if account:
|
||
for cat in account.categories:
|
||
self.query_category.addItem(cat)
|
||
type_category_layout.addWidget(self.query_category, 1)
|
||
filter_layout.addLayout(type_category_layout)
|
||
|
||
# 第三行:金额范围
|
||
amount_layout = QHBoxLayout()
|
||
amount_layout.addWidget(BodyLabel("金额范围:"))
|
||
self.query_amount_min = DoubleSpinBox()
|
||
self.query_amount_min.setRange(0, 999999)
|
||
self.query_amount_min.setPrefix("¥ ")
|
||
amount_layout.addWidget(self.query_amount_min, 1)
|
||
amount_layout.addWidget(BodyLabel("至"))
|
||
self.query_amount_max = DoubleSpinBox()
|
||
self.query_amount_max.setRange(0, 999999)
|
||
self.query_amount_max.setValue(999999)
|
||
self.query_amount_max.setPrefix("¥ ")
|
||
amount_layout.addWidget(self.query_amount_max, 1)
|
||
filter_layout.addLayout(amount_layout)
|
||
|
||
# 第四行:交易人搜索和查询按钮
|
||
trader_layout = QHBoxLayout()
|
||
trader_layout.addWidget(BodyLabel("交易人:"))
|
||
self.query_trader_edit = SearchLineEdit()
|
||
self.query_trader_edit.setPlaceholderText("输入交易人名称...")
|
||
trader_layout.addWidget(self.query_trader_edit, 1)
|
||
|
||
query_btn = PrimaryPushButton("查询")
|
||
query_btn.clicked.connect(self.perform_query)
|
||
trader_layout.addWidget(query_btn)
|
||
filter_layout.addLayout(trader_layout)
|
||
|
||
layout.addWidget(filter_card)
|
||
layout.addWidget(HorizontalSeparator())
|
||
|
||
# 查询结果表格 - 使用 TreeWidget 风格
|
||
self.query_result_table = TreeWidget()
|
||
self.query_result_table.setHeaderLabels(["日期", "交易人", "分类", "金额 (元)", "备注"])
|
||
self.query_result_table.setSelectionMode(self.query_result_table.SingleSelection)
|
||
self.query_result_table.setIndentation(0)
|
||
|
||
# 设置 TreeWidget 样式
|
||
header = self.query_result_table.header()
|
||
if header:
|
||
header.setStretchLastSection(False)
|
||
# 列宽自适应,可拖动调整
|
||
header.setSectionResizeMode(0, QHeaderView.ResizeToContents)
|
||
header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
|
||
header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
|
||
header.setSectionResizeMode(3, QHeaderView.ResizeToContents)
|
||
header.setSectionResizeMode(4, QHeaderView.Stretch)
|
||
# 启用列宽可拖动
|
||
header.setSectionsMovable(False)
|
||
header.setStretchLastSection(False)
|
||
|
||
self.query_result_table.setCheckedColor("#0078d4", "#2d7d9a")
|
||
self.query_result_table.setBorderRadius(8)
|
||
self.query_result_table.setBorderVisible(True)
|
||
self.query_result_table.itemSelectionChanged.connect(self.on_query_result_selection_changed)
|
||
|
||
layout.addWidget(self.query_result_table)
|
||
|
||
# 查询结果操作按钮
|
||
query_btn_layout = QHBoxLayout()
|
||
query_btn_layout.addStretch()
|
||
|
||
self.query_view_btn = PushButton("查看详情")
|
||
self.query_view_btn.setFixedWidth(90)
|
||
self.query_view_btn.clicked.connect(self.on_query_view_clicked)
|
||
self.query_view_btn.setEnabled(False)
|
||
query_btn_layout.addWidget(self.query_view_btn)
|
||
|
||
layout.addLayout(query_btn_layout)
|
||
|
||
return widget
|
||
|
||
def create_export_tab(self) -> QWidget:
|
||
"""创建导出标签页"""
|
||
widget = QWidget()
|
||
layout = QVBoxLayout(widget)
|
||
layout.setContentsMargins(20, 20, 20, 20)
|
||
layout.setSpacing(20)
|
||
|
||
layout.addWidget(TitleLabel("数据导出和导入"))
|
||
layout.addWidget(HorizontalSeparator())
|
||
|
||
# 导出选项
|
||
layout.addWidget(SubtitleLabel("导出选项"))
|
||
|
||
export_layout = QVBoxLayout()
|
||
|
||
# 导出账户为压缩包
|
||
account_export_layout = QHBoxLayout()
|
||
account_export_layout.addWidget(BodyLabel("导出当前账户:"))
|
||
account_export_layout.addStretch()
|
||
export_account_btn = PrimaryPushButton("导出为ZIP包")
|
||
export_account_btn.clicked.connect(self.export_account)
|
||
account_export_layout.addWidget(export_account_btn)
|
||
export_layout.addLayout(account_export_layout)
|
||
|
||
# 导出为CSV
|
||
csv_export_layout = QHBoxLayout()
|
||
csv_export_layout.addWidget(BodyLabel("导出为Excel格式:"))
|
||
csv_export_layout.addStretch()
|
||
export_csv_btn = PrimaryPushButton("导出CSV")
|
||
export_csv_btn.clicked.connect(self.export_csv)
|
||
csv_export_layout.addWidget(export_csv_btn)
|
||
export_layout.addLayout(csv_export_layout)
|
||
|
||
# 备份所有账户
|
||
backup_layout = QHBoxLayout()
|
||
backup_layout.addWidget(BodyLabel("备份所有账户:"))
|
||
backup_layout.addStretch()
|
||
backup_btn = PrimaryPushButton("创建备份")
|
||
backup_btn.clicked.connect(self.backup_all)
|
||
backup_layout.addWidget(backup_btn)
|
||
export_layout.addLayout(backup_layout)
|
||
|
||
layout.addLayout(export_layout)
|
||
layout.addWidget(HorizontalSeparator())
|
||
|
||
# 导入选项
|
||
layout.addWidget(SubtitleLabel("导入选项"))
|
||
|
||
import_layout = QVBoxLayout()
|
||
|
||
# 导入账户
|
||
account_import_layout = QHBoxLayout()
|
||
account_import_layout.addWidget(BodyLabel("导入账户ZIP包:"))
|
||
account_import_layout.addStretch()
|
||
import_account_btn = PrimaryPushButton("导入账户")
|
||
import_account_btn.clicked.connect(self.import_account)
|
||
account_import_layout.addWidget(import_account_btn)
|
||
import_layout.addLayout(account_import_layout)
|
||
|
||
layout.addLayout(import_layout)
|
||
layout.addStretch()
|
||
|
||
return widget
|
||
|
||
def init_default_account(self):
|
||
"""初始化默认账户为 'admin'"""
|
||
accounts = self.finance_manager.get_all_accounts()
|
||
|
||
# 查找 admin 账户(通常应该存在,因为 FinanceManager 会自动创建)
|
||
admin_account = None
|
||
for account in accounts:
|
||
if account.name == "admin":
|
||
admin_account = account
|
||
break
|
||
|
||
# 设置为当前账户
|
||
if admin_account:
|
||
self.default_account_id = admin_account.id
|
||
elif accounts:
|
||
# 备用方案:如果找不到 admin,使用第一个账户
|
||
self.default_account_id = accounts[0].id
|
||
else:
|
||
# 如果没有任何账户(不应该发生),创建 admin
|
||
admin_account = self.finance_manager.create_account(
|
||
account_name="admin",
|
||
description="默认管理账户"
|
||
)
|
||
self.default_account_id = admin_account.id
|
||
|
||
self.refresh_records_display()
|
||
|
||
def refresh_account_list(self):
|
||
"""刷新账户列表(已移除,保留兼容性)"""
|
||
pass
|
||
|
||
def get_current_account_id(self) -> Optional[str]:
|
||
"""获取当前账户ID"""
|
||
if hasattr(self, 'default_account_id'):
|
||
return self.default_account_id
|
||
|
||
# 备用:如果还没初始化,从财务管理器获取第一个账户
|
||
accounts = self.finance_manager.get_all_accounts()
|
||
if accounts:
|
||
return accounts[0].id
|
||
return None
|
||
|
||
def on_account_changed(self):
|
||
"""账户改变时刷新显示(已移除,保留兼容性)"""
|
||
pass
|
||
|
||
def refresh_records_display(self):
|
||
"""刷新记录显示"""
|
||
account_id = self.get_current_account_id()
|
||
if not account_id:
|
||
return
|
||
|
||
# 重新加载所有账户,从磁盘获取最新数据
|
||
self.finance_manager.load_all_accounts()
|
||
account = self.finance_manager.get_account(account_id)
|
||
if not account:
|
||
return
|
||
|
||
self.clear_records_table()
|
||
|
||
for transaction in account.transactions:
|
||
# 创建树形项
|
||
item = QTreeWidgetItem()
|
||
item.setText(0, transaction.date)
|
||
item.setText(1, transaction.trader)
|
||
item.setText(2, transaction.category)
|
||
item.setText(3, f"¥ {transaction.amount:.2f}")
|
||
item.setText(4, transaction.notes or "")
|
||
# 存储交易ID到第一列的 UserRole (Qt.UserRole = 32)
|
||
item.setData(0, 32, transaction.id)
|
||
|
||
self.records_table.addTopLevelItem(item)
|
||
|
||
# 更新统计信息
|
||
total_amount = sum(t.amount for t in account.transactions)
|
||
self.total_amount_label.setText(f"¥ {total_amount:.2f}")
|
||
self.record_count_label.setText(str(len(account.transactions)))
|
||
|
||
def clear_records_table(self):
|
||
"""清空记录表格"""
|
||
self.records_table.clear()
|
||
self.total_amount_label.setText("¥ 0.00")
|
||
self.record_count_label.setText("0")
|
||
|
||
def create_new_account(self):
|
||
"""创建新账户(已移除)"""
|
||
pass
|
||
|
||
def delete_current_account(self):
|
||
"""删除当前账户(已移除)"""
|
||
pass
|
||
|
||
def create_new_record(self):
|
||
"""创建新记录"""
|
||
account_id = self.get_current_account_id()
|
||
if not account_id:
|
||
InfoBar.warning(
|
||
title="提示",
|
||
content="请先创建或选择一个账户",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=3000,
|
||
parent=self
|
||
)
|
||
return
|
||
|
||
dialog = CreateTransactionDialog(self, account_id=account_id, finance_manager=self.finance_manager)
|
||
result = dialog.exec_()
|
||
# 无论是否成功,都尝试刷新表格
|
||
if result == QDialog.Accepted:
|
||
# 对话框正常关闭(保存)
|
||
self.refresh_records_display()
|
||
InfoBar.success(
|
||
title="成功",
|
||
content="记录已添加",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=2000,
|
||
parent=self
|
||
)
|
||
else:
|
||
# 对话框被取消,也刷新以防万一
|
||
self.refresh_records_display()
|
||
|
||
def edit_record(self, trans_id: str):
|
||
"""编辑记录"""
|
||
account_id = self.get_current_account_id()
|
||
if not account_id:
|
||
return
|
||
|
||
transaction = self.finance_manager.get_transaction(account_id, trans_id)
|
||
if not transaction:
|
||
return
|
||
|
||
dialog = CreateTransactionDialog(self, transaction=transaction, account_id=account_id, finance_manager=self.finance_manager)
|
||
result = dialog.exec_()
|
||
if result == QDialog.Accepted:
|
||
self.refresh_records_display()
|
||
InfoBar.success(
|
||
title="成功",
|
||
content="记录已更新",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=2000,
|
||
parent=self
|
||
)
|
||
else:
|
||
# 对话框被取消,也刷新以防万一
|
||
self.refresh_records_display()
|
||
|
||
def delete_record(self, trans_id: str):
|
||
"""删除记录"""
|
||
account_id = self.get_current_account_id()
|
||
if not account_id:
|
||
return
|
||
|
||
def on_delete_confirm():
|
||
self.finance_manager.delete_transaction(account_id, trans_id)
|
||
self.refresh_records_display()
|
||
InfoBar.success(
|
||
title="成功",
|
||
content="记录已删除",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=2000,
|
||
parent=self
|
||
)
|
||
|
||
dialog = Dialog(
|
||
title="确认删除",
|
||
content="确定要删除这条记录吗?",
|
||
parent=self
|
||
)
|
||
dialog.yesButton.setText("删除")
|
||
dialog.cancelButton.setText("取消")
|
||
dialog.yesButton.clicked.connect(on_delete_confirm)
|
||
dialog.exec()
|
||
|
||
def view_record(self, trans_id: str):
|
||
"""查看记录详情"""
|
||
account_id = self.get_current_account_id()
|
||
if not account_id:
|
||
return
|
||
|
||
transaction = self.finance_manager.get_transaction(account_id, trans_id)
|
||
if not transaction:
|
||
return
|
||
|
||
dialog = RecordViewDialog(self, account_id=account_id, transaction=transaction)
|
||
dialog.exec_()
|
||
|
||
def perform_query(self):
|
||
"""执行查询"""
|
||
account_id = self.get_current_account_id()
|
||
if not account_id:
|
||
InfoBar.warning(
|
||
title="提示",
|
||
content="请先创建或选择一个账户",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=3000,
|
||
parent=self
|
||
)
|
||
return
|
||
|
||
# 重新加载最新数据
|
||
self.finance_manager.load_all_accounts()
|
||
|
||
# 更新分类下拉框(如果分类列表发生变化)
|
||
account = self.finance_manager.get_account(account_id)
|
||
if account:
|
||
# 检查分类是否已经存在于下拉框中
|
||
current_count = self.query_category.count()
|
||
expected_count = len(account.categories) + 1 # +1 是因为有"全部"选项
|
||
|
||
# 只有在分类数量变化时才重新加载
|
||
if current_count != expected_count:
|
||
current_category = self.query_category.currentText()
|
||
self.query_category.clear()
|
||
self.query_category.addItem("全部")
|
||
for cat in account.categories:
|
||
self.query_category.addItem(cat)
|
||
# 尽量恢复之前的选择
|
||
index = self.query_category.findText(current_category)
|
||
if index >= 0:
|
||
self.query_category.setCurrentIndex(index)
|
||
else:
|
||
self.query_category.setCurrentIndex(0) # 默认选择"全部"
|
||
|
||
date_start = self.query_date_start.date().toString("yyyy-MM-dd")
|
||
date_end = self.query_date_end.date().toString("yyyy-MM-dd")
|
||
amount_min = self.query_amount_min.value() if self.query_amount_min.value() > 0 else None
|
||
amount_max = self.query_amount_max.value() if self.query_amount_max.value() < 999999999 else None
|
||
trader = self.query_trader_edit.text().strip() or None
|
||
|
||
# 分类查询 - 获取当前选择的分类
|
||
category_text = self.query_category.currentText()
|
||
category = None if category_text == "全部" else category_text
|
||
|
||
results = self.finance_manager.query_transactions(
|
||
account_id,
|
||
date_start=date_start, date_end=date_end,
|
||
amount_min=amount_min, amount_max=amount_max,
|
||
trader=trader, category=category
|
||
)
|
||
|
||
# 根据交易类型过滤
|
||
transaction_type_index = self.query_transaction_type.currentIndex()
|
||
if transaction_type_index == 1: # 收入(正数)
|
||
results = [t for t in results if t.amount >= 0]
|
||
elif transaction_type_index == 2: # 支出(负数)
|
||
results = [t for t in results if t.amount < 0]
|
||
# 如果是 0(全部),不进行过滤
|
||
|
||
self.query_result_table.clear()
|
||
|
||
for transaction in results:
|
||
# 创建树形项
|
||
item = QTreeWidgetItem()
|
||
item.setText(0, transaction.date)
|
||
item.setText(1, transaction.trader)
|
||
item.setText(2, transaction.category)
|
||
item.setText(3, f"¥ {transaction.amount:.2f}")
|
||
item.setText(4, transaction.notes or "")
|
||
# 存储交易ID
|
||
item.setData(0, 32, transaction.id)
|
||
|
||
self.query_result_table.addTopLevelItem(item)
|
||
|
||
InfoBar.success(
|
||
title="查询成功",
|
||
content=f"找到 {len(results)} 条记录",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=2000,
|
||
parent=self
|
||
)
|
||
|
||
def export_account(self):
|
||
"""导出账户为ZIP包"""
|
||
account_id = self.get_current_account_id()
|
||
if not account_id:
|
||
InfoBar.warning(
|
||
title="提示",
|
||
content="请先选择一个账户",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=3000,
|
||
parent=self
|
||
)
|
||
return
|
||
|
||
export_dir = QFileDialog.getExistingDirectory(self, "选择导出目录")
|
||
if export_dir:
|
||
if self.finance_manager.export_account_package(account_id, export_dir):
|
||
InfoBar.success(
|
||
title="成功",
|
||
content="账户导出成功",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=2000,
|
||
parent=self
|
||
)
|
||
else:
|
||
InfoBar.error(
|
||
title="失败",
|
||
content="导出账户失败",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=3000,
|
||
parent=self
|
||
)
|
||
|
||
def import_account(self):
|
||
"""导入账户ZIP包"""
|
||
zip_file, _ = QFileDialog.getOpenFileName(
|
||
self, "选择要导入的账户文件",
|
||
"", "ZIP文件 (*.zip)"
|
||
)
|
||
|
||
if zip_file:
|
||
account_id = self.finance_manager.import_account_package(zip_file)
|
||
if account_id:
|
||
# 重新初始化默认账户
|
||
self.init_default_account()
|
||
InfoBar.success(
|
||
title="成功",
|
||
content="账户导入成功",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=2000,
|
||
parent=self
|
||
)
|
||
else:
|
||
InfoBar.error(
|
||
title="失败",
|
||
content="导入账户失败",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=3000,
|
||
parent=self
|
||
)
|
||
|
||
def export_csv(self):
|
||
"""导出为CSV"""
|
||
account_id = self.get_current_account_id()
|
||
if not account_id:
|
||
InfoBar.warning(
|
||
title="提示",
|
||
content="请先选择一个账户",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=3000,
|
||
parent=self
|
||
)
|
||
return
|
||
|
||
account = self.finance_manager.get_account(account_id)
|
||
if not account:
|
||
return
|
||
|
||
file_path, _ = QFileDialog.getSaveFileName(
|
||
self, "保存CSV文件",
|
||
f"{account.name}.csv",
|
||
"CSV文件 (*.csv)"
|
||
)
|
||
|
||
if file_path:
|
||
if self.finance_manager.export_to_csv(account_id, file_path):
|
||
InfoBar.success(
|
||
title="成功",
|
||
content="已导出为CSV",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=2000,
|
||
parent=self
|
||
)
|
||
else:
|
||
InfoBar.error(
|
||
title="失败",
|
||
content="导出CSV失败",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=3000,
|
||
parent=self
|
||
)
|
||
|
||
def backup_all(self):
|
||
"""备份所有账户"""
|
||
if self.finance_manager.backup_all_accounts():
|
||
InfoBar.success(
|
||
title="成功",
|
||
content="备份创建成功,已保存到 assets/Finance_Data/backups",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=3000,
|
||
parent=self
|
||
)
|
||
else:
|
||
InfoBar.error(
|
||
title="失败",
|
||
content="创建备份失败",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=3000,
|
||
parent=self
|
||
)
|
||
|
||
def on_record_selection_changed(self):
|
||
"""记录表格选择改变时"""
|
||
selected_items = self.records_table.selectedItems()
|
||
has_selection = len(selected_items) > 0
|
||
self.view_record_btn.setEnabled(has_selection)
|
||
self.edit_record_btn.setEnabled(has_selection)
|
||
self.delete_record_btn.setEnabled(has_selection)
|
||
|
||
def on_query_result_selection_changed(self):
|
||
"""查询结果表格选择改变时"""
|
||
selected_items = self.query_result_table.selectedItems()
|
||
has_selection = len(selected_items) > 0
|
||
self.query_view_btn.setEnabled(has_selection)
|
||
|
||
def on_view_record_clicked(self):
|
||
"""查看记录按钮点击"""
|
||
current_item = self.records_table.currentItem()
|
||
if current_item:
|
||
trans_id = current_item.data(0, 32) # Qt.UserRole = 32
|
||
if trans_id:
|
||
self.view_record(trans_id)
|
||
|
||
def on_edit_record_clicked(self):
|
||
"""编辑记录按钮点击"""
|
||
current_item = self.records_table.currentItem()
|
||
if current_item:
|
||
trans_id = current_item.data(0, 32) # Qt.UserRole = 32
|
||
if trans_id:
|
||
self.edit_record(trans_id)
|
||
|
||
def on_delete_record_clicked(self):
|
||
"""删除记录按钮点击"""
|
||
current_item = self.records_table.currentItem()
|
||
if current_item:
|
||
trans_id = current_item.data(0, 32) # Qt.UserRole = 32
|
||
if trans_id:
|
||
self.delete_record(trans_id)
|
||
|
||
def on_query_view_clicked(self):
|
||
"""查询结果查看详情按钮点击"""
|
||
current_item = self.query_result_table.currentItem()
|
||
if current_item:
|
||
trans_id = current_item.data(0, 32) # Qt.UserRole = 32
|
||
if trans_id:
|
||
self.view_record(trans_id)
|
||
|
||
def on_create_category_clicked(self):
|
||
"""新建分类按钮点击"""
|
||
account_id = self.get_current_account_id()
|
||
if not account_id:
|
||
InfoBar.warning(
|
||
title="提示",
|
||
content="请先创建或选择一个账户",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=3000,
|
||
parent=self
|
||
)
|
||
return
|
||
|
||
# 创建自定义对话框
|
||
from PyQt5.QtWidgets import QDialog as QStdDialog, QLabel
|
||
|
||
category_dialog = QStdDialog(self)
|
||
category_dialog.setWindowTitle("新建分类")
|
||
category_dialog.setGeometry(100, 100, 400, 150)
|
||
|
||
layout = QVBoxLayout(category_dialog)
|
||
layout.addWidget(BodyLabel("分类名称:"))
|
||
|
||
input_edit = LineEdit()
|
||
input_edit.setPlaceholderText("例如:食品、交通、娱乐等")
|
||
layout.addWidget(input_edit)
|
||
|
||
# 按钮
|
||
btn_layout = QHBoxLayout()
|
||
btn_layout.addStretch()
|
||
|
||
def on_create():
|
||
category_name = input_edit.text().strip()
|
||
if not category_name:
|
||
InfoBar.warning(
|
||
title="提示",
|
||
content="分类名称不能为空",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=2000,
|
||
parent=self
|
||
)
|
||
return
|
||
|
||
if self.finance_manager.add_category(account_id, category_name):
|
||
InfoBar.success(
|
||
title="成功",
|
||
content=f"分类 '{category_name}' 创建成功",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=2000,
|
||
parent=self
|
||
)
|
||
|
||
# 更新查询页面的分类下拉框
|
||
if hasattr(self, 'query_category'):
|
||
# 检查是否已经存在
|
||
if self.query_category.findText(category_name) < 0:
|
||
self.query_category.addItem(category_name)
|
||
|
||
category_dialog.accept()
|
||
else:
|
||
InfoBar.warning(
|
||
title="提示",
|
||
content="分类已存在",
|
||
isClosable=True,
|
||
position=InfoBarPosition.TOP,
|
||
duration=2000,
|
||
parent=self
|
||
)
|
||
|
||
cancel_btn = PushButton("取消")
|
||
cancel_btn.clicked.connect(category_dialog.reject)
|
||
btn_layout.addWidget(cancel_btn)
|
||
|
||
create_btn = PrimaryPushButton("创建")
|
||
create_btn.clicked.connect(on_create)
|
||
btn_layout.addWidget(create_btn)
|
||
|
||
layout.addLayout(btn_layout)
|
||
category_dialog.exec()
|