排除LhPyQt5疑难bug的经验

一、排雷结果

复制代码
import re
from datetime import datetime
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QStyledItemDelegate, QStyle, QGraphicsDropShadowEffect, QAbstractItemView

from LhPyQt5.LhQt5 import *


# ======================== 快速找回密码窗口 ========================
class FindPasswordDialog(QDialog):
    def __init__(self, customer_account=None, parent=None):
        super().__init__(parent)
        self.customer_account = customer_account
        self.setWindowTitle("快速找回密码")
        self.setFixedWidth(500)
        self.matched_user = None
        self.init_ui()

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

        hint_label = QLabel("请至少填写用户账号或联系方式其中一项")
        layout.addWidget(hint_label)

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(20)

        self.account_edit = QLineEdit()
        self.account_edit.setPlaceholderText("请输入用户账号")
        self.phone_edit = QLineEdit()
        self.phone_edit.setPlaceholderText("请输入联系方式")
        self.question_edit = QLineEdit()
        self.question_edit.setReadOnly(True)
        self.question_edit.setPlaceholderText("验证通过后自动显示")
        self.answer_edit = QLineEdit()
        self.answer_edit.setPlaceholderText("请输入密保答案")

        form_layout.addRow("用户账号:", self.account_edit)
        form_layout.addRow("联系方式:", self.phone_edit)
        form_layout.addRow("密保问题:", self.question_edit)
        form_layout.addRow("密码答案:", self.answer_edit)
        layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setFixedHeight(40)
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(40)
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)
class FindPasswordDialog2(QDialog):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.setWindowTitle("快速找回密码")
        self.resize(500,350)
        self.init_ui()

    def init_ui(self):

        # 主布局:表单布局
        layout = QFormLayout(self)
        layout.setSpacing(20)
        layout.setContentsMargins(40, 40, 40, 40)

        hint_label = QLabel("请至少填写用户账号或联系方式其中一项")
        layout.addRow(hint_label)

        self.account_edit = QLineEdit()
        self.account_edit.setPlaceholderText("请输入用户账号")
        self.phone_edit = QLineEdit()
        self.phone_edit.setPlaceholderText("请输入联系方式")
        self.question_edit = QLineEdit()
        self.question_edit.setReadOnly(True)
        self.question_edit.setPlaceholderText("验证通过后自动显示")
        self.answer_edit = QLineEdit()
        self.answer_edit.setPlaceholderText("请输入密保答案")

        layout.addRow("用户账号:", self.account_edit)
        layout.addRow("联系方式:", self.phone_edit)
        layout.addRow("密保问题:", self.question_edit)
        layout.addRow("密码答案:", self.answer_edit)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setFixedHeight(40)
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(40)
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addRow("",btn_layout)
class FindPasswordDialog6(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("快速找回密码")
        self.resize(500, 350)
        self.init_ui()

    def init_ui(self):
        # 主布局:表单布局
        layout = QFormLayout(self)
        layout.setSpacing(20)
        layout.setContentsMargins(40, 40, 40, 40)

        # 顶部提示文字
        self.tip_label = QLabel("请至少填写用户账号或联系方式其中一项")
        layout.addRow(self.tip_label)

        # 1. 用户账号
        self.account_edit = QLineEdit()
        self.account_edit.setPlaceholderText("请输入用户账号")
        layout.addRow("用户账号:", self.account_edit)

        # 2. 联系方式
        self.contact_edit = QLineEdit()
        self.contact_edit.setPlaceholderText("请输入联系方式")
        layout.addRow("联系方式:", self.contact_edit)

        # 3. 密保问题(只读)
        self.question_edit = QLineEdit()
        self.question_edit.setPlaceholderText("验证通过后自动显示")
        self.question_edit.setReadOnly(True)  # 模拟验证后自动填充
        layout.addRow("密保问题:", self.question_edit)

        # 4. 密保答案
        self.answer_edit = QLineEdit()
        self.answer_edit.setPlaceholderText("请输入密保答案")
        layout.addRow("密码答案:", self.answer_edit)

        # 按钮布局
        btn_layout = QHBoxLayout()
        self.ok_btn = QPushButton("确定")
        self.cancel_btn = QPushButton("取消")
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        layout.addRow("", btn_layout)

class FindPwdDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("快速找回密码")
        self.resize(500, 350)
        self.init_ui()

    def init_ui(self):
        # 主布局:表单布局
        layout = QFormLayout(self)
        layout.setSpacing(20)
        layout.setContentsMargins(40, 40, 40, 40)

        # 顶部提示文字
        self.tip_label = QLabel("请至少填写用户账号或联系方式其中一项")
        layout.addRow(self.tip_label)

        # 1. 用户账号
        self.account_edit = QLineEdit()
        self.account_edit.setPlaceholderText("请输入用户账号")
        layout.addRow("用户账号:", self.account_edit)

        # 2. 联系方式
        self.contact_edit = QLineEdit()
        self.contact_edit.setPlaceholderText("请输入联系方式")
        layout.addRow("联系方式:", self.contact_edit)

        # 3. 密保问题(只读)
        self.question_edit = QLineEdit()
        self.question_edit.setPlaceholderText("验证通过后自动显示")
        self.question_edit.setReadOnly(True)  # 模拟验证后自动填充
        layout.addRow("密保问题:", self.question_edit)

        # 4. 密保答案
        self.answer_edit = QLineEdit()
        self.answer_edit.setPlaceholderText("请输入密保答案")
        layout.addRow("密码答案:", self.answer_edit)

        # 按钮布局
        btn_layout = QHBoxLayout()
        self.ok_btn = QPushButton("确定")
        self.cancel_btn = QPushButton("取消")
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        layout.addRow("", btn_layout)


# ======================== 主窗口 ========================
class MainWindow(QWidget):
    def __init__(self, account, net_name, phone, password):
        super().__init__()
        self.account = account
        self.net_name = net_name
        self.phone = phone
        self.password = password
        self.set_theme("暖茶棕")
        self.setWindowTitle("我的主窗口")
        self.resize(400, 400)
        self.init_ui()

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

        title = QLabel(f"欢迎,{self.net_name}")
        title.setAlignment(Qt.AlignCenter)
        layout.addWidget(title)
        b1=QPushButton("找回密码1")
        b2=QPushButton("找回密码2")
        b3=QPushButton("找回密码3")
        b6=QPushButton("找回密码6")
        layout.addWidget(b1)
        layout.addWidget(b2)
        layout.addWidget(b3)
        layout.addWidget(b6)
        b1.clicked.connect(self.open_find_password1)
        b2.clicked.connect(self.open_find_password2)
        b3.clicked.connect(self.open_find_password3)
        b6.clicked.connect(self.open_find_password6)



    def open_find_password1(self):
        dlg = FindPasswordDialog(customer_account=self.account, parent=self)
        dlg.exec_()
    def open_find_password2(self):
        dlg = FindPwdDialog() # 这个窗口QLabel文字下没有阴影,同其他3个窗口的区别就是在于没有传入parent=self
        dlg.exec_()
    def open_find_password3(self):
        dlg = FindPasswordDialog2()
        dlg.exec_()
    def open_find_password6(self):
        dlg = FindPasswordDialog6(parent=self)
        dlg.exec_()


# ======================== 程序入口 ========================
if __name__ == "__main__":
    config = {
        'applicationName': 'PyQt5 主题化控件库演示',
        'organizationName': 'MyCompany',
        'organizationDomain': 'mycompany.com',
        'applicationVersion': '2.0',
        'windowIcon': 'fox.ico',
        'font': {
            'family': 'Microsoft YaHei',
            'pointSize': 10,
            'weight': QFont.Normal
        },
        'translatorPath': 'qt_zh_CN.qm'
    }

    app = QApplication(sys.argv,config)
    win=MainWindow(account="A00001", net_name="大白不白", phone="17550629195", password="xiaob0370")
    win.show()
    sys.exit(app.exec_())

删除代码中所有QSS样式设置 - DeepSeek

二、排雷后

复制代码
import json
import re
from datetime import datetime

from PyQt5.QtCore import *
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QStyledItemDelegate, QStyle, QGraphicsDropShadowEffect, QAbstractItemView

from DB.UserDB import UserDB
from SecurityCrypto.SecurityCrypto import SecurityCrypto
from MyClass.BLHQT5 import *
# ======================== 全局实例 ========================
crypto = SecurityCrypto(key_salt="海算销售密钥盐", master_password="HaiSuan@2025")
db = UserDB(user_table="product_customer")

# ======================== 自动换行且垂直居中的委托 ========================
class WordWrapDelegate(QStyledItemDelegate):
    def paint(self, painter, option, index):
        text = index.data(Qt.DisplayRole)
        if not text:
            return super().paint(painter, option, index)

        if option.state & QStyle.State_Selected:
            painter.fillRect(option.rect, option.palette.highlight())

        painter.save()
        doc = QTextDocument()
        doc.setDefaultFont(option.font)
        doc.setHtml(str(text))
        doc.setTextWidth(option.rect.width())

        content_height = doc.size().height()
        y_offset = option.rect.top() + max(0, (option.rect.height() - content_height) // 2)
        painter.translate(option.rect.left(), y_offset)
        doc.drawContents(painter)
        painter.restore()

    def sizeHint(self, option, index):
        text = index.data(Qt.DisplayRole)
        if not text:
            return super().sizeHint(option, index)
        doc = QTextDocument()
        doc.setDefaultFont(option.font)
        doc.setHtml(str(text))
        doc.setTextWidth(option.rect.width())
        return QSize(int(doc.idealWidth()), int(doc.size().height()))


# ======================== 自定义窗口基类 ========================
class BaseWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.setGraphicsEffect(self.create_shadow())

    def create_shadow(self):
        shadow = QGraphicsDropShadowEffect()
        shadow.setBlurRadius(30)
        shadow.setXOffset(0)
        shadow.setYOffset(0)
        shadow.setColor(QColor(0, 0, 0, 80))
        return shadow

# ======================== 登录窗口 ========================
class LoginWindow(BaseWidget):
    def __init__(self):
        super().__init__()
        self.setGraphicsEffect(None)
        self.set_theme("暖茶棕")
        self.initUI()

    def initUI(self):
        self.setWindowTitle('企业管理系统 - 登录')
        self.setFixedSize(900, 550)
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)

        main_layout = QHBoxLayout(self)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.setSpacing(0)

        # 左侧区域(蓝色#4F7EF7)
        left_widget = QtWidgets.QWidget()
        left_widget.setObjectName("left_widget")
        left_layout = QVBoxLayout()
        left_layout.setContentsMargins(40, 40, 40, 40)

        title_label = QLabel("企业管理系统")
        title_label.setAlignment(Qt.AlignHCenter)
        title_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 36px; font-weight: bold; color: white;")

        subtitle_label = QLabel("精准营销·业绩倍增")
        subtitle_label.setAlignment(Qt.AlignHCenter)
        subtitle_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-weight: bold; font-size: 24px; color: rgba(255,255,255,0.9); margin-top: 15px;")

        slogan_label = QLabel("提升销售效率\n优化客户关系\n加速业务增长")
        slogan_label.setAlignment(Qt.AlignCenter)
        slogan_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 22px; color: white; margin-top: 60px; line-height: 1.8; background-color: rgba(255,255,255,0.1); border-radius: 10px; padding: 10px;")

        support_label = QLabel("技术支持:海算(海南)信息有限公司\n服务热线:15890561786")
        support_label.setAlignment(Qt.AlignCenter)
        support_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 18px; color: white; margin-top: 40px; line-height: 1.5;")

        left_layout.addSpacing(80)
        left_layout.addWidget(title_label)
        left_layout.addWidget(subtitle_label)
        left_layout.addWidget(slogan_label)
        left_layout.addWidget(support_label)
        left_widget.setLayout(left_layout)
        left_widget.setStyleSheet(f"QWidget#left_widget{{background-color: {GlobalTheme.color['primary']}; border-top-left-radius: 15px; border-bottom-left-radius: 15px; }}")

        # 右侧区域(白色)
        right_widget = QtWidgets.QWidget()
        right_widget.setObjectName("right_widget")
        right_layout = QVBoxLayout()
        right_layout.setContentsMargins(20, 20, 20, 20)

        top_bar = QHBoxLayout()
        top_bar.addStretch()
        close_btn = QToolButton()
        close_btn.setText("×")
        close_btn.setFixedSize(40, 40)
        close_btn.setStyleSheet("QToolButton { font-family: 'Microsoft YaHei'; font-size: 30px; font-weight: bold; color: #999; border: none; background: transparent; } QToolButton:hover { color: #333; background-color: #f5f5f5; border-radius: 10px; }")
        close_btn.clicked.connect(self.close)
        top_bar.addWidget(close_btn)

        version_label = QLabel("海算企业管理系统 V1.01")
        version_label.setAlignment(Qt.AlignCenter)
        version_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 32px; font-weight: bold; color: #333; margin-top: 10px; margin-bottom: 20px;")

        form_layout = QVBoxLayout()
        form_layout.setSpacing(25)

        username_widget = QtWidgets.QWidget()
        username_layout = QVBoxLayout(username_widget)
        username_layout.setContentsMargins(50, 0, 50, 0)
        username_label = QLabel("账号")
        username_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 20px; color: black; margin-bottom: 5px;")
        self.username_input = QLineEdit()
        self.username_input.setPlaceholderText("请输入账号")
        self.username_input.setFixedHeight(45)
        # self.username_input.setStyleSheet("QLineEdit { font-family: 'Microsoft YaHei'; font-size: 18px; border: 1px solid #d0d7e5; border-radius: 8px; padding: 0 15px; background-color: white; } QLineEdit:focus { border: 2px solid #4F7EF7; padding: 0 14px; }")
        username_layout.addWidget(username_label)
        username_layout.addWidget(self.username_input)

        password_widget = QtWidgets.QWidget()
        password_layout = QVBoxLayout(password_widget)
        password_layout.setContentsMargins(50, 0, 50, 0)
        password_label = QLabel("密码")
        password_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 20px; color: black; margin-bottom: 5px;")
        self.password_input = QLineEdit()
        self.password_input.setPlaceholderText("请输入密码")
        self.password_input.setEchoMode(QLineEdit.Password)
        self.password_input.setFixedHeight(45)
        # self.password_input.setStyleSheet("QLineEdit { font-family: 'Microsoft YaHei'; font-size: 18px; border: 1px solid #d0d7e5; border-radius: 8px; padding: 0 15px; background-color: white; } QLineEdit:focus { border: 2px solid #4F7EF7; padding: 0 14px; }")
        password_layout.addWidget(password_label)
        password_layout.addWidget(self.password_input)

        form_layout.addWidget(username_widget)
        form_layout.addWidget(password_widget)

        forgot_layout = QHBoxLayout()
        forgot_layout.setContentsMargins(50, 0, 50, 0)
        self.forgot_label = QLabel(f"<a href='#' style='color: {GlobalTheme.color['primary']}; text-decoration: none; font-family: \"Microsoft YaHei\"; font-size: 22px;'>忘记密码?</a>")
        self.forgot_label.setOpenExternalLinks(False)
        self.forgot_label.linkActivated.connect(self.on_forgot_password)
        forgot_layout.addStretch()
        forgot_layout.addWidget(self.forgot_label)

        button_layout = QHBoxLayout()
        button_layout.setSpacing(20)
        self.login_btn = QPushButton("登录")
        self.login_btn.setFixedWidth(120)
        self.login_btn.setFixedHeight(45)
        self.login_btn.setObjectName("primaryBtn")
        self.login_btn.clicked.connect(self.on_login)

        self.register_btn = QPushButton("注册")
        self.register_btn.setFixedWidth(120)
        self.register_btn.setFixedHeight(45)
        self.register_btn.setObjectName("secondaryBtn")
        self.register_btn.clicked.connect(self.on_register)

        button_layout.addStretch()
        button_layout.addWidget(self.login_btn)
        button_layout.addWidget(self.register_btn)
        button_layout.addStretch()

        copyright_label = QLabel(f"© {datetime.today().year} Sales Management System. All rights reserved.")
        copyright_label.setAlignment(Qt.AlignCenter)
        copyright_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 16px; color: #999999; margin-top: 15px;")

        right_layout.addLayout(top_bar)
        right_layout.addWidget(version_label)
        right_layout.addLayout(form_layout)
        right_layout.addSpacing(5)
        right_layout.addLayout(forgot_layout)
        right_layout.addSpacing(20)
        right_layout.addLayout(button_layout)
        right_layout.addStretch()
        right_layout.addWidget(copyright_label)

        right_widget.setLayout(right_layout)
        right_widget.setStyleSheet("QWidget#right_widget { background-color: #ffffff; border-top-right-radius: 15px; border-bottom-right-radius: 15px; }")

        main_layout.addWidget(left_widget, 40)
        main_layout.addWidget(right_widget, 60)

        self.setStyleSheet("""
            QWidget { font-family: "Microsoft YaHei"; }
        """)

    def on_login(self):
        username = self.username_input.text().strip()
        password = self.password_input.text().strip()
        if not username or not password:
            QMessageBox.warning(self, "警告", "请输入账号和密码!")
            return

        user = db.get_user_by_account(username)
        if not user:
            QMessageBox.warning(self, "警告", "账号不存在!")
            return
        if crypto.verify_hash(password, user["customer_pwd"]) != 0:
            QMessageBox.warning(self, "警告", "密码错误!")
            return
        self.close()
        self.main_window = MainWindow(account=user["customer_account"], net_name=user["customer_netname"],
                                      phone=crypto.decrypt(user["contact_phone"]), password=password)
        self.main_window.show()

    def on_register(self):
        dialog = RegisterDialog(product_name="云约智能(企业版)", parent=self)
        dialog.exec_()

    def on_forgot_password(self):
        dialog = FindPasswordDialog(customer_account=None, parent=self)
        dialog.exec_()

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drag_pos = event.globalPos() - self.frameGeometry().topLeft()
            event.accept()

    def mouseMoveEvent(self, event):
        if event.buttons() == Qt.LeftButton:
            self.move(event.globalPos() - self.drag_pos)
            event.accept()



# ======================== 注册窗口 ========================
class RegisterDialog(QDialog):
    def __init__(self, product_name="云约智能(企业版)", parent=None):
        super().__init__(parent)
        self.product_name = product_name
        self.setWindowTitle("用户注册")
        self.setFixedWidth(600)
        self.custom_index = None
        self.previous_index = None
        self.ignore_index_change = False
        self.init_ui()


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

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(15)

        self.account_edit = QLineEdit()
        self.account_edit.setPlaceholderText("8~12位字母或数字")
        form_layout.addRow("用户账号:", self.account_edit)

        self.netname_edit = QLineEdit()
        self.netname_edit.setPlaceholderText("18个以内汉字、字母或数字")
        form_layout.addRow("用户网名:", self.netname_edit)

        self.password_edit = QLineEdit()
        self.password_edit.setEchoMode(QLineEdit.Password)
        self.password_edit.setPlaceholderText("8~18位字母或数字")
        form_layout.addRow("登录密码:", self.password_edit)

        self.confirm_password_edit = QLineEdit()
        self.confirm_password_edit.setEchoMode(QLineEdit.Password)
        self.confirm_password_edit.setPlaceholderText("请确认密码")
        form_layout.addRow("确认密码:", self.confirm_password_edit)

        self.phone_edit = QLineEdit()
        self.phone_edit.setPlaceholderText("请输入真实手机号或固定电话")
        form_layout.addRow("联系方式:", self.phone_edit)

        self.security_combo = QComboBox()
        self.security_combo.addItems(["您母亲的姓名?", "您父亲的姓名?", "自定义"])
        self.custom_index = 2
        self.security_combo.currentIndexChanged.connect(self.on_security_combo_changed)
        form_layout.addRow("密保问题:", self.security_combo)

        self.security_answer_edit = QLineEdit()
        form_layout.addRow("密保答案:", self.security_answer_edit)

        self.referral_code_edit = QLineEdit()
        self.referral_code_edit.setPlaceholderText("推荐码(选填)")
        form_layout.addRow("推荐码:", self.referral_code_edit)

        main_layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setFixedHeight(40)
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(40)
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        main_layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.validate_and_register)
        self.cancel_btn.clicked.connect(self.reject)


    def on_security_combo_changed(self, index):
        if self.ignore_index_change:
            return
        if index == self.custom_index:
            new_question, ok = QInputDialog.getText(self, "自定义密保问题", "请输入您的自定义密保问题:")
            if ok and new_question.strip():
                self.ignore_index_change = True
                self.security_combo.insertItem(self.custom_index, new_question.strip())
                self.security_combo.setCurrentIndex(self.custom_index)
                self.custom_index += 1
                self.ignore_index_change = False
            else:
                self.ignore_index_change = True
                self.security_combo.setCurrentIndex(self.previous_index if self.previous_index is not None else 0)
                self.ignore_index_change = False
        else:
            self.previous_index = index

    def validate_and_register(self):
        account = self.account_edit.text().strip()
        netname = self.netname_edit.text().strip()
        password = self.password_edit.text().strip()
        confirm = self.confirm_password_edit.text().strip()
        phone = self.phone_edit.text().strip()
        security_q = self.security_combo.currentText().strip()
        security_a = self.security_answer_edit.text().strip()
        referral = self.referral_code_edit.text().strip()

        if not all([account, netname, password, confirm, phone, security_q, security_a]):
            QMessageBox.warning(self, "验证失败", "所有带*号为必填项,请填写完整。")
            return

        if not re.match(r'^[a-zA-Z0-9]{8,12}$', account):
            QMessageBox.warning(self, "验证失败", "账号必须为8~12位字母或数字。")
            return

        if not re.match(r'^[\u4e00-\u9fa5a-zA-Z0-9]{1,18}$', netname):
            QMessageBox.warning(self, "验证失败", "网名必须为18个以内汉字、字母或数字。")
            return

        if not re.match(r'^[a-zA-Z0-9]{8,18}$', password):
            QMessageBox.warning(self, "验证失败", "密码必须为8~18位字母或数字。")
            return
        if password != confirm:
            QMessageBox.warning(self, "验证失败", "两次输入的密码不一致。")
            return

        if not re.match(r'^(\d{11}|\d{3,4}-?\d{7,8})$', phone):
            QMessageBox.warning(self, "验证失败", "请输入正确的手机号或固定电话。")
            return

        if db.is_account_exist(account):
            QMessageBox.warning(self, "验证失败", "该账号已存在。")
            return

        hash_phone = crypto.generate_query_hash(phone)
        if db.is_phone_exist(self.product_name, hash_phone):
            QMessageBox.warning(self, "验证失败", "该联系方式已在该产品下注册。")
            return

        if referral:
            if not self.verify_referral(referral):
                QMessageBox.warning(self, "验证失败", "推荐码无效。")
                return

        hashed_pwd = crypto.generate_hash(password)
        encrypted_phone = crypto.encrypt(phone)

        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        security_info = json.dumps([{"pwd_question": security_q, "pwd_answer": security_a, "operator": account, "operate_time": now}])
        sales_info = json.dumps([{"sales_account": account, "parent_sales": "F008216", "sales_director": "F008888", "operator": account, "operate_time": now}])
        register_ip, register_area = self.get_ip_and_area()
        register_info = json.dumps([{"register_time": now, "register_area": register_area, "register_ip": register_ip}])

        try:
            db.register_user(
                self.product_name, account, hashed_pwd, netname, encrypted_phone, hash_phone,
                now, None, security_info, sales_info, register_info
            )
            QMessageBox.information(self, "成功", "注册成功!")
            self.accept()
        except Exception as e:
            QMessageBox.warning(self, "失败", f"注册失败:{e}")

    def verify_referral(self, code, default=1):
        return default == 1

    def get_ip_and_area(self):
        return "192.168.1.100", "本地测试"


