吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4515|回复: 48
上一主题 下一主题
收起左侧

[Python 原创] PYQT5写的个人账号信息管理系统

[复制链接]
跳转到指定楼层
楼主
phantomxjc 发表于 2025-7-18 09:19 回帖奖励
[Python] 纯文本查看 复制代码
import sys
import pandas as pd
import numpy as np
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QDialog, QLabel,
                             QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,
                             QListWidget, QStackedWidget, QTableWidget, QTableWidgetItem,
                             QTabWidget, QMessageBox, QAbstractItemView, QHeaderView,
                             QFormLayout, QFrame, QComboBox, QToolButton)
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QFont, QIcon, QPalette, QColor, QLinearGradient, QBrush


# ======================
# 登录对话框
# ======================
class LoginDialog(QDialog):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("系统登录")
        self.setFixedSize(800, 600)
        self.setStyleSheet("""
            background-color: #f5f7fa;
            font-family: 'Microsoft YaHei';
        """)

        # 创建渐变背景
        palette = self.palette()
        gradient = QLinearGradient(0, 0, 0, 400)
        gradient.setColorAt(0, QColor("#4facfe"))
        gradient.setColorAt(1, QColor("#00f2fe"))
        palette.setBrush(QPalette.Window, QBrush(gradient))
        self.setPalette(palette)

        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()
        layout.setContentsMargins(40, 40, 40, 40)
        layout.setSpacing(20)

        # 标题
        title = QLabel("欢迎来到个人信息管理系统")
        title.setStyleSheet("""
            font-size: 28px;
            font-weight: bold;
            color: red;
            padding: 10px;
        """)
        title.setAlignment(Qt.AlignCenter)

        # 输入框容器
        form_frame = QFrame()
        form_frame.setStyleSheet("""
            background-color: rgba(255, 255, 255, 0.9);
            border-radius: 12px;
            padding: 20px;
        """)
        form_layout = QVBoxLayout(form_frame)
        form_layout.setContentsMargins(15, 15, 15, 15)
        form_layout.setSpacing(20)

        # 用户名输入
        self.username_input = QLineEdit()
        self.username_input.setPlaceholderText("用户名")
        self.username_input.setStyleSheet("""
            QLineEdit {
                border: 2px solid #e0e0e0;
                border-radius: 8px;
                padding: 12px;
                font-size: 16px;
            }
            QLineEdit:focus {
                border-color: #4facfe;
            }
        """)

        # 密码输入
        self.password_input = QLineEdit()
        self.password_input.setPlaceholderText("密码")
        self.password_input.setEchoMode(QLineEdit.Password)
        self.password_input.setStyleSheet(self.username_input.styleSheet())

        # 登录按钮
        login_btn = QPushButton("登 录")
        login_btn.setStyleSheet("""
            QPushButton {
                background-color: #4facfe;
                color: white;
                border: none;
                border-radius: 8px;
                padding: 14px;
                font-size: 16px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #3a8bce;
            }
        """)
        login_btn.clicked.connect(self.check_credentials)

        form_layout.addWidget(self.username_input)
        form_layout.addWidget(self.password_input)
        form_layout.addWidget(login_btn)

        layout.addWidget(title)
        layout.addWidget(form_frame)
        self.setLayout(layout)

    def check_credentials(self):
        username = self.username_input.text().strip()
        password = self.password_input.text().strip()

        # 简单验证(实际应用中应使用数据库验证)
        if username == "admin" and password == "password":
            self.accept()
        else:
            QMessageBox.warning(self, "登录失败", "用户名或密码错误")