# ======================== 我的资料窗口 ========================
class ProfileDialog(QDialog):
    def __init__(self, account, net_name, phone, password, parent=None):
        super().__init__(parent)
        self.account = account
        self.original_net_name = net_name
        self.original_phone = phone
        self.password = password
        self.setWindowTitle("我的资料")
        self.setFixedWidth(500)
        self.init_ui()
        self.load_data()

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

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(15)

        self.account_edit = QLineEdit()
        self.account_edit.setReadOnly(True)
        self.netname_edit = QLineEdit()
        self.phone_edit = QLineEdit()

        form_layout.addRow("用户账号:", self.account_edit)
        form_layout.addRow("用户网名:", self.netname_edit)
        form_layout.addRow("联系方式:", self.phone_edit)
        layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.save_btn = QPushButton("保 存")
        self.save_btn.setFixedHeight(38)
        self.save_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(38)
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.save_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)

        self.save_btn.clicked.connect(self.on_save)
        self.cancel_btn.clicked.connect(self.reject)


    def load_data(self):
        self.account_edit.setText(self.account)
        self.netname_edit.setText(self.original_net_name)
        self.phone_edit.setText(self.original_phone)

    def on_save(self):
        new_netname = self.netname_edit.text().strip()
        new_phone = self.phone_edit.text().strip()

        if not new_netname or not new_phone:
            QMessageBox.warning(self, "警告", "网名和联系方式不能为空!")
            self.load_data()
            return

        if not re.match(r'^[\u4e00-\u9fa5a-zA-Z0-9]{1,18}$', new_netname):
            QMessageBox.warning(self, "警告", "网名格式不正确。")
            return

        if not re.match(r'^(\d{11}|\d{3,4}-?\d{7,8})$', new_phone):
            QMessageBox.warning(self, "警告", "联系方式格式不正确。")
            return

        if new_netname == self.original_net_name and new_phone == self.original_phone:
            self.accept()
            return

        hash_phone = crypto.generate_query_hash(new_phone)
        if db.is_phone_exist_exclude_account("云约智能(企业版)", hash_phone, self.account):
            QMessageBox.warning(self, "警告", "该联系方式已与其他账号绑定。")
            return

        encrypted_phone = crypto.encrypt(new_phone)
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        db.update_profile(self.account, new_netname, encrypted_phone, hash_phone)

        old_history = db.get_history_info(self.account)
        history_list = json.loads(old_history) if old_history else []
        history_entry = {
            "phone": crypto.encrypt(self.original_phone),
            "password": crypto.generate_hash(self.password),
            "operate_time": now
        }
        history_list.append(history_entry)
        db.set_history_info(self.account, json.dumps(history_list))

        QMessageBox.information(self, "成功", "资料修改成功!")
        self.accept()


# ======================== 修改密码窗口 ========================
class ChangePasswordDialog(QDialog):
    def __init__(self, account, phone, parent=None):
        super().__init__(parent)
        self.account = account
        self.phone = phone
        self.setWindowTitle("修改密码")
        self.setFixedWidth(500)
        self.init_ui()


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

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(20)

        self.old_pwd_edit = QLineEdit()
        self.old_pwd_edit.setEchoMode(QLineEdit.Password)
        self.old_pwd_edit.setPlaceholderText("请输入原密码")
        self.new_pwd_edit = QLineEdit()
        self.new_pwd_edit.setEchoMode(QLineEdit.Password)
        self.new_pwd_edit.setPlaceholderText("请输入新密码")
        self.confirm_pwd_edit = QLineEdit()
        self.confirm_pwd_edit.setEchoMode(QLineEdit.Password)
        self.confirm_pwd_edit.setPlaceholderText("请再次输入新密码")

        form_layout.addRow("原密码:", self.old_pwd_edit)
        form_layout.addRow("新密码:", self.new_pwd_edit)
        form_layout.addRow("确认密码:", self.confirm_pwd_edit)
        layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setFixedHeight(38)
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(38)
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.on_ok)
        self.cancel_btn.clicked.connect(self.reject)

    def on_ok(self):
        old_pwd = self.old_pwd_edit.text().strip()
        new_pwd = self.new_pwd_edit.text().strip()
        confirm_pwd = self.confirm_pwd_edit.text().strip()

        if not all([old_pwd, new_pwd, confirm_pwd]):
            QMessageBox.warning(self, "警告", "所有字段不能为空!")
            return

        stored_hash = db.get_password_hash(self.account)
        if not stored_hash or crypto.verify_hash(old_pwd, stored_hash) != 0:
            QMessageBox.warning(self, "错误", "原密码不正确!")
            return

        if not re.match(r'^[a-zA-Z0-9]{8,18}$', new_pwd):
            QMessageBox.warning(self, "警告", "新密码必须为8~18位字母或数字。")
            return
        if new_pwd != confirm_pwd:
            QMessageBox.warning(self, "警告", "两次输入的新密码不一致!")
            return
        if new_pwd == old_pwd:
            QMessageBox.warning(self, "警告", "新密码不能与原密码相同!")
            return

        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        hashed_new = crypto.generate_hash(new_pwd)

        db.update_password(self.account, hashed_new)

        old_history = db.get_history_info(self.account)
        history_list = json.loads(old_history) if old_history else []
        encrypted_phone = db.get_encrypted_phone(self.account)
        history_entry = {
            "phone": encrypted_phone,
            "password": stored_hash,
            "operate_time": now
        }
        history_list.append(history_entry)
        db.set_history_info(self.account, json.dumps(history_list))

        QMessageBox.information(self, "成功", "密码修改成功!")
        self.accept()


# ======================== 设置新密码弹窗 ========================
class SetNewPasswordDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("设置新密码")
        self.setFixedWidth(460)
        self.init_ui()
        self.new_password = None

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

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(20)

        self.new_pwd_edit = QLineEdit()
        self.new_pwd_edit.setEchoMode(QLineEdit.Password)
        self.new_pwd_edit.setPlaceholderText("请输入新密码")
        self.confirm_pwd_edit = QLineEdit()
        self.confirm_pwd_edit.setEchoMode(QLineEdit.Password)
        self.confirm_pwd_edit.setPlaceholderText("请再次输入新密码")

        form_layout.addRow("新密码:", self.new_pwd_edit)
        form_layout.addRow("确认密码:", self.confirm_pwd_edit)
        layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setFixedHeight(38)
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(38)
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.validate)
        self.cancel_btn.clicked.connect(self.reject)

    def validate(self):
        new_pwd = self.new_pwd_edit.text().strip()
        confirm_pwd = self.confirm_pwd_edit.text().strip()
        if not new_pwd:
            QMessageBox.warning(self, "警告", "新密码不能为空!")
            return
        if new_pwd != confirm_pwd:
            QMessageBox.warning(self, "警告", "两次输入的密码不一致!")
            return
        self.new_password = new_pwd
        self.accept()


# ======================== 快速找回密码窗口 ========================
class FindPasswordDialog(QDialog):
    def __init__(self, customer_account=None, parent=None):
        super().__init__(parent)
        self.customer_account = customer_account
        self.setWindowTitle("快速找回密码")
        self.setFixedWidth(500)
        self.matched_user = None
        self.init_ui()

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

        hint_label = QLabel("请至少填写用户账号或联系方式其中一项")
        layout.addWidget(hint_label)

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(20)

        self.account_edit = QLineEdit()
        self.account_edit.setPlaceholderText("请输入用户账号")
        self.phone_edit = QLineEdit()
        self.phone_edit.setPlaceholderText("请输入联系方式")
        self.question_edit = QLineEdit()
        self.question_edit.setReadOnly(True)
        self.question_edit.setPlaceholderText("验证通过后自动显示")
        self.answer_edit = QLineEdit()
        self.answer_edit.setPlaceholderText("请输入密保答案")

        form_layout.addRow("用户账号:", self.account_edit)
        form_layout.addRow("联系方式:", self.phone_edit)
        form_layout.addRow("密保问题:", self.question_edit)
        form_layout.addRow("密码答案:", self.answer_edit)
        layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setFixedHeight(40)
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(40)
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)

        self.account_edit.editingFinished.connect(self.auto_verify)
        self.phone_edit.editingFinished.connect(self.auto_verify)
        self.ok_btn.clicked.connect(self.on_ok)
        self.cancel_btn.clicked.connect(self.reject)

    def auto_verify(self):
        account = self.account_edit.text().strip()
        phone = self.phone_edit.text().strip()
        if not account and not phone:
            self.question_edit.clear()
            self.matched_user = None
            return

        hash_phone = crypto.generate_query_hash(phone) if phone else None
        user = db.find_user_by_account_or_phone(account, hash_phone)
        if not user:
            QMessageBox.warning(self, "提示", "未找到匹配的账号信息。")
            self.question_edit.clear()
            self.matched_user = None
            return

        self.matched_user = user
        self.account_edit.setText(user["customer_account"])
        self.account_edit.setReadOnly(True)
        decrypted_phone = crypto.decrypt(user["contact_phone"])
        self.phone_edit.setText(decrypted_phone)
        self.phone_edit.setReadOnly(True)

        security_info = json.loads(user["security_info"])
        if security_info:
            self.question_edit.setText(security_info[-1]["pwd_question"])
        else:
            self.question_edit.clear()

    def on_ok(self):
        if not self.matched_user:
            QMessageBox.warning(self, "警告", "请先完成身份验证。")
            return

        answer = self.answer_edit.text().strip()
        if not answer:
            QMessageBox.warning(self, "警告", "请输入密保答案。")
            return

        security_info = json.loads(self.matched_user["security_info"])
        if not security_info or security_info[-1]["pwd_answer"] != answer:
            QMessageBox.warning(self, "错误", "密保答案不正确。")
            return

        dlg = SetNewPasswordDialog(self)
        if dlg.exec_() == QDialog.Accepted:
            new_pwd = dlg.new_password
            now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            hashed_new = crypto.generate_hash(new_pwd)

            db.update_password(self.matched_user["customer_account"], hashed_new)

            old_phone = self.matched_user["contact_phone"]
            old_pwd_hash = self.matched_user["customer_pwd"]
            old_history = db.get_history_info(self.matched_user["customer_account"])
            history_list = json.loads(old_history) if old_history else []
            history_list.append({
                "phone": old_phone,
                "password": old_pwd_hash,
                "operate_time": now
            })
            db.set_history_info(self.matched_user["customer_account"], json.dumps(history_list))

            QMessageBox.information(self, "成功", "新密码设置成功!")
            self.accept()


# ======================== 完善团队信息窗口 ========================
class TeamInfoDialog(QDialog):
    DEPARTMENTS = ["工程部", "技术部", "财务部", "行政部", "物资部", "未分组"]

    def __init__(self, account, parent=None):
        super().__init__(parent)
        self.account = account
        self.setWindowTitle("完善团队信息")
        self.setFixedWidth(500)
        self.init_ui()

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

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(15)

        self.code_edit = QLineEdit()
        self.code_edit.setPlaceholderText("12位大写字母(不含I,O)+数字")
        self.name_edit = QLineEdit()
        self.phone_edit = QLineEdit()
        self.role_combo = QComboBox()
        self.role_combo.addItems(["", "团长", "管理员", "组长", "队员"])
        self.depart_combo = QComboBox()
        self.depart_combo.addItem("")
        self.depart_combo.addItems(self.DEPARTMENTS)

        form_layout.addRow("编码:", self.code_edit)
        form_layout.addRow("姓名:", self.name_edit)
        form_layout.addRow("电话:", self.phone_edit)
        form_layout.addRow("权限:", self.role_combo)
        form_layout.addRow("部门:", self.depart_combo)
        layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setFixedHeight(38)
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(38)
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.on_save)
        self.cancel_btn.clicked.connect(self.reject)

    def on_save(self):
        code = self.code_edit.text().strip()
        name = self.name_edit.text().strip()
        phone = self.phone_edit.text().strip()
        role = self.role_combo.currentText().strip()
        depart = self.depart_combo.currentText().strip()

        if not all([code, name, phone, role, depart]):
            QMessageBox.warning(self, "警告", "所有字段不能为空。")
            return

        if not re.match(r'^[A-HJ-NP-Z0-9]{12}$', code):
            QMessageBox.warning(self, "警告", "成员编码必须为12位大写字母(不含I,O)和数字。")
            return

        team_info = {
            "member_code": code,
            "member_name": name,
            "member_phone": phone,
            "member_role": role,
            "member_depart": depart,
            "group_departs": self.DEPARTMENTS
        }
        db.update_team_info(self.account, json.dumps(team_info))
        QMessageBox.information(self, "成功", "团队信息更新成功!")
        self.accept()


# ======================== 服务记录窗口 ========================
class ServiceRecordDialog(QDialog):
    def __init__(self, account, service_record=None, parent=None):
        super().__init__(parent)
        self.account = account
        self.service_record = service_record if service_record else []
        self.setWindowTitle("服务记录")
        self.resize(700, 500)
        self.init_ui()
        self.load_data()

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

        self.table = QTableWidget()
        self.table.setColumnCount(4)
        self.table.setHorizontalHeaderLabels(["序号", "内容", "操作人", "时间"])
        self.table.verticalHeader().setVisible(False)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.setColumnWidth(0, 80)
        self.table.setColumnWidth(1, 280)
        self.table.setColumnWidth(2, 150)
        self.table.setColumnWidth(3, 180)

        self.word_delegate = WordWrapDelegate()
        self.table.setItemDelegateForColumn(1, self.word_delegate)

        layout.addWidget(self.table)

        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        self.add_btn = QPushButton("添加记录")
        self.add_btn.setObjectName("primaryBtn")
        self.close_btn = QPushButton("关闭")
        self.close_btn.setObjectName("secondaryBtn")
        btn_layout.addWidget(self.add_btn)
        btn_layout.addWidget(self.close_btn)
        layout.addLayout(btn_layout)

        self.add_btn.clicked.connect(self.add_record)
        self.close_btn.clicked.connect(self.close)

    def load_data(self):
        self.table.setRowCount(len(self.service_record))
        for row, record in enumerate(self.service_record):
            item0 = QTableWidgetItem(str(row + 1))
            item0.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 0, item0)

            item1 = QTableWidgetItem(record.get("content", ""))
            item1.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            self.table.setItem(row, 1, item1)

            item2 = QTableWidgetItem(record.get("operator", ""))
            item2.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 2, item2)

            item3 = QTableWidgetItem(record.get("operate_time", ""))
            item3.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 3, item3)

        self.table.resizeRowsToContents()

    def add_record(self):
        dlg = AddRecordDialog(self.account, "添加服务记录", parent=self)
        if dlg.exec_() == QDialog.Accepted:
            new_record = dlg.get_record()
            if new_record:
                self.service_record.append(new_record)
                db.set_service_records(self.account, self.service_record)
                self.load_data()
                QMessageBox.information(self, "成功", "服务记录添加成功!")


class AddRecordDialog(QDialog):
    def __init__(self, account, title="添加记录", parent=None):
        super().__init__(parent)
        self.account = account
        self.setWindowTitle(title)
        self.setFixedSize(420, 320)
        self.record = None
        self.init_ui()

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

        title_label = QLabel("新增记录")
        layout.addWidget(title_label)

        self.text_edit = QTextEdit()
        self.text_edit.setPlaceholderText("请输入记录内容...")
        layout.addWidget(self.text_edit)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.validate)
        self.cancel_btn.clicked.connect(self.reject)

    def validate(self):
        content = self.text_edit.toPlainText().strip()
        if not content:
            QMessageBox.warning(self, "警告", "内容不能为空!")
            return
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.record = {"content": content, "operator": self.account, "operate_time": now}
        self.accept()

    def get_record(self):
        return self.record


# ======================== 客户评价窗口 ========================
class CustomerEvaluateDialog(QDialog):
    def __init__(self, account, parent=None):
        super().__init__(parent)
        self.account = account
        self.setWindowTitle("客户评价")
        self.setFixedSize(420, 320)
        self.init_ui()

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

        title_label = QLabel("写下您的评价")
        layout.addWidget(title_label)

        self.text_edit = QTextEdit()
        self.text_edit.setPlaceholderText("请在此输入评价内容...")
        layout.addWidget(self.text_edit)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("提 交")
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.on_ok)
        self.cancel_btn.clicked.connect(self.reject)

    def on_ok(self):
        content = self.text_edit.toPlainText().strip()
        if not content:
            QMessageBox.warning(self, "警告", "评价内容不能为空!")
            return
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        evaluate_entry = {"content": content, "evaluate_time": now}

        evaluate_list = db.get_customer_evaluate(self.account)
        evaluate_list.append(evaluate_entry)

        try:
            db.set_customer_evaluate(self.account, evaluate_list)
            QMessageBox.information(self, "成功", "评价提交成功!")
            self.accept()
        except Exception as e:
            QMessageBox.warning(self, "失败", f"提交失败:{e}")