# ======================
# 主界面
# ======================
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("数据管理系统")
        self.setGeometry(100, 100, 1200, 800)
        self.setStyleSheet("""
            background-color: #f5f7fa;
            font-family: 'Microsoft YaHei';
        """)

        self.init_ui()
        self.load_data()

    def init_ui(self):
        # 主布局
        main_widget = QWidget()
        main_layout = QHBoxLayout(main_widget)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.setSpacing(0)

        # 左侧导航栏 (1/12宽度)
        self.sidebar = QFrame()
        self.sidebar.setFixedWidth(int(self.width() / 7))
        self.sidebar.setStyleSheet("""
            background-color: #2c3e50;
            border-right: 1px solid #34495e;
        """)
        sidebar_layout = QVBoxLayout(self.sidebar)
        sidebar_layout.setContentsMargins(0, 20, 0, 20)
        sidebar_layout.setSpacing(10)

        # 导航按钮
        self.nav_list = QListWidget()
        self.nav_list.setStyleSheet("""
            QListWidget {
                background-color: transparent;
                border: none;
                color: #ecf0f1;
                font-size: 16px;
                padding: 10px;
            }
            QListWidget::item {
                padding: 15px 20px;
                border-left: 4px solid transparent;
            }
            QListWidget::item:selected {
                background-color: #34495e;
                border-left: 4px solid #3498db;
            }
        """)
        self.nav_list.setFrameShape(QListWidget.NoFrame)
        self.nav_list.setFixedSize(300, 800)
        item_height = 80  # 400 / 10 = 40px
        self.nav_list.setGridSize(QSize(0, item_height))  # 宽度自适应,高度固定

        # 固定导航栏总高度
        self.nav_list.setFixedHeight(10 * item_height)
        self.nav_list.addItems([
            "账号密码管理",
            "随礼记录",
            "栏目三",
            "栏目四",
            "栏目五",
            "栏目六",
            "栏目七",
            "栏目八",
            "栏目九",
            "栏目十"
        ])
        self.nav_list.currentRowChanged.connect(self.switch_page)

        sidebar_layout.addWidget(self.nav_list)
        sidebar_layout.addStretch()

        # 右侧堆叠窗口
        self.stacked_widget = QStackedWidget()
        self.stacked_widget.setStyleSheet("""
            background-color: white;
            border-radius: 0;
        """)

        # 添加各个页面
        self.account_page = AccountPasswordPage()
        self.gift_page = GiftRecordPage()

        self.stacked_widget.addWidget(self.account_page)
        self.stacked_widget.addWidget(self.gift_page)

        # 添加8个占位页面
        for i in range(8):
            placeholder = QWidget()
            placeholder.setStyleSheet("background-color: white;")
            layout = QVBoxLayout(placeholder)
            label = QLabel(f"栏目 {i + 3} 开发中...")
            label.setStyleSheet("font-size: 24px; color: #7f8c8d;")
            label.setAlignment(Qt.AlignCenter)
            layout.addWidget(label)
            self.stacked_widget.addWidget(placeholder)

        main_layout.addWidget(self.sidebar)
        main_layout.addWidget(self.stacked_widget)

        self.setCentralWidget(main_widget)

    def switch_page(self, index):
        self.stacked_widget.setCurrentIndex(index)

    def load_data(self):
        # 尝试加载账号数据
        try:
            self.account_page.load_account_data()
        except Exception as e:
            QMessageBox.warning(self, "数据加载错误", f"账号数据加载失败: {str(e)}")

        # 尝试加载随礼数据
        try:
            self.gift_page.load_gift_data()
        except Exception as e:
            QMessageBox.warning(self, "数据加载错误", f"随礼数据加载失败: {str(e)}")