# ======================== 客户评价历史窗口 ========================
class EvaluateHistoryDialog(QDialog):
    def __init__(self, customer_evaluate=None, parent=None):
        super().__init__(parent)
        self.evaluate_data = customer_evaluate if customer_evaluate else []
        self.setWindowTitle("客户评价历史记录")
        self.resize(600, 400)
        self.init_ui()
        self.load_data()

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

        self.table = QTableWidget()
        self.table.setColumnCount(3)
        self.table.setHorizontalHeaderLabels(["序号", "内容", "时间"])
        self.table.verticalHeader().setVisible(False)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.setColumnWidth(0, 80)
        self.table.setColumnWidth(1, 300)
        self.table.setColumnWidth(2, 180)

        self.word_delegate = WordWrapDelegate()
        self.table.setItemDelegateForColumn(1, self.word_delegate)

        layout.addWidget(self.table)

        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        self.close_btn = QPushButton("关 闭")
        self.close_btn.setObjectName("secondaryBtn")
        btn_layout.addWidget(self.close_btn)
        layout.addLayout(btn_layout)
        self.close_btn.clicked.connect(self.close)

    def load_data(self):
        self.table.setRowCount(len(self.evaluate_data))
        for row, record in enumerate(self.evaluate_data):
            item0 = QTableWidgetItem(str(row + 1))
            item0.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 0, item0)

            item1 = QTableWidgetItem(record.get("content", ""))
            item1.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            self.table.setItem(row, 1, item1)

            item2 = QTableWidgetItem(record.get("evaluate_time", ""))
            item2.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 2, item2)

        self.table.resizeRowsToContents()


# ======================== 客户备注窗口 ========================
class CustomerRemarkDialog(QDialog):
    def __init__(self, account, customer_remark=None, parent=None):
        super().__init__(parent)
        self.account = account
        self.remark_data = customer_remark if customer_remark else []
        self.setWindowTitle("客户备注")
        self.resize(700, 500)
        self.init_ui()
        self.load_data()

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

        self.table = QTableWidget()
        self.table.setColumnCount(4)
        self.table.setHorizontalHeaderLabels(["序号", "内容", "操作人", "时间"])
        self.table.verticalHeader().setVisible(False)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.setColumnWidth(0, 80)
        self.table.setColumnWidth(1, 280)
        self.table.setColumnWidth(2, 150)
        self.table.setColumnWidth(3, 180)

        self.word_delegate = WordWrapDelegate()
        self.table.setItemDelegateForColumn(1, self.word_delegate)

        layout.addWidget(self.table)

        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        self.add_btn = QPushButton("添加备注")
        self.add_btn.setObjectName("primaryBtn")
        self.close_btn = QPushButton("关 闭")
        self.close_btn.setObjectName("secondaryBtn")
        btn_layout.addWidget(self.add_btn)
        btn_layout.addWidget(self.close_btn)
        layout.addLayout(btn_layout)

        self.add_btn.clicked.connect(self.add_remark)
        self.close_btn.clicked.connect(self.close)

    def load_data(self):
        self.table.setRowCount(len(self.remark_data))
        for row, record in enumerate(self.remark_data):
            item0 = QTableWidgetItem(str(row + 1))
            item0.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 0, item0)

            item1 = QTableWidgetItem(record.get("content", ""))
            item1.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            self.table.setItem(row, 1, item1)

            item2 = QTableWidgetItem(record.get("operator", ""))
            item2.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 2, item2)

            item3 = QTableWidgetItem(record.get("operate_time", ""))
            item3.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 3, item3)

        self.table.resizeRowsToContents()

    def add_remark(self):
        dlg = AddRecordDialog(self.account, "添加备注", parent=self)
        if dlg.exec_() == QDialog.Accepted:
            new_record = dlg.get_record()
            if new_record:
                self.remark_data.append(new_record)
                db.set_customer_remark(self.account, self.remark_data)
                self.load_data()
                QMessageBox.information(self, "成功", "备注添加成功!")


# ======================== 授权窗口 ========================
class AuthorizationDialog(QDialog):
    def __init__(self, account=None, parent=None):
        super().__init__(parent)
        self.setWindowTitle("授权管理")
        self.setFixedSize(400, 200)
        self.init_ui()

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

        self.auth_edit = QLineEdit()
        self.auth_edit.setPlaceholderText("请输入32位授权码(大写字母不含I,O和数字)")
        layout.addWidget(self.auth_edit)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.on_ok)
        self.cancel_btn.clicked.connect(self.reject)

    def on_ok(self):
        auth_code = self.auth_edit.text().strip()
        if not auth_code:
            QMessageBox.warning(self, "警告", "授权码不能为空!")
            return
        if not re.match(r'^[A-HJ-NP-Z0-9]{32}$', auth_code):
            QMessageBox.warning(self, "警告", "授权码格式不正确,应为32位大写字母(不含I,O)和数字。")
            return
        QMessageBox.information(self, "成功", "恭喜,授权成功!")
        self.accept()


# ======================== 主窗口 ========================
class MainWindow(QWidget):
    def __init__(self, account, net_name, phone, password):
        super().__init__()
        self.account = account
        self.net_name = net_name
        self.phone = phone
        self.password = password
        self.set_theme("中国红")
        self.setWindowTitle("我的主窗口")
        self.resize(1000, 700)
        self.init_ui()

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

        title = QLabel(f"欢迎,{self.net_name}")
        title.setAlignment(Qt.AlignCenter)
        layout.addWidget(title)

        grid = QGridLayout()
        grid.setSpacing(15)

        buttons_info = [
            ("我的资料", self.open_profile),
            ("修改密码", self.open_change_password),
            ("找回密码", self.open_find_password),
            ("团队信息", self.open_team_info),
            ("服务记录", self.open_service_record),
            ("客户评价", self.open_customer_evaluate),
            ("评价历史", self.open_evaluate_history),
            ("客户备注", self.open_customer_remark),
            ("授权管理", self.open_authorization),
        ]
        for i in range(21):
            buttons_info.append((f"备用按钮{i+1}", lambda _, name=f"备用按钮{i+1}": self.show_spare(name)))

        row, col = 0, 0
        for text, func in buttons_info:
            btn = QPushButton(text)
            btn.setFixedSize(160, 50)
            btn.setObjectName("primaryBtn" if "备用" not in text else "secondaryBtn")
            btn.clicked.connect(func)
            grid.addWidget(btn, row, col)
            col += 1
            if col >= 5:
                col = 0
                row += 1

        layout.addLayout(grid)

    def open_profile(self):
        dlg = ProfileDialog(self.account, self.net_name, self.phone, self.password)
        dlg.exec_()

    def open_change_password(self):
        dlg = ChangePasswordDialog(self.account, self.phone)
        dlg.exec_()

    def open_find_password(self):
        dlg = FindPasswordDialog(customer_account=self.account)
        dlg.exec_()

    def open_team_info(self):
        dlg = TeamInfoDialog(self.account)
        dlg.exec_()

    def open_service_record(self):
        data = db.get_service_records(self.account)
        dlg = ServiceRecordDialog(self.account, data)
        dlg.exec_()

    def open_customer_evaluate(self):
        dlg = CustomerEvaluateDialog(self.account)
        dlg.exec_()

    def open_evaluate_history(self):
        data = db.get_customer_evaluate(self.account)
        dlg = EvaluateHistoryDialog(data)
        dlg.exec_()

    def open_customer_remark(self):
        data = db.get_customer_remark(self.account)
        dlg = CustomerRemarkDialog(self.account, data)
        dlg.exec_()

    def open_authorization(self):
        dlg = AuthorizationDialog(self.account)
        dlg.exec_()

    def show_spare(self, name):
        QMessageBox.information(self, "备用按钮", f"您点击了:{name}")


# ======================== 程序入口 ========================
if __name__ == "__main__":
    config = {
        'applicationName': 'PyQt5 主题化控件库演示',
        'organizationName': 'MyCompany',
        'organizationDomain': 'mycompany.com',
        'applicationVersion': '2.0',
        'windowIcon': 'fox.ico',
        'font': {
            'family': 'Microsoft YaHei',
            'pointSize': 9,
            'weight': QFont.Normal
        },
        'translatorPath': 'qt_zh_CN.qm'
    }

    app = QApplication(sys.argv,config)
    app.setFont(QFont("Microsoft YaHei", 10))
    login = LoginWindow()
    login.show()
    sys.exit(app.exec_())

三、排雷前

python 复制代码
import sys
import re
import json
import base64
import hashlib
import os
import pymysql
from datetime import datetime
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from PyQt5.QtWidgets import (
    QApplication, QWidget, QDialog, QLabel, QLineEdit, QPushButton,
    QVBoxLayout, QHBoxLayout, QFormLayout, QComboBox, QMessageBox,
    QTableView, QHeaderView, QAbstractItemView, QTextEdit, QToolButton,
    QGraphicsDropShadowEffect, QTableWidget, QTableWidgetItem, QGridLayout,
    QInputDialog, QStyledItemDelegate, QStyle
)
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QFont, QColor, QPixmap, QTextDocument
from SecurityCrypto.SecurityCrypto import SecurityCrypto
from LhPyQt5.LhQt5 import *


# ======================== 数据库操作类(UserDB) ========================
class UserDB:
    """用户数据库操作类,通过参数配置数据库连接和表名"""

    def __init__(self, sql_dict, user_table="product_customer"):
        """
        :param sql_dict: pymysql 连接参数字典(不含 autocommit)
        :param user_table: 操作的主表名,默认 product_customer
        """
        self.sql_dict = sql_dict
        self.user_table = user_table

    # ---- 原始 execute_mysql 函数作为静态方法 ----
    @staticmethod
    def execute_mysql(
            sql_dict,
            sql_text,
            params=None,
            fetch=False,
            executemany=False,
            dictionary=True,
            autocommit=True,
            transaction=False
    ):
        conn = None
        cursor = None
        try:
            # 尝试建立数据库连接
            try:
                conn = pymysql.connect(**sql_dict)
            except pymysql.err.OperationalError:
                # 网络断开或无法连接时返回 None
                return None

            # 设置游标类型
            cursor_type = pymysql.cursors.DictCursor if dictionary else pymysql.cursors.Cursor
            cursor = conn.cursor(cursor_type)

            # 事务控制逻辑
            if transaction:
                conn.begin()

            # 执行核心逻辑
            try:
                if executemany:
                    cursor.executemany(sql_text, params)
                else:
                    cursor.execute(sql_text, params)
            except pymysql.err.OperationalError:
                # 执行过程中网络断开,回滚后返回 None
                if conn:
                    conn.rollback()
                return None

            # 结果处理
            if fetch or sql_text.strip().upper().startswith('SELECT'):
                result = cursor.fetchall()
            elif sql_text.strip().upper().startswith('INSERT'):
                result = cursor.lastrowid
            else:
                result = cursor.rowcount

            # 提交控制
            if autocommit and not conn.get_autocommit():
                conn.commit()

            return result

        except pymysql.MySQLError as e:
            if conn:
                conn.rollback()
            raise RuntimeError(f"数据库操作失败: {e}") from e
        finally:
            if cursor:
                cursor.close()
            if conn:
                conn.close()

    # ---------- 用户相关 ----------
    def get_user_by_account(self, account):
        """根据账号查询用户完整记录,返回 dict 或 None"""
        try:
            sql = f"SELECT * FROM {self.user_table} WHERE customer_account = %s"
            users = UserDB.execute_mysql(self.sql_dict, sql, (account,), fetch=True)
            return users[0] if users else None
        except:
            return None

    def is_account_exist(self, account):
        """判断账号是否存在"""
        try:
            sql = f"SELECT id FROM {self.user_table} WHERE customer_account = %s"
            res = UserDB.execute_mysql(self.sql_dict, sql, (account,), fetch=True)
            return res is not None and len(res) > 0
        except:
            return False

    def is_phone_exist(self, product_name, hash_phone):
        """判断联系方式是否已存在(同一产品下)"""
        try:
            sql = f"SELECT id FROM {self.user_table} WHERE product_name = %s AND hash_phone = %s"
            res = UserDB.execute_mysql(self.sql_dict, sql, (product_name, hash_phone), fetch=True)
            return res is not None and len(res) > 0
        except:
            return False

    def is_phone_exist_exclude_account(self, product_name, hash_phone, account):
        """判断联系方式是否与其他账号绑定(排除自身)"""
        try:
            sql = f"SELECT id FROM {self.user_table} WHERE product_name = %s AND hash_phone = %s AND customer_account != %s"
            res = UserDB.execute_mysql(self.sql_dict, sql, (product_name, hash_phone, account), fetch=True)
            return res is not None and len(res) > 0
        except:
            return False

    def register_user(self, product_name, account, hashed_pwd, netname, encrypted_phone, hash_phone,
                      right_date, customer_status, security_info, sales_info, register_info):
        """注册新用户"""
        sql = f"""
            INSERT INTO {self.user_table} 
            (product_name, customer_account, customer_pwd, customer_netname, contact_phone, hash_phone, 
             right_date, customer_status, security_info, sales_info, register_info)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
        """
        params = (product_name, account, hashed_pwd, netname, encrypted_phone, hash_phone,
                  right_date, customer_status, security_info, sales_info, register_info)
        UserDB.execute_mysql(self.sql_dict, sql, params)

    # ---------- 资料修改 ----------
    def update_profile(self, account, netname, encrypted_phone, hash_phone):
        """更新网名和联系方式"""
        sql = f"UPDATE {self.user_table} SET customer_netname = %s, contact_phone = %s, hash_phone = %s WHERE customer_account = %s"
        UserDB.execute_mysql(self.sql_dict, sql, (netname, encrypted_phone, hash_phone, account))

    def get_history_info(self, account):
        """获取 history_info 字段"""
        sql = f"SELECT history_info FROM {self.user_table} WHERE customer_account = %s"
        res = UserDB.execute_mysql(self.sql_dict, sql, (account,), fetch=True)
        if res and res[0]["history_info"]:
            return res[0]["history_info"]
        return None

    def set_history_info(self, account, history_json):
        """设置 history_info 字段"""
        sql = f"UPDATE {self.user_table} SET history_info = %s WHERE customer_account = %s"
        UserDB.execute_mysql(self.sql_dict, sql, (history_json, account))

    def get_password_hash(self, account):
        """获取当前密码哈希值"""
        sql = f"SELECT customer_pwd FROM {self.user_table} WHERE customer_account = %s"
        res = UserDB.execute_mysql(self.sql_dict, sql, (account,), fetch=True)
        return res[0]["customer_pwd"] if res else None

    def update_password(self, account, new_hash):
        """修改密码"""
        sql = f"UPDATE {self.user_table} SET customer_pwd = %s WHERE customer_account = %s"
        UserDB.execute_mysql(self.sql_dict, sql, (new_hash, account))

    def get_encrypted_phone(self, account):
        """获取加密的手机号(用于 history 记录)"""
        sql = f"SELECT contact_phone FROM {self.user_table} WHERE customer_account = %s"
        res = UserDB.execute_mysql(self.sql_dict, sql, (account,), fetch=True)
        return res[0]["contact_phone"] if res else None

    # ---------- 团队信息 ----------
    def update_team_info(self, account, team_info_json):
        """更新团队信息"""
        sql = f"UPDATE {self.user_table} SET team_info = %s WHERE customer_account = %s"
        UserDB.execute_mysql(self.sql_dict, sql, (team_info_json, account))

    # ---------- 服务记录 ----------
    def get_service_records(self, account):
        """获取服务记录,返回列表"""
        sql = f"SELECT service_record FROM {self.user_table} WHERE customer_account = %s"
        res = UserDB.execute_mysql(self.sql_dict, sql, (account,), fetch=True)
        if res and res[0]["service_record"]:
            return json.loads(res[0]["service_record"])
        return []

    def set_service_records(self, account, records):
        """更新服务记录"""
        sql = f"UPDATE {self.user_table} SET service_record = %s WHERE customer_account = %s"
        UserDB.execute_mysql(self.sql_dict, sql, (json.dumps(records), account))

    # ---------- 客户评价 ----------
    def get_customer_evaluate(self, account):
        """获取客户评价列表"""
        sql = f"SELECT customer_evaluate FROM {self.user_table} WHERE customer_account = %s"
        res = UserDB.execute_mysql(self.sql_dict, sql, (account,), fetch=True)
        if res and res[0]["customer_evaluate"]:
            return json.loads(res[0]["customer_evaluate"])
        return []

    def set_customer_evaluate(self, account, records):
        """更新客户评价"""
        sql = f"UPDATE {self.user_table} SET customer_evaluate = %s WHERE customer_account = %s"
        UserDB.execute_mysql(self.sql_dict, sql, (json.dumps(records), account))

    # ---------- 客户备注 ----------
    def get_customer_remark(self, account):
        """获取客户备注列表"""
        sql = f"SELECT customer_remark FROM {self.user_table} WHERE customer_account = %s"
        res = UserDB.execute_mysql(self.sql_dict, sql, (account,), fetch=True)
        if res and res[0]["customer_remark"]:
            return json.loads(res[0]["customer_remark"])
        return []

    def set_customer_remark(self, account, records):
        """更新客户备注"""
        sql = f"UPDATE {self.user_table} SET customer_remark = %s WHERE customer_account = %s"
        UserDB.execute_mysql(self.sql_dict, sql, (json.dumps(records), account))

    # ---------- 找回密码 ----------
    def find_user_by_account_or_phone(self, account, hash_phone):
        """通过账号或联系方式查找用户,返回完整记录或 None"""
        conditions = []
        params = []
        if account:
            conditions.append("customer_account = %s")
            params.append(account)
        if hash_phone:
            conditions.append("hash_phone = %s")
            params.append(hash_phone)
        if not conditions:
            return None
        sql = f"SELECT * FROM {self.user_table} WHERE {' OR '.join(conditions)}"
        users = UserDB.execute_mysql(self.sql_dict, sql, tuple(params), fetch=True)
        return users[0] if users else None


# ======================== 全局实例 ========================
crypto = SecurityCrypto(key_salt="海算销售密钥盐", master_password="HaiSuan@2025")
db = UserDB(
    sql_dict={
        "host": "localhost",
        "user": "root",
        "password": "root",
        "db": "my_sale_system",
        "charset": "utf8mb4"
    },
    user_table="product_customer"
)


# ======================== 自动换行且垂直居中的委托 ========================
class WordWrapDelegate(QStyledItemDelegate):
    def paint(self, painter, option, index):
        text = index.data(Qt.DisplayRole)
        if not text:
            return super().paint(painter, option, index)

        if option.state & QStyle.State_Selected:
            painter.fillRect(option.rect, option.palette.highlight())

        painter.save()
        doc = QTextDocument()
        doc.setDefaultFont(option.font)
        doc.setHtml(str(text))
        doc.setTextWidth(option.rect.width())

        content_height = doc.size().height()
        y_offset = option.rect.top() + max(0, (option.rect.height() - content_height) // 2)
        painter.translate(option.rect.left(), y_offset)
        doc.drawContents(painter)
        painter.restore()

    def sizeHint(self, option, index):
        text = index.data(Qt.DisplayRole)
        if not text:
            return super().sizeHint(option, index)
        doc = QTextDocument()
        doc.setDefaultFont(option.font)
        doc.setHtml(str(text))
        doc.setTextWidth(option.rect.width())
        return QSize(int(doc.idealWidth()), int(doc.size().height()))


# ======================== 自定义窗口基类 ========================
class BaseWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.setGraphicsEffect(self.create_shadow())

    def create_shadow(self):
        shadow = QGraphicsDropShadowEffect()
        shadow.setBlurRadius(30)
        shadow.setXOffset(0)
        shadow.setYOffset(0)
        shadow.setColor(QColor(0, 0, 0, 80))
        return shadow


# ======================== 登录窗口 ========================
class LoginWindow(BaseWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle('销售管理系统 - 登录')
        self.setFixedSize(900, 550)
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)

        container = QWidget(self)
        container.setObjectName("container")
        container.setGeometry(0, 0, 900, 550)
        container.setStyleSheet("QWidget#container { background-color: transparent; border-radius: 15px; }")

        main_layout = QHBoxLayout(container)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.setSpacing(0)

        # 左侧区域(蓝色#4F7EF7)
        left_widget = QWidget()
        left_widget.setObjectName("left_widget")
        left_layout = QVBoxLayout()
        left_layout.setContentsMargins(40, 40, 40, 40)

        title_label = QLabel("销售管理系统")
        title_label.setAlignment(Qt.AlignHCenter)
        title_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 36px; font-weight: bold; color: white;")

        subtitle_label = QLabel("精准营销·业绩倍增")
        subtitle_label.setAlignment(Qt.AlignHCenter)
        subtitle_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-weight: bold; font-size: 24px; color: rgba(255,255,255,0.9); margin-top: 15px;")

        slogan_label = QLabel("提升销售效率\n优化客户关系\n加速业务增长")
        slogan_label.setAlignment(Qt.AlignCenter)
        slogan_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 22px; color: white; margin-top: 60px; line-height: 1.8; background-color: rgba(255,255,255,0.1); border-radius: 10px; padding: 10px;")

        support_label = QLabel("技术支持:海算(海南)信息有限公司\n服务热线:15890561786")
        support_label.setAlignment(Qt.AlignCenter)
        support_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 18px; color: white; margin-top: 40px; line-height: 1.5;")

        left_layout.addSpacing(80)
        left_layout.addWidget(title_label)
        left_layout.addWidget(subtitle_label)
        left_layout.addWidget(slogan_label)
        left_layout.addWidget(support_label)
        left_widget.setLayout(left_layout)
        left_widget.setStyleSheet("QWidget#left_widget { background-color: #4F7EF7; border-top-left-radius: 15px; border-bottom-left-radius: 15px; }")

        # 右侧区域(白色)
        right_widget = QWidget()
        right_widget.setObjectName("right_widget")
        right_layout = QVBoxLayout()
        right_layout.setContentsMargins(20, 20, 20, 20)

        top_bar = QHBoxLayout()
        top_bar.addStretch()
        close_btn = QToolButton()
        close_btn.setText("×")
        close_btn.setFixedSize(40, 40)
        close_btn.setStyleSheet("QToolButton { font-family: 'Microsoft YaHei'; font-size: 30px; font-weight: bold; color: #999; border: none; background: transparent; } QToolButton:hover { color: #333; background-color: #f5f5f5; border-radius: 10px; }")
        close_btn.clicked.connect(self.close)
        top_bar.addWidget(close_btn)

        version_label = QLabel("海算销售管理系统 V1.01")
        version_label.setAlignment(Qt.AlignCenter)
        version_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 32px; font-weight: bold; color: #333; margin-top: 10px; margin-bottom: 20px;")

        form_layout = QVBoxLayout()
        form_layout.setSpacing(25)

        username_widget = QWidget()
        username_layout = QVBoxLayout(username_widget)
        username_layout.setContentsMargins(50, 0, 50, 0)
        username_label = QLabel("账号")
        username_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 20px; color: black; margin-bottom: 5px;")
        self.username_input = QLineEdit()
        self.username_input.setPlaceholderText("请输入账号")
        self.username_input.setFixedHeight(45)
        self.username_input.setStyleSheet("QLineEdit { font-family: 'Microsoft YaHei'; font-size: 18px; border: 1px solid #d0d7e5; border-radius: 8px; padding: 0 15px; background-color: white; } QLineEdit:focus { border: 2px solid #4F7EF7; padding: 0 14px; }")
        username_layout.addWidget(username_label)
        username_layout.addWidget(self.username_input)

        password_widget = QWidget()
        password_layout = QVBoxLayout(password_widget)
        password_layout.setContentsMargins(50, 0, 50, 0)
        password_label = QLabel("密码")
        password_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 20px; color: black; margin-bottom: 5px;")
        self.password_input = QLineEdit()
        self.password_input.setPlaceholderText("请输入密码")
        self.password_input.setEchoMode(QLineEdit.Password)
        self.password_input.setFixedHeight(45)
        self.password_input.setStyleSheet("QLineEdit { font-family: 'Microsoft YaHei'; font-size: 18px; border: 1px solid #d0d7e5; border-radius: 8px; padding: 0 15px; background-color: white; } QLineEdit:focus { border: 2px solid #4F7EF7; padding: 0 14px; }")
        password_layout.addWidget(password_label)
        password_layout.addWidget(self.password_input)

        form_layout.addWidget(username_widget)
        form_layout.addWidget(password_widget)

        forgot_layout = QHBoxLayout()
        forgot_layout.setContentsMargins(50, 0, 50, 0)
        self.forgot_label = QLabel("<a href='#' style='color: #4F7EF7; text-decoration: none; font-family: \"Microsoft YaHei\"; font-size: 22px;'>忘记密码?</a>")
        self.forgot_label.setOpenExternalLinks(False)
        self.forgot_label.linkActivated.connect(self.on_forgot_password)
        forgot_layout.addStretch()
        forgot_layout.addWidget(self.forgot_label)

        button_layout = QHBoxLayout()
        button_layout.setSpacing(20)
        self.login_btn = QPushButton("登录")
        self.login_btn.setFixedWidth(120)
        self.login_btn.setFixedHeight(45)
        self.login_btn.setObjectName("primaryBtn")
        self.login_btn.clicked.connect(self.on_login)

        self.register_btn = QPushButton("注册")
        self.register_btn.setFixedWidth(120)
        self.register_btn.setFixedHeight(45)
        self.register_btn.setObjectName("secondaryBtn")
        self.register_btn.clicked.connect(self.on_register)

        button_layout.addStretch()
        button_layout.addWidget(self.login_btn)
        button_layout.addWidget(self.register_btn)
        button_layout.addStretch()

        copyright_label = QLabel(f"© {datetime.today().year} Sales Management System. All rights reserved.")
        copyright_label.setAlignment(Qt.AlignCenter)
        copyright_label.setStyleSheet("font-family: 'Microsoft YaHei'; font-size: 16px; color: #999999; margin-top: 15px;")

        right_layout.addLayout(top_bar)
        right_layout.addWidget(version_label)
        right_layout.addLayout(form_layout)
        right_layout.addSpacing(5)
        right_layout.addLayout(forgot_layout)
        right_layout.addSpacing(20)
        right_layout.addLayout(button_layout)
        right_layout.addStretch()
        right_layout.addWidget(copyright_label)

        right_widget.setLayout(right_layout)
        right_widget.setStyleSheet("QWidget#right_widget { background-color: #ffffff; border-top-right-radius: 15px; border-bottom-right-radius: 15px; }")

        main_layout.addWidget(left_widget, 40)
        main_layout.addWidget(right_widget, 60)

        self.setStyleSheet("""
            QWidget { font-family: "Microsoft YaHei"; }
            QPushButton#primaryBtn { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #6b9af8, stop:1 #4F7EF7); color: white; border: none; border-radius: 8px; font-size: 18px; font-weight: bold; }
            QPushButton#primaryBtn:hover { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #7ba8ff, stop:1 #5f8eff); }
            QPushButton#primaryBtn:pressed { background: #4F7EF7; }
            QPushButton#secondaryBtn { background: white; color: #4F7EF7; border: 2px solid #4F7EF7; border-radius: 8px; font-size: 18px; font-weight: bold; }
            QPushButton#secondaryBtn:hover { background: #eaf1ff; }
            QPushButton#secondaryBtn:pressed { background: #d4e2ff; }
        """)

    def on_login(self):
        username = self.username_input.text().strip()
        password = self.password_input.text().strip()
        if not username or not password:
            QMessageBox.warning(self, "警告", "请输入账号和密码!")
            return

        user = db.get_user_by_account(username)
        if not user:
            QMessageBox.warning(self, "警告", "账号不存在!")
            return
        if crypto.verify_hash(password, user["customer_pwd"]) != 0:
            QMessageBox.warning(self, "警告", "密码错误!")
            return
        self.close()
        self.main_window = MainWindow(account=user["customer_account"], net_name=user["customer_netname"],
                                      phone=crypto.decrypt(user["contact_phone"]), password=password)
        self.main_window.show()

    def on_register(self):
        dialog = RegisterDialog(product_name="云约智能(企业版)", parent=self)
        dialog.exec_()

    def on_forgot_password(self):
        dialog = FindPasswordDialog(customer_account=None, parent=self)
        dialog.exec_()

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drag_pos = event.globalPos() - self.frameGeometry().topLeft()
            event.accept()

    def mouseMoveEvent(self, event):
        if event.buttons() == Qt.LeftButton:
            self.move(event.globalPos() - self.drag_pos)
            event.accept()


# ======================== 注册窗口 ========================
class RegisterDialog(QDialog):
    def __init__(self, product_name="云约智能(企业版)", parent=None):
        super().__init__(parent)
        self.product_name = product_name
        self.setWindowTitle("用户注册")
        self.setFixedWidth(600)
        self.custom_index = None
        self.previous_index = None
        self.ignore_index_change = False
        self.init_ui()
        self.apply_styles()

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

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(15)

        self.account_edit = QLineEdit()
        self.account_edit.setPlaceholderText("8~12位字母或数字")
        form_layout.addRow("用户账号:", self.account_edit)

        self.netname_edit = QLineEdit()
        self.netname_edit.setPlaceholderText("18个以内汉字、字母或数字")
        form_layout.addRow("用户网名:", self.netname_edit)

        self.password_edit = QLineEdit()
        self.password_edit.setEchoMode(QLineEdit.Password)
        self.password_edit.setPlaceholderText("8~18位字母或数字")
        form_layout.addRow("登录密码:", self.password_edit)

        self.confirm_password_edit = QLineEdit()
        self.confirm_password_edit.setEchoMode(QLineEdit.Password)
        self.confirm_password_edit.setPlaceholderText("请确认密码")
        form_layout.addRow("确认密码:", self.confirm_password_edit)

        self.phone_edit = QLineEdit()
        self.phone_edit.setPlaceholderText("请输入真实手机号或固定电话")
        form_layout.addRow("联系方式:", self.phone_edit)

        self.security_combo = QComboBox()
        self.security_combo.addItems(["您母亲的姓名?", "您父亲的姓名?", "自定义"])
        self.custom_index = 2
        self.security_combo.currentIndexChanged.connect(self.on_security_combo_changed)
        form_layout.addRow("密保问题:", self.security_combo)

        self.security_answer_edit = QLineEdit()
        form_layout.addRow("密保答案:", self.security_answer_edit)

        self.referral_code_edit = QLineEdit()
        self.referral_code_edit.setPlaceholderText("推荐码(选填)")
        form_layout.addRow("推荐码:", self.referral_code_edit)

        main_layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setFixedHeight(40)
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(40)
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        main_layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.validate_and_register)
        self.cancel_btn.clicked.connect(self.reject)

    def apply_styles(self):
        self.setStyleSheet("""
            QDialog { background-color: #f8faff; font-family: "Microsoft YaHei"; }
            QLabel { color: #333; font-size: 18px; }
            QLineEdit { border: 1px solid #d0d7e5; border-radius: 5px; padding: 8px 12px; background: white; font-size: 18px; }
            QLineEdit:focus { border: 2px solid #4F7EF7; padding: 7px 11px; }
            QComboBox { border: 1px solid #d0d7e5; border-radius: 5px; padding: 8px 12px; background: white; font-size: 18px; }
            QPushButton#primaryBtn { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #6b9af8, stop:1 #4F7EF7); color: white; border: none; border-radius: 5px; font-size: 18px; font-weight: bold; min-width: 100px; }
            QPushButton#primaryBtn:hover { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #7ba8ff, stop:1 #5f8eff); }
            QPushButton#secondaryBtn { background: white; color: #4F7EF7; border: 2px solid #4F7EF7; border-radius: 5px; font-size: 18px; font-weight: bold; min-width: 100px; }
            QPushButton#secondaryBtn:hover { background: #eaf1ff; }
        """)

    def on_security_combo_changed(self, index):
        if self.ignore_index_change:
            return
        if index == self.custom_index:
            new_question, ok = QInputDialog.getText(self, "自定义密保问题", "请输入您的自定义密保问题:")
            if ok and new_question.strip():
                self.ignore_index_change = True
                self.security_combo.insertItem(self.custom_index, new_question.strip())
                self.security_combo.setCurrentIndex(self.custom_index)
                self.custom_index += 1
                self.ignore_index_change = False
            else:
                self.ignore_index_change = True
                self.security_combo.setCurrentIndex(self.previous_index if self.previous_index is not None else 0)
                self.ignore_index_change = False
        else:
            self.previous_index = index

    def validate_and_register(self):
        account = self.account_edit.text().strip()
        netname = self.netname_edit.text().strip()
        password = self.password_edit.text().strip()
        confirm = self.confirm_password_edit.text().strip()
        phone = self.phone_edit.text().strip()
        security_q = self.security_combo.currentText().strip()
        security_a = self.security_answer_edit.text().strip()
        referral = self.referral_code_edit.text().strip()

        if not all([account, netname, password, confirm, phone, security_q, security_a]):
            QMessageBox.warning(self, "验证失败", "所有带*号为必填项,请填写完整。")
            return

        if not re.match(r'^[a-zA-Z0-9]{8,12}$', account):
            QMessageBox.warning(self, "验证失败", "账号必须为8~12位字母或数字。")
            return

        if not re.match(r'^[\u4e00-\u9fa5a-zA-Z0-9]{1,18}$', netname):
            QMessageBox.warning(self, "验证失败", "网名必须为18个以内汉字、字母或数字。")
            return

        if not re.match(r'^[a-zA-Z0-9]{8,18}$', password):
            QMessageBox.warning(self, "验证失败", "密码必须为8~18位字母或数字。")
            return
        if password != confirm:
            QMessageBox.warning(self, "验证失败", "两次输入的密码不一致。")
            return

        if not re.match(r'^(\d{11}|\d{3,4}-?\d{7,8})$', phone):
            QMessageBox.warning(self, "验证失败", "请输入正确的手机号或固定电话。")
            return

        if db.is_account_exist(account):
            QMessageBox.warning(self, "验证失败", "该账号已存在。")
            return

        hash_phone = crypto.generate_query_hash(phone)
        if db.is_phone_exist(self.product_name, hash_phone):
            QMessageBox.warning(self, "验证失败", "该联系方式已在该产品下注册。")
            return

        if referral:
            if not self.verify_referral(referral):
                QMessageBox.warning(self, "验证失败", "推荐码无效。")
                return

        hashed_pwd = crypto.generate_hash(password)
        encrypted_phone = crypto.encrypt(phone)

        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        security_info = json.dumps([{"pwd_question": security_q, "pwd_answer": security_a, "operator": account, "operate_time": now}])
        sales_info = json.dumps([{"sales_account": account, "parent_sales": "F008216", "sales_director": "F008888", "operator": account, "operate_time": now}])
        register_ip, register_area = self.get_ip_and_area()
        register_info = json.dumps([{"register_time": now, "register_area": register_area, "register_ip": register_ip}])

        try:
            db.register_user(
                self.product_name, account, hashed_pwd, netname, encrypted_phone, hash_phone,
                now, None, security_info, sales_info, register_info
            )
            QMessageBox.information(self, "成功", "注册成功!")
            self.accept()
        except Exception as e:
            QMessageBox.warning(self, "失败", f"注册失败:{e}")

    def verify_referral(self, code, default=1):
        return default == 1

    def get_ip_and_area(self):
        return "192.168.1.100", "本地测试"