# ======================
# 账号密码管理页面
# ======================
class AccountPasswordPage(QWidget):
    def __init__(self):
        super().__init__()
        self.account_data = {
            'int_info_account': pd.DataFrame(columns=['id', '名称', '网址', '账号', '密码', '备注']),
            'personal_account': pd.DataFrame(columns=['id', '名称', '网址', '账号', '密码', '备注'])
        }
        self.current_table = 'int_info_account'
        self.init_ui()

    def init_ui(self):
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(20, 20, 20, 20)
        main_layout.setSpacing(20)

        # 标题
        title = QLabel("账号密码管理")
        title.setStyleSheet("""
            font-size: 24px;
            font-weight: bold;
            color: #2c3e50;
            padding-bottom: 10px;
            border-bottom: 2px solid #3498db;
        """)

        # 选项卡
        self.tabs = QTabWidget()
        self.tabs.setStyleSheet("""
            QTabWidget::pane {
                border: 1px solid #ddd;
                border-radius: 4px;
                background: white;
            }
            QTabBar::tab {
                background: #f8f9fa;
                border: 1px solid #ddd;
                border-bottom: none;
                padding: 10px 20px;
                font-size: 14px;
                border-top-left-radius: 4px;
                border-top-right-radius: 4px;
            }
            QTabBar::tab:selected {
                background: white;
                border-color: #3498db;
                color: #3498db;
                font-weight: bold;
            }
        """)

        # 创建两个选项卡
        self.tab1 = QWidget()
        self.tab2 = QWidget()


        self.tabs.addTab(self.tab1, "  单位账号  ")
        self.tabs.addTab(self.tab2, "  个人账号  ")
        self.tabs.currentChanged.connect(self.tab_changed)

        # 初始化选项卡内容
        self.init_tab(self.tab1, 'int_info_account')
        self.init_tab(self.tab2, 'personal_account')

        main_layout.addWidget(title)
        main_layout.addWidget(self.tabs)
        self.setLayout(main_layout)

    def init_tab(self, tab, table_name):
        layout = QVBoxLayout(tab)
        layout.setContentsMargins(10, 10, 10, 10)
        layout.setSpacing(15)

        # 操作栏
        action_bar = QWidget()
        action_layout = QHBoxLayout(action_bar)
        action_layout.setContentsMargins(0, 0, 0, 0)

        # 添加按钮
        add_btn = QPushButton("添加账号")
        add_btn.setIcon(QIcon.fromTheme("list-add"))
        add_btn.setStyleSheet("""
            QPushButton {
                background-color: #27ae60;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 8px 16px;
                font-size: 14px;
            }
            QPushButton:hover {
                background-color: #219653;
            }
        """)
        add_btn.clicked.connect(lambda: self.add_account(table_name))

        # 搜索框
        self.search_input = QLineEdit()
        self.search_input.setPlaceholderText("搜索名称、账号或备注...")
        self.search_input.setStyleSheet("""
            QLineEdit {
                border: 1px solid #ddd;
                border-radius: 4px;
                padding: 8px 12px;
                font-size: 14px;
            }
            QLineEdit:focus {
                border-color: #3498db;
            }
        """)
        self.search_input.textChanged.connect(self.filter_table)

        action_layout.addWidget(add_btn)
        action_layout.addStretch()
        action_layout.addWidget(self.search_input)

        # 表格
        table = QTableWidget()
        table.setColumnCount(6)
        table.setHorizontalHeaderLabels(['ID', '名称', '网址', '账号', '密码', '备注'])
        table.setSelectionBehavior(QAbstractItemView.SelectRows)
        table.setSelectionMode(QAbstractItemView.SingleSelection)
        table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        table.verticalHeader().setVisible(False)
        table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        table.horizontalHeader().setStyleSheet("""
            QHeaderView::section {
                background-color: #3498db;
                color: white;
                padding: 8px;
                border: none;
                font-weight: bold;
            }
        """)
        table.setStyleSheet("""
            QTableWidget {
                border: 1px solid #ddd;
                border-radius: 4px;
                gridline-color: #eee;
                font-size: 14px;
            }
            QTableWidget::item {
                padding: 10px;
            }
            QTableWidget::item:selected {
                background-color: #d6eaf8;
                color: black;
            }
        """)

        if table_name == 'int_info_account':
            self.table1 = table
        else:
            self.table2 = table

        # 按钮组
        btn_group = QWidget()
        btn_layout = QHBoxLayout(btn_group)
        btn_layout.setContentsMargins(0, 0, 0, 0)

        # 查看密码按钮
        view_pwd_btn = QPushButton("查看密码")
        view_pwd_btn.setStyleSheet("""
            QPushButton {
                background-color: #3498db;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 8px 16px;
                font-size: 14px;
            }
            QPushButton:hover {
                background-color: #2980b9;
            }
        """)
        view_pwd_btn.clicked.connect(lambda: self.view_password(table_name))

        # 编辑按钮
        edit_btn = QPushButton("编辑")
        edit_btn.setStyleSheet("""
            QPushButton {
                background-color: #f39c12;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 8px 16px;
                font-size: 14px;
            }
            QPushButton:hover {
                background-color: #d35400;
            }
        """)
        edit_btn.clicked.connect(lambda: self.edit_account(table_name))

        # 删除按钮
        delete_btn = QPushButton("删除")
        delete_btn.setStyleSheet("""
            QPushButton {
                background-color: #e74c3c;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 8px 16px;
                font-size: 14px;
            }
            QPushButton:hover {
                background-color: #c0392b;
            }
        """)
        delete_btn.clicked.connect(lambda: self.delete_account(table_name))

        btn_layout.addWidget(view_pwd_btn)
        btn_layout.addWidget(edit_btn)
        btn_layout.addWidget(delete_btn)
        btn_layout.addStretch()

        layout.addWidget(action_bar)
        layout.addWidget(table)
        layout.addWidget(btn_group)

    def tab_changed(self, index):
        self.current_table = 'int_info_account' if index == 0 else 'personal_account'

    def load_account_data(self):
        # 尝试从Excel文件加载数据
        try:
            # 内部信息账号
            df1 = pd.read_excel('账号密码.xls', sheet_name='int_info_account')
            if not df1.empty:
                self.account_data['int_info_account'] = df1
                self.populate_table(self.table1, df1)

            # 个人账号
            df2 = pd.read_excel('账号密码.xls', sheet_name='personal_account')
            if not df2.empty:
                self.account_data['personal_account'] = df2
                self.populate_table(self.table2, df2)
        except:
            # 如果文件不存在,创建空的DataFrame
            self.account_data = {
                'int_info_account': pd.DataFrame(columns=['id', '名称', '网址', '账号', '密码', '备注']),
                'personal_account': pd.DataFrame(columns=['id', '名称', '网址', '账号', '密码', '备注'])
            }

    def populate_table(self, table, df):
        table.setRowCount(len(df))

        for row_idx, row in df.iterrows():
            for col_idx, col in enumerate(['id', '名称', '网址', '账号', '密码', '备注']):
                item = QTableWidgetItem(str(row[col]) if pd.notna(row[col]) else "")
                table.setItem(row_idx, col_idx, item)

    def filter_table(self):
        search_text = self.search_input.text().lower()
        table = self.table1 if self.current_table == 'int_info_account' else self.table2
        df = self.account_data[self.current_table]

        if search_text:
            filtered_df = df[
                df['名称'].str.lower().str.contains(search_text) |
                df['账号'].str.lower().str.contains(search_text) |
                df['备注'].str.lower().str.contains(search_text)
                ]
        else:
            filtered_df = df

        self.populate_table(table, filtered_df)

    def add_account(self, table_name):
        dialog = AccountDialog()
        if dialog.exec_() == QDialog.Accepted:
            # 获取表单数据
            new_data = dialog.get_data()

            # 获取当前表数据
            df = self.account_data[table_name]

            # 生成新ID
            new_id = df['id'].max() + 1 if not df.empty else 1

            # 添加新行
            new_row = {
                'id': new_id,
                '名称': new_data['name'],
                '网址': new_data['url'],
                '账号': new_data['username'],
                '密码': new_data['password'],
                '备注': new_data['notes']
            }

            # 更新数据
            self.account_data[table_name] = pd.concat([df, pd.DataFrame([new_row])], ignore_index=True)

            # 更新表格
            table = self.table1 if table_name == 'int_info_account' else self.table2
            self.populate_table(table, self.account_data[table_name])

            # 保存到Excel
            self.save_account_data()

    def view_password(self, table_name):
        table = self.table1 if table_name == 'int_info_account' else self.table2
        selected_row = table.currentRow()

        if selected_row < 0:
            QMessageBox.warning(self, "操作失败", "请先选择一个账号")
            return

        # 获取密码
        password = table.item(selected_row, 4).text()

        # 显示密码
        QMessageBox.information(self, "密码信息", f"账号密码为: {password}")

    def edit_account(self, table_name):
        table = self.table1 if table_name == 'int_info_account' else self.table2
        selected_row = table.currentRow()

        if selected_row < 0:
            QMessageBox.warning(self, "操作失败", "请先选择一个账号")
            return

        # 获取当前行数据
        account_id = int(table.item(selected_row, 0).text())
        name = table.item(selected_row, 1).text()
        url = table.item(selected_row, 2).text()
        username = table.item(selected_row, 3).text()
        password = table.item(selected_row, 4).text()
        notes = table.item(selected_row, 5).text()

        # 打开编辑对话框
        dialog = AccountDialog(edit_mode=True)
        dialog.set_data({
            'name': name,
            'url': url,
            'username': username,
            'password': password,
            'notes': notes
        })

        if dialog.exec_() == QDialog.Accepted:
            # 获取更新后的数据
            updated_data = dialog.get_data()

            # 更新数据
            df = self.account_data[table_name]
            idx = df[df['id'] == account_id].index[0]

            df.at[idx, '名称'] = updated_data['name']
            df.at[idx, '网址'] = updated_data['url']
            df.at[idx, '账号'] = updated_data['username']
            df.at[idx, '密码'] = updated_data['password']
            df.at[idx, '备注'] = updated_data['notes']

            # 更新表格
            self.populate_table(table, df)

            # 保存到Excel
            self.save_account_data()

    def delete_account(self, table_name):
        table = self.table1 if table_name == 'int_info_account' else self.table2
        selected_row = table.currentRow()

        if selected_row < 0:
            QMessageBox.warning(self, "操作失败", "请先选择一个账号")
            return

        # 确认删除
        account_name = table.item(selected_row, 1).text()
        reply = QMessageBox.question(
            self, '确认删除',
            f"确定要删除账号 '{account_name}' 吗?",
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No
        )

        if reply == QMessageBox.Yes:
            # 获取ID
            account_id = int(table.item(selected_row, 0).text())

            # 从数据中删除
            df = self.account_data[table_name]
            self.account_data[table_name] = df[df['id'] != account_id]

            # 更新表格
            self.populate_table(table, self.account_data[table_name])

            # 保存到Excel
            self.save_account_data()

    def save_account_data(self):
        try:
            with pd.ExcelWriter('账号密码.xls') as writer:
                self.account_data['int_info_account'].to_excel(writer, sheet_name='int_info_account', index=False)
                self.account_data['personal_account'].to_excel(writer, sheet_name='personal_account', index=False)
        except Exception as e:
            QMessageBox.critical(self, "保存失败", f"数据保存失败: {str(e)}")


# ======================
# 账号对话框
# ======================
class AccountDialog(QDialog):
    def __init__(self, edit_mode=False):
        super().__init__()
        self.setWindowTitle("添加账号" if not edit_mode else "编辑账号")
        self.setFixedSize(500, 400)
        self.setStyleSheet("""
            QDialog {
                background-color: #f5f7fa;
                font-family: 'Microsoft YaHei';
            }
        """)

        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()
        layout.setContentsMargins(30, 20, 30, 20)
        layout.setSpacing(20)

        # 标题
        title = QLabel(self.windowTitle())
        title.setStyleSheet("""
            font-size: 20px;
            font-weight: bold;
            color: #2c3e50;
            padding-bottom: 10px;
            border-bottom: 1px solid #3498db;
        """)
        title.setAlignment(Qt.AlignCenter)

        # 表单
        form = QWidget()
        form_layout = QFormLayout(form)
        form_layout.setContentsMargins(20, 20, 20, 20)
        form_layout.setVerticalSpacing(15)
        form_layout.setHorizontalSpacing(20)

        # 名称
        self.name_input = QLineEdit()
        self.name_input.setPlaceholderText("必填")
        self.name_input.setStyleSheet("""
            QLineEdit {
                border: 1px solid #ddd;
                border-radius: 4px;
                padding: 8px;
                font-size: 14px;
            }
            QLineEdit:focus {
                border-color: #3498db;
            }
        """)

        # 网址
        self.url_input = QLineEdit()
        self.url_input.setPlaceholderText("例如: https://example.com")
        self.url_input.setStyleSheet(self.name_input.styleSheet())

        # 账号
        self.username_input = QLineEdit()
        self.username_input.setStyleSheet(self.name_input.styleSheet())

        # 密码
        self.password_input = QLineEdit()
        self.password_input.setEchoMode(QLineEdit.Password)
        self.password_input.setStyleSheet(self.name_input.styleSheet())

        # 显示密码按钮
        self.toggle_pwd_btn = QToolButton()
        self.toggle_pwd_btn.setIcon(QIcon.fromTheme("view-hidden"))
        self.toggle_pwd_btn.setCheckable(True)
        self.toggle_pwd_btn.setStyleSheet("""
            QToolButton {
                background-color: #e0e0e0;
                border: none;
                border-radius: 4px;
                padding: 5px;
            }
            QToolButton:hover {
                background-color: #d0d0d0;
            }
        """)
        self.toggle_pwd_btn.toggled.connect(self.toggle_password_visibility)

        pwd_layout = QHBoxLayout()
        pwd_layout.addWidget(self.password_input)
        pwd_layout.addWidget(self.toggle_pwd_btn)

        # 备注
        self.notes_input = QLineEdit()
        self.notes_input.setStyleSheet(self.name_input.styleSheet())

        # 添加表单行
        form_layout.addRow("名称:", self.name_input)
        form_layout.addRow("网址:", self.url_input)
        form_layout.addRow("账号:", self.username_input)
        form_layout.addRow("密码:", pwd_layout)
        form_layout.addRow("备注:", self.notes_input)

        # 按钮组
        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(15)

        # 保存按钮
        save_btn = QPushButton("保存")
        save_btn.setStyleSheet("""
            QPushButton {
                background-color: #27ae60;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 10px 20px;
                font-size: 14px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #219653;
            }
        """)
        save_btn.clicked.connect(self.validate_and_accept)

        # 取消按钮
        cancel_btn = QPushButton("取消")
        cancel_btn.setStyleSheet("""
            QPushButton {
                background-color: #95a5a6;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 10px 20px;
                font-size: 14px;
            }
            QPushButton:hover {
                background-color: #7f8c8d;
            }
        """)
        cancel_btn.clicked.connect(self.reject)

        btn_layout.addStretch()
        btn_layout.addWidget(save_btn)
        btn_layout.addWidget(cancel_btn)

        layout.addWidget(title)
        layout.addWidget(form)
        layout.addLayout(btn_layout)
        self.setLayout(layout)

    def toggle_password_visibility(self, checked):
        if checked:
            self.password_input.setEchoMode(QLineEdit.Normal)
            self.toggle_pwd_btn.setIcon(QIcon.fromTheme("view-visible"))
        else:
            self.password_input.setEchoMode(QLineEdit.Password)
            self.toggle_pwd_btn.setIcon(QIcon.fromTheme("view-hidden"))

    def set_data(self, data):
        self.name_input.setText(data['name'])
        self.url_input.setText(data['url'])
        self.username_input.setText(data['username'])
        self.password_input.setText(data['password'])
        self.notes_input.setText(data['notes'])

    def get_data(self):
        return {
            'name': self.name_input.text().strip(),
            'url': self.url_input.text().strip(),
            'username': self.username_input.text().strip(),
            'password': self.password_input.text(),
            'notes': self.notes_input.text().strip()
        }

    def validate_and_accept(self):
        if not self.name_input.text().strip():
            QMessageBox.warning(self, "输入错误", "名称不能为空")
            self.name_input.setFocus()
            return

        self.accept()