# ======================== 我的资料窗口 ========================
class ProfileDialog(QDialog):
    def __init__(self, account, net_name, phone, password, parent=None):
        super().__init__(parent)
        self.account = account
        self.original_net_name = net_name
        self.original_phone = phone
        self.password = password
        self.setWindowTitle("我的资料")
        self.setFixedWidth(500)
        self.init_ui()
        self.apply_styles()
        self.load_data()

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

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(15)

        self.account_edit = QLineEdit()
        self.account_edit.setReadOnly(True)
        self.netname_edit = QLineEdit()
        self.phone_edit = QLineEdit()

        form_layout.addRow("用户账号:", self.account_edit)
        form_layout.addRow("用户网名:", self.netname_edit)
        form_layout.addRow("联系方式:", self.phone_edit)
        layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.save_btn = QPushButton("保 存")
        self.save_btn.setFixedHeight(38)
        self.save_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(38)
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.save_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)

        self.save_btn.clicked.connect(self.on_save)
        self.cancel_btn.clicked.connect(self.reject)

    def apply_styles(self):
        self.setStyleSheet("""
            QLabel { color: #333; font-size: 18px; }
            QLineEdit { border: 1px solid #d0d7e5; border-radius: 5px; padding: 8px 12px; background: white; font-size: 18px; }
            QLineEdit:focus { border: 2px solid #4F7EF7; padding: 7px 11px; }
            QLineEdit[readOnly="true"] { background: #f0f3f9; color: #666; }
            QPushButton#primaryBtn { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #6b9af8, stop:1 #4F7EF7); color: white; border: none; border-radius: 5px; font-size: 18px; font-weight: bold; min-width: 100px; }
            QPushButton#primaryBtn:hover { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #7ba8ff, stop:1 #5f8eff); }
            QPushButton#secondaryBtn { background: white; color: #4F7EF7; border: 2px solid #4F7EF7; border-radius: 5px; font-size: 18px; font-weight: bold; min-width: 100px; }
            QPushButton#secondaryBtn:hover { background: #eaf1ff; }
        """)

    def load_data(self):
        self.account_edit.setText(self.account)
        self.netname_edit.setText(self.original_net_name)
        self.phone_edit.setText(self.original_phone)

    def on_save(self):
        new_netname = self.netname_edit.text().strip()
        new_phone = self.phone_edit.text().strip()

        if not new_netname or not new_phone:
            QMessageBox.warning(self, "警告", "网名和联系方式不能为空!")
            self.load_data()
            return

        if not re.match(r'^[\u4e00-\u9fa5a-zA-Z0-9]{1,18}$', new_netname):
            QMessageBox.warning(self, "警告", "网名格式不正确。")
            return

        if not re.match(r'^(\d{11}|\d{3,4}-?\d{7,8})$', new_phone):
            QMessageBox.warning(self, "警告", "联系方式格式不正确。")
            return

        if new_netname == self.original_net_name and new_phone == self.original_phone:
            self.accept()
            return

        hash_phone = crypto.generate_query_hash(new_phone)
        if db.is_phone_exist_exclude_account("云约智能(企业版)", hash_phone, self.account):
            QMessageBox.warning(self, "警告", "该联系方式已与其他账号绑定。")
            return

        encrypted_phone = crypto.encrypt(new_phone)
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        db.update_profile(self.account, new_netname, encrypted_phone, hash_phone)

        old_history = db.get_history_info(self.account)
        history_list = json.loads(old_history) if old_history else []
        history_entry = {
            "phone": crypto.encrypt(self.original_phone),
            "password": crypto.generate_hash(self.password),
            "operate_time": now
        }
        history_list.append(history_entry)
        db.set_history_info(self.account, json.dumps(history_list))

        QMessageBox.information(self, "成功", "资料修改成功!")
        self.accept()