# ======================
# 随礼记录页面
# ======================
class GiftRecordPage(QWidget):
    def __init__(self):
        super().__init__()
        self.gift_data = pd.DataFrame(columns=['序号', '姓名', '事由', '金额'])
        self.init_ui()

    def init_ui(self):
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(20, 20, 20, 20)
        main_layout.setSpacing(20)

        # 标题
        title = QLabel("随礼记录管理")
        title.setStyleSheet("""
            font-size: 24px;
            font-weight: bold;
            color: #2c3e50;
            padding-bottom: 10px;
            border-bottom: 2px solid #9b59b6;
        """)

        # 操作栏
        action_bar = QWidget()
        action_layout = QHBoxLayout(action_bar)
        action_layout.setContentsMargins(0, 0, 0, 0)

        # 添加按钮
        add_btn = QPushButton("添加记录")
        add_btn.setIcon(QIcon.fromTheme("list-add"))
        add_btn.setStyleSheet("""
            QPushButton {
                background-color: #9b59b6;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 8px 16px;
                font-size: 14px;
            }
            QPushButton:hover {
                background-color: #8e44ad;
            }
        """)
        add_btn.clicked.connect(self.add_gift_record)

        # 搜索框
        self.search_input = QLineEdit()
        self.search_input.setPlaceholderText("搜索姓名或事由...")
        self.search_input.setStyleSheet("""
            QLineEdit {
                border: 1px solid #ddd;
                border-radius: 4px;
                padding: 8px 12px;
                font-size: 14px;
            }
            QLineEdit:focus {
                border-color: #9b59b6;
            }
        """)
        self.search_input.textChanged.connect(self.filter_table)

        # 统计标签
        self.sum_label = QLabel("总金额: 0元")
        self.sum_label.setStyleSheet("""
            font-size: 14px;
            font-weight: bold;
            color: #9b59b6;
            padding: 8px 12px;
        """)

        action_layout.addWidget(add_btn)
        action_layout.addStretch()
        action_layout.addWidget(self.search_input)
        action_layout.addSpacing(15)
        action_layout.addWidget(self.sum_label)

        # 表格
        self.table = QTableWidget()
        self.table.setColumnCount(4)
        self.table.setHorizontalHeaderLabels(['序号', '姓名', '事由', '金额'])
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.verticalHeader().setVisible(False)
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.table.horizontalHeader().setStyleSheet("""
            QHeaderView::section {
                background-color: #9b59b6;
                color: white;
                padding: 8px;
                border: none;
                font-weight: bold;
            }
        """)
        self.table.setStyleSheet("""
            QTableWidget {
                border: 1px solid #ddd;
                border-radius: 4px;
                gridline-color: #eee;
                font-size: 14px;
            }
            QTableWidget::item {
                padding: 10px;
            }
            QTableWidget::item:selected {
                background-color: #e8d5f0;
                color: black;
            }
        """)

        # 按钮组
        btn_group = QWidget()
        btn_layout = QHBoxLayout(btn_group)
        btn_layout.setContentsMargins(0, 0, 0, 0)

        # 编辑按钮
        edit_btn = QPushButton("编辑")
        edit_btn.setStyleSheet("""
            QPushButton {
                background-color: #f39c12;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 8px 16px;
                font-size: 14px;
            }
            QPushButton:hover {
                background-color: #d35400;
            }
        """)
        edit_btn.clicked.connect(self.edit_gift_record)

        # 删除按钮
        delete_btn = QPushButton("删除")
        delete_btn.setStyleSheet("""
            QPushButton {
                background-color: #e74c3c;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 8px 16px;
                font-size: 14px;
            }
            QPushButton:hover {
                background-color: #c0392b;
            }
        """)
        delete_btn.clicked.connect(self.delete_gift_record)

        btn_layout.addWidget(edit_btn)
        btn_layout.addWidget(delete_btn)
        btn_layout.addStretch()

        main_layout.addWidget(title)
        main_layout.addWidget(action_bar)
        main_layout.addWidget(self.table)
        main_layout.addWidget(btn_group)
        self.setLayout(main_layout)

    def load_gift_data(self):
        # 尝试从Excel文件加载数据
        try:
            df = pd.read_excel('随礼记录.xls')
            if not df.empty:
                self.gift_data = df
                self.populate_table()
        except:
            # 如果文件不存在,创建空的DataFrame
            self.gift_data = pd.DataFrame(columns=['序号', '姓名', '事由', '金额'])

    def populate_table(self):
        self.table.setRowCount(len(self.gift_data))

        for row_idx, row in self.gift_data.iterrows():
            for col_idx, col in enumerate(['序号', '姓名', '事由', '金额']):
                item = QTableWidgetItem(str(row[col]) if pd.notna(row[col]) else "")
                self.table.setItem(row_idx, col_idx, item)

        # 更新总金额
        total = self.gift_data['金额'].sum()
        self.sum_label.setText(f"总金额: {total}元")

    def filter_table(self):
        search_text = self.search_input.text().lower()

        if search_text:
            filtered_df = self.gift_data[
                self.gift_data['姓名'].str.lower().str.contains(search_text) |
                self.gift_data['事由'].str.lower().str.contains(search_text)
                ]
        else:
            filtered_df = self.gift_data

        self.table.setRowCount(len(filtered_df))

        for row_idx, row in filtered_df.iterrows():
            for col_idx, col in enumerate(['序号', '姓名', '事由', '金额']):
                item = QTableWidgetItem(str(row[col]) if pd.notna(row[col]) else "")
                self.table.setItem(row_idx, col_idx, item)

        # 更新总金额
        total = filtered_df['金额'].sum()
        self.sum_label.setText(f"总金额: {total}元")

    def add_gift_record(self):
        dialog = GiftDialog()
        if dialog.exec_() == QDialog.Accepted:
            # 获取表单数据
            new_data = dialog.get_data()

            # 生成新ID
            new_id = self.gift_data['序号'].max() + 1 if not self.gift_data.empty else 1

            # 添加新行
            new_row = {
                '序号': new_id,
                '姓名': new_data['name'],
                '事由': new_data['reason'],
                '金额': new_data['amount']
            }

            # 更新数据
            self.gift_data = pd.concat([self.gift_data, pd.DataFrame([new_row])], ignore_index=True)

            # 更新表格
            self.populate_table()

            # 保存到Excel
            self.save_gift_data()

    def edit_gift_record(self):
        selected_row = self.table.currentRow()

        if selected_row < 0:
            QMessageBox.warning(self, "操作失败", "请先选择一个记录")
            return

        # 获取当前行数据
        record_id = int(self.table.item(selected_row, 0).text())
        name = self.table.item(selected_row, 1).text()
        reason = self.table.item(selected_row, 2).text()
        amount = float(self.table.item(selected_row, 3).text())

        # 打开编辑对话框
        dialog = GiftDialog(edit_mode=True)
        dialog.set_data({
            'name': name,
            'reason': reason,
            'amount': amount
        })

        if dialog.exec_() == QDialog.Accepted:
            # 获取更新后的数据
            updated_data = dialog.get_data()

            # 更新数据
            idx = self.gift_data[self.gift_data['序号'] == record_id].index[0]

            self.gift_data.at[idx, '姓名'] = updated_data['name']
            self.gift_data.at[idx, '事由'] = updated_data['reason']
            self.gift_data.at[idx, '金额'] = updated_data['amount']

            # 更新表格
            self.populate_table()

            # 保存到Excel
            self.save_gift_data()

    def delete_gift_record(self):
        selected_row = self.table.currentRow()

        if selected_row < 0:
            QMessageBox.warning(self, "操作失败", "请先选择一个记录")
            return

        # 确认删除
        person_name = self.table.item(selected_row, 1).text()
        reply = QMessageBox.question(
            self, '确认删除',
            f"确定要删除 '{person_name}' 的随礼记录吗?",
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No
        )

        if reply == QMessageBox.Yes:
            # 获取ID
            record_id = int(self.table.item(selected_row, 0).text())

            # 从数据中删除
            self.gift_data = self.gift_data[self.gift_data['序号'] != record_id]

            # 更新表格
            self.populate_table()

            # 保存到Excel
            self.save_gift_data()

    def save_gift_data(self):
        try:
            self.gift_data.to_excel('随礼记录.xls', index=False)
        except Exception as e:
            QMessageBox.critical(self, "保存失败", f"数据保存失败: {str(e)}")


# ======================
# 随礼对话框
# ======================
class GiftDialog(QDialog):
    def __init__(self, edit_mode=False):
        super().__init__()
        self.setWindowTitle("添加随礼记录" if not edit_mode else "编辑随礼记录")
        self.setFixedSize(400, 300)
        self.setStyleSheet("""
            QDialog {
                background-color: #f5f7fa;
                font-family: 'Microsoft YaHei';
            }
        """)

        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()
        layout.setContentsMargins(30, 20, 30, 20)
        layout.setSpacing(20)

        # 标题
        title = QLabel(self.windowTitle())
        title.setStyleSheet("""
            font-size: 20px;
            font-weight: bold;
            color: #2c3e50;
            padding-bottom: 10px;
            border-bottom: 1px solid #9b59b6;
        """)
        title.setAlignment(Qt.AlignCenter)

        # 表单
        form = QWidget()
        form_layout = QFormLayout(form)
        form_layout.setContentsMargins(20, 20, 20, 20)
        form_layout.setVerticalSpacing(15)
        form_layout.setHorizontalSpacing(20)

        # 姓名
        self.name_input = QLineEdit()
        self.name_input.setStyleSheet("""
            QLineEdit {
                border: 1px solid #ddd;
                border-radius: 4px;
                padding: 8px;
                font-size: 14px;
            }
            QLineEdit:focus {
                border-color: #9b59b6;
            }
        """)

        # 事由
        self.reason_input = QLineEdit()
        self.reason_input.setStyleSheet(self.name_input.styleSheet())

        # 金额
        self.amount_input = QLineEdit()
        self.amount_input.setStyleSheet(self.name_input.styleSheet())

        form_layout.addRow("姓名:", self.name_input)
        form_layout.addRow("事由:", self.reason_input)
        form_layout.addRow("金额:", self.amount_input)

        # 按钮组
        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(15)

        # 保存按钮
        save_btn = QPushButton("保存")
        save_btn.setStyleSheet("""
            QPushButton {
                background-color: #9b59b6;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 10px 20px;
                font-size: 14px;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #8e44ad;
            }
        """)
        save_btn.clicked.connect(self.validate_and_accept)

        # 取消按钮
        cancel_btn = QPushButton("取消")
        cancel_btn.setStyleSheet("""
            QPushButton {
                background-color: #95a5a6;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 10px 20px;
                font-size: 14px;
            }
            QPushButton:hover {
                background-color: #7f8c8d;
            }
        """)
        cancel_btn.clicked.connect(self.reject)

        btn_layout.addStretch()
        btn_layout.addWidget(save_btn)
        btn_layout.addWidget(cancel_btn)

        layout.addWidget(title)
        layout.addWidget(form)
        layout.addLayout(btn_layout)
        self.setLayout(layout)

    def set_data(self, data):
        self.name_input.setText(data['name'])
        self.reason_input.setText(data['reason'])
        self.amount_input.setText(str(data['amount']))

    def get_data(self):
        return {
            'name': self.name_input.text().strip(),
            'reason': self.reason_input.text().strip(),
            'amount': float(self.amount_input.text()) if self.amount_input.text() else 0
        }

    def validate_and_accept(self):
        if not self.name_input.text().strip():
            QMessageBox.warning(self, "输入错误", "姓名不能为空")
            self.name_input.setFocus()
            return

        try:
            float(self.amount_input.text())
        except ValueError:
            QMessageBox.warning(self, "输入错误", "金额必须是数字")
            self.amount_input.setFocus()
            return

        self.accept()