# ======================== 修改密码窗口 ========================
class ChangePasswordDialog(QDialog):
    def __init__(self, account, phone, parent=None):
        super().__init__(parent)
        self.account = account
        self.phone = phone
        self.setWindowTitle("修改密码")
        self.setFixedWidth(500)
        self.init_ui()
        self.apply_styles()

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

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(20)

        self.old_pwd_edit = QLineEdit()
        self.old_pwd_edit.setEchoMode(QLineEdit.Password)
        self.old_pwd_edit.setPlaceholderText("请输入原密码")
        self.new_pwd_edit = QLineEdit()
        self.new_pwd_edit.setEchoMode(QLineEdit.Password)
        self.new_pwd_edit.setPlaceholderText("请输入新密码")
        self.confirm_pwd_edit = QLineEdit()
        self.confirm_pwd_edit.setEchoMode(QLineEdit.Password)
        self.confirm_pwd_edit.setPlaceholderText("请再次输入新密码")

        form_layout.addRow("原密码:", self.old_pwd_edit)
        form_layout.addRow("新密码:", self.new_pwd_edit)
        form_layout.addRow("确认密码:", self.confirm_pwd_edit)
        layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setFixedHeight(38)
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(38)
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.on_ok)
        self.cancel_btn.clicked.connect(self.reject)

    def apply_styles(self):
        self.setStyleSheet("""
            QLabel { color: #333; font-size: 18px; }
            QLineEdit { border: 1px solid #d0d7e5; border-radius: 5px; padding: 8px 12px; background: white; font-size: 18px; }
            QLineEdit:focus { border: 2px solid #4F7EF7; padding: 7px 11px; }
            QPushButton#primaryBtn { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #6b9af8, stop:1 #4F7EF7); color: white; border: none; border-radius: 5px; font-size: 18px; font-weight: bold; min-width: 100px; }
            QPushButton#primaryBtn:hover { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #7ba8ff, stop:1 #5f8eff); }
            QPushButton#secondaryBtn { background: white; color: #4F7EF7; border: 2px solid #4F7EF7; border-radius: 5px; font-size: 18px; font-weight: bold; min-width: 100px; }
            QPushButton#secondaryBtn:hover { background: #eaf1ff; }
        """)

    def on_ok(self):
        old_pwd = self.old_pwd_edit.text().strip()
        new_pwd = self.new_pwd_edit.text().strip()
        confirm_pwd = self.confirm_pwd_edit.text().strip()

        if not all([old_pwd, new_pwd, confirm_pwd]):
            QMessageBox.warning(self, "警告", "所有字段不能为空!")
            return

        stored_hash = db.get_password_hash(self.account)
        if not stored_hash or crypto.verify_hash(old_pwd, stored_hash) != 0:
            QMessageBox.warning(self, "错误", "原密码不正确!")
            return

        if not re.match(r'^[a-zA-Z0-9]{8,18}$', new_pwd):
            QMessageBox.warning(self, "警告", "新密码必须为8~18位字母或数字。")
            return
        if new_pwd != confirm_pwd:
            QMessageBox.warning(self, "警告", "两次输入的新密码不一致!")
            return
        if new_pwd == old_pwd:
            QMessageBox.warning(self, "警告", "新密码不能与原密码相同!")
            return

        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        hashed_new = crypto.generate_hash(new_pwd)

        db.update_password(self.account, hashed_new)

        old_history = db.get_history_info(self.account)
        history_list = json.loads(old_history) if old_history else []
        encrypted_phone = db.get_encrypted_phone(self.account)
        history_entry = {
            "phone": encrypted_phone,
            "password": stored_hash,
            "operate_time": now
        }
        history_list.append(history_entry)
        db.set_history_info(self.account, json.dumps(history_list))

        QMessageBox.information(self, "成功", "密码修改成功!")
        self.accept()


# ======================== 设置新密码弹窗 ========================
class SetNewPasswordDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("设置新密码")
        self.setFixedWidth(460)
        self.init_ui()
        self.apply_styles()
        self.new_password = None

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

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(20)

        self.new_pwd_edit = QLineEdit()
        self.new_pwd_edit.setEchoMode(QLineEdit.Password)
        self.new_pwd_edit.setPlaceholderText("请输入新密码")
        self.confirm_pwd_edit = QLineEdit()
        self.confirm_pwd_edit.setEchoMode(QLineEdit.Password)
        self.confirm_pwd_edit.setPlaceholderText("请再次输入新密码")

        form_layout.addRow("新密码:", self.new_pwd_edit)
        form_layout.addRow("确认密码:", self.confirm_pwd_edit)
        layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setFixedHeight(38)
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(38)
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.validate)
        self.cancel_btn.clicked.connect(self.reject)

    def apply_styles(self):
        self.setStyleSheet("""
            QDialog { background-color: #f8faff; }
            QLabel { color: #333; font-size: 18px; }
            QLineEdit { border: 1px solid #d0d7e5; border-radius: 5px; padding: 8px 12px; background: white; font-size: 18px; }
            QLineEdit:focus { border: 2px solid #4F7EF7; padding: 7px 11px; }
        """)

    def validate(self):
        new_pwd = self.new_pwd_edit.text().strip()
        confirm_pwd = self.confirm_pwd_edit.text().strip()
        if not new_pwd:
            QMessageBox.warning(self, "警告", "新密码不能为空!")
            return
        if new_pwd != confirm_pwd:
            QMessageBox.warning(self, "警告", "两次输入的密码不一致!")
            return
        self.new_password = new_pwd
        self.accept()


# ======================== 快速找回密码窗口 ========================
class FindPasswordDialog(QDialog):
    def __init__(self, customer_account=None, parent=None):
        super().__init__(parent)
        self.customer_account = customer_account
        self.setWindowTitle("快速找回密码")
        self.setFixedWidth(500)
        self.matched_user = None
        self.init_ui()
        self.apply_styles()

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

        hint_label = QLabel("请至少填写用户账号或联系方式其中一项")
        hint_label.setStyleSheet("color: #4F7EF7; font-size: 18px; margin-bottom: 10px;")
        layout.addWidget(hint_label)

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(20)

        self.account_edit = QLineEdit()
        self.account_edit.setPlaceholderText("请输入用户账号")
        self.phone_edit = QLineEdit()
        self.phone_edit.setPlaceholderText("请输入联系方式")
        self.question_edit = QLineEdit()
        self.question_edit.setReadOnly(True)
        self.question_edit.setPlaceholderText("验证通过后自动显示")
        self.answer_edit = QLineEdit()
        self.answer_edit.setPlaceholderText("请输入密保答案")

        form_layout.addRow("用户账号:", self.account_edit)
        form_layout.addRow("联系方式:", self.phone_edit)
        form_layout.addRow("密保问题:", self.question_edit)
        form_layout.addRow("密码答案:", self.answer_edit)
        layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setFixedHeight(40)
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(40)
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)

        self.account_edit.editingFinished.connect(self.auto_verify)
        self.phone_edit.editingFinished.connect(self.auto_verify)
        self.ok_btn.clicked.connect(self.on_ok)
        self.cancel_btn.clicked.connect(self.reject)

    def apply_styles(self):
        self.setStyleSheet("""
            QDialog { background-color: #f8faff; }
            QLabel { color: #333; font-size: 18px; }
            QLineEdit { border: 1px solid #d0d7e5; border-radius: 5px; padding: 8px 12px; background: white; font-size: 18px; }
            QLineEdit:focus { border: 2px solid #4F7EF7; padding: 7px 11px; }
            QLineEdit[readOnly="true"] { background: #f0f3f9; color: #666; }
        """)

    def auto_verify(self):
        account = self.account_edit.text().strip()
        phone = self.phone_edit.text().strip()
        if not account and not phone:
            self.question_edit.clear()
            self.matched_user = None
            return

        hash_phone = crypto.generate_query_hash(phone) if phone else None
        user = db.find_user_by_account_or_phone(account, hash_phone)
        if not user:
            QMessageBox.warning(self, "提示", "未找到匹配的账号信息。")
            self.question_edit.clear()
            self.matched_user = None
            return

        self.matched_user = user
        self.account_edit.setText(user["customer_account"])
        self.account_edit.setReadOnly(True)
        decrypted_phone = crypto.decrypt(user["contact_phone"])
        self.phone_edit.setText(decrypted_phone)
        self.phone_edit.setReadOnly(True)

        security_info = json.loads(user["security_info"])
        if security_info:
            self.question_edit.setText(security_info[-1]["pwd_question"])
        else:
            self.question_edit.clear()

    def on_ok(self):
        if not self.matched_user:
            QMessageBox.warning(self, "警告", "请先完成身份验证。")
            return

        answer = self.answer_edit.text().strip()
        if not answer:
            QMessageBox.warning(self, "警告", "请输入密保答案。")
            return

        security_info = json.loads(self.matched_user["security_info"])
        if not security_info or security_info[-1]["pwd_answer"] != answer:
            QMessageBox.warning(self, "错误", "密保答案不正确。")
            return

        dlg = SetNewPasswordDialog(self)
        if dlg.exec_() == QDialog.Accepted:
            new_pwd = dlg.new_password
            now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            hashed_new = crypto.generate_hash(new_pwd)

            db.update_password(self.matched_user["customer_account"], hashed_new)

            old_phone = self.matched_user["contact_phone"]
            old_pwd_hash = self.matched_user["customer_pwd"]
            old_history = db.get_history_info(self.matched_user["customer_account"])
            history_list = json.loads(old_history) if old_history else []
            history_list.append({
                "phone": old_phone,
                "password": old_pwd_hash,
                "operate_time": now
            })
            db.set_history_info(self.matched_user["customer_account"], json.dumps(history_list))

            QMessageBox.information(self, "成功", "新密码设置成功!")
            self.accept()


# ======================== 完善团队信息窗口 ========================
class TeamInfoDialog(QDialog):
    DEPARTMENTS = ["工程部", "技术部", "财务部", "行政部", "物资部", "未分组"]

    def __init__(self, account, parent=None):
        super().__init__(parent)
        self.account = account
        self.setWindowTitle("完善团队信息")
        self.setFixedWidth(500)
        self.init_ui()
        self.apply_styles()

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

        form_layout = QFormLayout()
        form_layout.setLabelAlignment(Qt.AlignRight)
        form_layout.setSpacing(15)

        self.code_edit = QLineEdit()
        self.code_edit.setPlaceholderText("12位大写字母(不含I,O)+数字")
        self.name_edit = QLineEdit()
        self.phone_edit = QLineEdit()
        self.role_combo = QComboBox()
        self.role_combo.addItems(["", "团长", "管理员", "组长", "队员"])
        self.depart_combo = QComboBox()
        self.depart_combo.addItem("")
        self.depart_combo.addItems(self.DEPARTMENTS)

        form_layout.addRow("编码:", self.code_edit)
        form_layout.addRow("姓名:", self.name_edit)
        form_layout.addRow("电话:", self.phone_edit)
        form_layout.addRow("权限:", self.role_combo)
        form_layout.addRow("部门:", self.depart_combo)
        layout.addLayout(form_layout)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setFixedHeight(38)
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setFixedHeight(38)
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.on_save)
        self.cancel_btn.clicked.connect(self.reject)

    def apply_styles(self):
        self.setStyleSheet("""
            QLabel { color: #333; font-size: 18px; }
            QLineEdit, QComboBox { border: 1px solid #d0d7e5; border-radius: 5px; padding: 8px 12px; background: white; font-size: 18px; }
            QLineEdit:focus, QComboBox:focus { border: 2px solid #4F7EF7; padding: 7px 11px; }
        """)

    def on_save(self):
        code = self.code_edit.text().strip()
        name = self.name_edit.text().strip()
        phone = self.phone_edit.text().strip()
        role = self.role_combo.currentText().strip()
        depart = self.depart_combo.currentText().strip()

        if not all([code, name, phone, role, depart]):
            QMessageBox.warning(self, "警告", "所有字段不能为空。")
            return

        if not re.match(r'^[A-HJ-NP-Z0-9]{12}$', code):
            QMessageBox.warning(self, "警告", "成员编码必须为12位大写字母(不含I,O)和数字。")
            return

        team_info = {
            "member_code": code,
            "member_name": name,
            "member_phone": phone,
            "member_role": role,
            "member_depart": depart,
            "group_departs": self.DEPARTMENTS
        }
        db.update_team_info(self.account, json.dumps(team_info))
        QMessageBox.information(self, "成功", "团队信息更新成功!")
        self.accept()


# ======================== 服务记录窗口 ========================
class ServiceRecordDialog(QDialog):
    def __init__(self, account, service_record=None, parent=None):
        super().__init__(parent)
        self.account = account
        self.service_record = service_record if service_record else []
        self.setWindowTitle("服务记录")
        self.resize(700, 500)
        self.init_ui()
        self.load_data()

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

        self.table = QTableWidget()
        self.table.setColumnCount(4)
        self.table.setHorizontalHeaderLabels(["序号", "内容", "操作人", "时间"])
        self.table.verticalHeader().setVisible(False)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.setColumnWidth(0, 80)
        self.table.setColumnWidth(1, 280)
        self.table.setColumnWidth(2, 150)
        self.table.setColumnWidth(3, 180)

        self.table.setStyleSheet("""
            QHeaderView::section { background-color: #4F7EF7; color: white; }
            QTableWidget::item:selected { background-color: #4F7EF7; color: white; }
        """)

        self.word_delegate = WordWrapDelegate()
        self.table.setItemDelegateForColumn(1, self.word_delegate)

        layout.addWidget(self.table)

        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        self.add_btn = QPushButton("添加记录")
        self.add_btn.setObjectName("primaryBtn")
        self.close_btn = QPushButton("关闭")
        self.close_btn.setObjectName("secondaryBtn")
        btn_layout.addWidget(self.add_btn)
        btn_layout.addWidget(self.close_btn)
        layout.addLayout(btn_layout)

        self.add_btn.clicked.connect(self.add_record)
        self.close_btn.clicked.connect(self.close)

    def load_data(self):
        self.table.setRowCount(len(self.service_record))
        for row, record in enumerate(self.service_record):
            item0 = QTableWidgetItem(str(row + 1))
            item0.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 0, item0)

            item1 = QTableWidgetItem(record.get("content", ""))
            item1.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            self.table.setItem(row, 1, item1)

            item2 = QTableWidgetItem(record.get("operator", ""))
            item2.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 2, item2)

            item3 = QTableWidgetItem(record.get("operate_time", ""))
            item3.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 3, item3)

        self.table.resizeRowsToContents()

    def add_record(self):
        dlg = AddRecordDialog(self.account, "添加服务记录", parent=self)
        if dlg.exec_() == QDialog.Accepted:
            new_record = dlg.get_record()
            if new_record:
                self.service_record.append(new_record)
                db.set_service_records(self.account, self.service_record)
                self.load_data()
                QMessageBox.information(self, "成功", "服务记录添加成功!")