# ======================
# 应用入口
# ======================
if __name__ == "__main__":
    app = QApplication(sys.argv)

    # 创建并显示登录对话框
    login_dialog = LoginDialog()
    if login_dialog.exec_() == QDialog.Accepted:
        main_window = MainWindow()
        main_window.show()
        sys.exit(app.exec_())


个人账号密码:admin/password,因为是自己一个人用,所以很多设计没有那么完善
效果图如下:

微信图片_20250718090744.png (40.27 KB, 下载次数: 4)

微信图片_20250718090744.png

微信图片_20250718090730.png (27.63 KB, 下载次数: 0)

微信图片_20250718090730.png

微信图片_20250718090739.png (43.77 KB, 下载次数: 0)

微信图片_20250718090739.png

免费评分

参与人数 6吾爱币 +12 热心值 +5 收起 理由
homdjan + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
erhubali008 + 1 + 1 谢谢@Thanks!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
thornjay + 1 + 1 我很赞同!
shengruqing + 1 热心回复!
cioceo + 1 + 1 之前我接触到一个相似软件KeePass,点击可复制账号密码

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
toufaluanle 发表于 2026-7-14 11:00
phantomxjc 发表于 2026-7-14 10:55
你想要啥样的

比如这个网址里面的  有软件分类  游戏分类 可以快捷启动改软件  又可以添加多个预览图 预览  类似链接里面的 模块
https://www.52pojie.cn/thread-2116704-1-1.html
推荐
lxzblack 发表于 2026-8-16 21:08
很棒,公司及个人账户信息管理、财务收支管理等等这些都包括,像是家里的日常支出、车辆保养记录啥的,自己可以编辑管理就挺好的,而且本地化管理,不牵扯信息泄露,数据库可以备份吧?很不错的工具了……
沙发
orz4260 发表于 2025-7-18 10:01
很棒,公司及个人账户信息管理、财务收支管理等等这些都包括,像是家里的日常支出、车辆保养记录啥的,自己可以编辑管理就挺好的,而且本地化管理,不牵扯信息泄露,数据库可以备份吧?很不错的工具了……
3#
y6862854 发表于 2025-7-18 10:01
你好,可以打包exe吗?谢谢。
4#
m_h 发表于 2025-7-18 10:08
除非有浏览器 账号密码填写插件,不然不知道这个能干嘛。。
5#
naixubao 发表于 2025-7-18 10:11
楼主,原创辛苦了,麻烦发个成品软件,谢谢。
6#
jy3399 发表于 2025-7-18 10:19
前段时间公司也有个人说用python写了些页面,还好奇用什么写的,看来应该就是这个东西了,受教!
7#
萝卜就是甜 发表于 2025-7-18 10:36
学习了。真的狠不错!
8#
shen13246579 发表于 2025-7-18 10:38
楼主,原创辛苦了,学习了。真的狠不错!
9#
blakeyi 发表于 2025-7-18 10:39
可以考虑做成插件
10#
wodeweiyimpm 发表于 2025-7-18 10:41
这个好用 可以记账
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-9-6 22:03

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表