class AddRecordDialog(QDialog):
    def __init__(self, account, title="添加记录", parent=None):
        super().__init__(parent)
        self.account = account
        self.setWindowTitle(title)
        self.setFixedSize(420, 320)
        self.record = None
        self.init_ui()
        self.apply_styles()

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

        title_label = QLabel("新增记录")
        title_label.setStyleSheet("font-size: 20px; font-weight: bold; color: #4F7EF7;")
        layout.addWidget(title_label)

        self.text_edit = QTextEdit()
        self.text_edit.setPlaceholderText("请输入记录内容...")
        layout.addWidget(self.text_edit)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.validate)
        self.cancel_btn.clicked.connect(self.reject)

    def apply_styles(self):
        self.setStyleSheet("""
            QTextEdit { border: 1px solid #d0d7e5; border-radius: 5px; padding: 8px; font-size: 16px; }
        """)

    def validate(self):
        content = self.text_edit.toPlainText().strip()
        if not content:
            QMessageBox.warning(self, "警告", "内容不能为空!")
            return
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.record = {"content": content, "operator": self.account, "operate_time": now}
        self.accept()

    def get_record(self):
        return self.record


# ======================== 客户评价窗口 ========================
class CustomerEvaluateDialog(QDialog):
    def __init__(self, account, parent=None):
        super().__init__(parent)
        self.account = account
        self.setWindowTitle("客户评价")
        self.setFixedSize(420, 320)
        self.init_ui()
        self.apply_styles()

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

        title_label = QLabel("写下您的评价")
        title_label.setStyleSheet("font-size: 20px; font-weight: bold; color: #4F7EF7;")
        layout.addWidget(title_label)

        self.text_edit = QTextEdit()
        self.text_edit.setPlaceholderText("请在此输入评价内容...")
        layout.addWidget(self.text_edit)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("提 交")
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.on_ok)
        self.cancel_btn.clicked.connect(self.reject)

    def apply_styles(self):
        self.setStyleSheet("""
            QTextEdit { border: 1px solid #d0d7e5; border-radius: 5px; padding: 8px; font-size: 16px; }
        """)

    def on_ok(self):
        content = self.text_edit.toPlainText().strip()
        if not content:
            QMessageBox.warning(self, "警告", "评价内容不能为空!")
            return
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        evaluate_entry = {"content": content, "evaluate_time": now}

        evaluate_list = db.get_customer_evaluate(self.account)
        evaluate_list.append(evaluate_entry)

        try:
            db.set_customer_evaluate(self.account, evaluate_list)
            QMessageBox.information(self, "成功", "评价提交成功!")
            self.accept()
        except Exception as e:
            QMessageBox.warning(self, "失败", f"提交失败:{e}")


# ======================== 客户评价历史窗口 ========================
class EvaluateHistoryDialog(QDialog):
    def __init__(self, customer_evaluate=None, parent=None):
        super().__init__(parent)
        self.evaluate_data = customer_evaluate if customer_evaluate else []
        self.setWindowTitle("客户评价历史记录")
        self.resize(600, 400)
        self.init_ui()
        self.load_data()

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

        self.table = QTableWidget()
        self.table.setColumnCount(3)
        self.table.setHorizontalHeaderLabels(["序号", "内容", "时间"])
        self.table.verticalHeader().setVisible(False)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.setColumnWidth(0, 80)
        self.table.setColumnWidth(1, 300)
        self.table.setColumnWidth(2, 180)

        self.table.setStyleSheet("""
            QHeaderView::section { background-color: #4F7EF7; color: white; }
            QTableWidget::item:selected { background-color: #4F7EF7; color: white; }
        """)

        self.word_delegate = WordWrapDelegate()
        self.table.setItemDelegateForColumn(1, self.word_delegate)

        layout.addWidget(self.table)

        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        self.close_btn = QPushButton("关 闭")
        self.close_btn.setObjectName("secondaryBtn")
        btn_layout.addWidget(self.close_btn)
        layout.addLayout(btn_layout)
        self.close_btn.clicked.connect(self.close)

    def load_data(self):
        self.table.setRowCount(len(self.evaluate_data))
        for row, record in enumerate(self.evaluate_data):
            item0 = QTableWidgetItem(str(row + 1))
            item0.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 0, item0)

            item1 = QTableWidgetItem(record.get("content", ""))
            item1.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            self.table.setItem(row, 1, item1)

            item2 = QTableWidgetItem(record.get("evaluate_time", ""))
            item2.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 2, item2)

        self.table.resizeRowsToContents()


# ======================== 客户备注窗口 ========================
class CustomerRemarkDialog(QDialog):
    def __init__(self, account, customer_remark=None, parent=None):
        super().__init__(parent)
        self.account = account
        self.remark_data = customer_remark if customer_remark else []
        self.setWindowTitle("客户备注")
        self.resize(700, 500)
        self.init_ui()
        self.load_data()

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

        self.table = QTableWidget()
        self.table.setColumnCount(4)
        self.table.setHorizontalHeaderLabels(["序号", "内容", "操作人", "时间"])
        self.table.verticalHeader().setVisible(False)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.setColumnWidth(0, 80)
        self.table.setColumnWidth(1, 280)
        self.table.setColumnWidth(2, 150)
        self.table.setColumnWidth(3, 180)

        self.table.setStyleSheet("""
            QHeaderView::section { background-color: #4F7EF7; color: white; }
            QTableWidget::item:selected { background-color: #4F7EF7; color: white; }
        """)

        self.word_delegate = WordWrapDelegate()
        self.table.setItemDelegateForColumn(1, self.word_delegate)

        layout.addWidget(self.table)

        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        self.add_btn = QPushButton("添加备注")
        self.add_btn.setObjectName("primaryBtn")
        self.close_btn = QPushButton("关 闭")
        self.close_btn.setObjectName("secondaryBtn")
        btn_layout.addWidget(self.add_btn)
        btn_layout.addWidget(self.close_btn)
        layout.addLayout(btn_layout)

        self.add_btn.clicked.connect(self.add_remark)
        self.close_btn.clicked.connect(self.close)

    def load_data(self):
        self.table.setRowCount(len(self.remark_data))
        for row, record in enumerate(self.remark_data):
            item0 = QTableWidgetItem(str(row + 1))
            item0.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 0, item0)

            item1 = QTableWidgetItem(record.get("content", ""))
            item1.setTextAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            self.table.setItem(row, 1, item1)

            item2 = QTableWidgetItem(record.get("operator", ""))
            item2.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 2, item2)

            item3 = QTableWidgetItem(record.get("operate_time", ""))
            item3.setTextAlignment(Qt.AlignCenter)
            self.table.setItem(row, 3, item3)

        self.table.resizeRowsToContents()

    def add_remark(self):
        dlg = AddRecordDialog(self.account, "添加备注", parent=self)
        if dlg.exec_() == QDialog.Accepted:
            new_record = dlg.get_record()
            if new_record:
                self.remark_data.append(new_record)
                db.set_customer_remark(self.account, self.remark_data)
                self.load_data()
                QMessageBox.information(self, "成功", "备注添加成功!")


# ======================== 授权窗口 ========================
class AuthorizationDialog(QDialog):
    def __init__(self, account=None, parent=None):
        super().__init__(parent)
        self.setWindowTitle("授权管理")
        self.setFixedSize(400, 200)
        self.init_ui()
        self.apply_styles()

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

        self.auth_edit = QLineEdit()
        self.auth_edit.setPlaceholderText("请输入32位授权码(大写字母不含I,O和数字)")
        layout.addWidget(self.auth_edit)

        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(20)
        self.ok_btn = QPushButton("确 定")
        self.ok_btn.setObjectName("primaryBtn")
        self.cancel_btn = QPushButton("取 消")
        self.cancel_btn.setObjectName("secondaryBtn")
        btn_layout.addStretch()
        btn_layout.addWidget(self.ok_btn)
        btn_layout.addWidget(self.cancel_btn)
        layout.addLayout(btn_layout)

        self.ok_btn.clicked.connect(self.on_ok)
        self.cancel_btn.clicked.connect(self.reject)

    def apply_styles(self):
        self.setStyleSheet("""
            QLineEdit { border: 1px solid #d0d7e5; border-radius: 5px; padding: 8px 12px; font-size: 18px; }
        """)

    def on_ok(self):
        auth_code = self.auth_edit.text().strip()
        if not auth_code:
            QMessageBox.warning(self, "警告", "授权码不能为空!")
            return
        if not re.match(r'^[A-HJ-NP-Z0-9]{32}$', auth_code):
            QMessageBox.warning(self, "警告", "授权码格式不正确,应为32位大写字母(不含I,O)和数字。")
            return
        QMessageBox.information(self, "成功", "恭喜,授权成功!")
        self.accept()


# ======================== 主窗口 ========================
class MainWindow(QWidget):
    def __init__(self, account, net_name, phone, password):
        super().__init__()
        self.account = account
        self.net_name = net_name
        self.phone = phone
        self.password = password
        self.setWindowTitle("我的主窗口")
        self.resize(1000, 700)
        self.init_ui()
        self.apply_styles()

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

        title = QLabel(f"欢迎,{self.net_name}")
        title.setAlignment(Qt.AlignCenter)
        title.setStyleSheet("font-size: 24px; font-weight: bold; color: #4F7EF7;")
        layout.addWidget(title)

        grid = QGridLayout()
        grid.setSpacing(15)

        buttons_info = [
            ("我的资料", self.open_profile),
            ("修改密码", self.open_change_password),
            ("找回密码", self.open_find_password),
            ("团队信息", self.open_team_info),
            ("服务记录", self.open_service_record),
            ("客户评价", self.open_customer_evaluate),
            ("评价历史", self.open_evaluate_history),
            ("客户备注", self.open_customer_remark),
            ("授权管理", self.open_authorization),
        ]
        for i in range(21):
            buttons_info.append((f"备用按钮{i+1}", lambda _, name=f"备用按钮{i+1}": self.show_spare(name)))

        row, col = 0, 0
        for text, func in buttons_info:
            btn = QPushButton(text)
            btn.setFixedSize(160, 50)
            btn.setObjectName("primaryBtn" if "备用" not in text else "secondaryBtn")
            btn.clicked.connect(func)
            grid.addWidget(btn, row, col)
            col += 1
            if col >= 5:
                col = 0
                row += 1

        layout.addLayout(grid)

    def apply_styles(self):
        self.setStyleSheet("""
            QWidget { background-color: #f8faff; }
            QPushButton#primaryBtn, QPushButton#secondaryBtn {
                border-radius: 8px; font-size: 18px; font-weight: bold;
            }
            QPushButton#primaryBtn { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #6b9af8, stop:1 #4F7EF7); color: white; border: none; }
            QPushButton#primaryBtn:hover { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #7ba8ff, stop:1 #5f8eff); }
            QPushButton#secondaryBtn { background: white; color: #4F7EF7; border: 2px solid #4F7EF7; }
            QPushButton#secondaryBtn:hover { background: #eaf1ff; }
        """)

    def open_profile(self):
        dlg = ProfileDialog(self.account, self.net_name, self.phone, self.password, self)
        dlg.exec_()

    def open_change_password(self):
        dlg = ChangePasswordDialog(self.account, self.phone, self)
        dlg.exec_()

    def open_find_password(self):
        dlg = FindPasswordDialog(customer_account=self.account, parent=self)
        dlg.exec_()

    def open_team_info(self):
        dlg = TeamInfoDialog(self.account, self)
        dlg.exec_()

    def open_service_record(self):
        data = db.get_service_records(self.account)
        dlg = ServiceRecordDialog(self.account, data, self)
        dlg.exec_()

    def open_customer_evaluate(self):
        dlg = CustomerEvaluateDialog(self.account, self)
        dlg.exec_()

    def open_evaluate_history(self):
        data = db.get_customer_evaluate(self.account)
        dlg = EvaluateHistoryDialog(data, self)
        dlg.exec_()

    def open_customer_remark(self):
        data = db.get_customer_remark(self.account)
        dlg = CustomerRemarkDialog(self.account, data, self)
        dlg.exec_()

    def open_authorization(self):
        dlg = AuthorizationDialog(self.account, self)
        dlg.exec_()

    def show_spare(self, name):
        QMessageBox.information(self, "备用按钮", f"您点击了:{name}")


# ======================== 程序入口 ========================
if __name__ == "__main__":
    config = {
        'applicationName': 'PyQt5 主题化控件库演示',
        'organizationName': 'MyCompany',
        'organizationDomain': 'mycompany.com',
        'applicationVersion': '2.0',
        'windowIcon': 'fox.ico',
        'font': {
            'family': 'Microsoft YaHei',
            'pointSize': 9,
            'weight': QFont.Normal
        },
        'translatorPath': 'qt_zh_CN.qm'
    }

    app = QApplication(sys.argv,config)
    app.setFont(QFont("Microsoft YaHei", 10))
    login = LoginWindow()
    login.show()
    sys.exit(app.exec_())
相关推荐
好奇龙猫2 小时前
[大学院-python-base gammer learning2: python base programming ]
开发语言·python
2301_803875612 小时前
c++如何通过重定向streambuf流捕获标准错误输出并记录到运行日志【详解】
jvm·数据库·python
2301_795099742 小时前
HTML怎么创建时间轴布局_HTML结构化时间线写法【方法】
jvm·数据库·python
运气好好的2 小时前
CSS组件库如何快速扩展_通过Sass @extend继承基础布局
jvm·数据库·python
m0_613856292 小时前
Go install 命令失效原因解析与正确使用指南
jvm·数据库·python
jaycyj2 小时前
pytest
开发语言·python
Gary Studio2 小时前
安卓HAL编译流程
开发语言·python
tangweiguo030519872 小时前
LangChain + RAG + Agent + 多模态 完整实战教程
python·langchain
我是无敌小恐龙3 小时前
Java SE 零基础入门Day06 方法重载+Debug调试+String字符串全套API详解(超全干货)
java·开发语言·人工智能·python·transformer·无人机·量子计算