基于 Qt 的智慧社区物业管理系统

基于 Qt 的智慧社区物业管理系统

项目描述

这是一个面向物业公司的社区管理桌面软件,实现了业主信息管理、房屋管理、车位管理、缴费管理、报修管理等核心业务功能。系统支持管理员、员工、业主三种角色登录,不同角色拥有不同权限。

项目描述:

  • 基于 Qt 框架开发的桌面端物业管理系统,支持业主、管理员、工作人员三端登录

  • 实现业主信息管理、房屋管理、物业费缴纳、报修工单流转、车位申请等核心功能

  • 采用 MVC 设计模式,使用 QSqlTableModel 实现数据与界面分离

  • 使用 SHA-256 加密用户密码,防止 SQL 注入,保证数据安全

  • 运用 Qt 样式表(QSS)美化界面,提升用户体验

个人贡献:

  • 独立完成数据库表设计和核心业务逻辑开发

  • 实现了业主管理、缴费管理、报修管理 3 个核心模块

  • 优化了数据库查询性能,支持 10000+ 条数据流畅显示

  • 编写了完整的代码注释和技术文档

系统版本

技术栈:Qt 6.10.3 / C++ / SQLite / SQL

核心职责

  1. 负责登录模块开发:实现三种角色(管理员/员工/业主)的身份认证和权限控制。

  2. 负责业主管理模块:实现业主信息的增删改查功能,使用QTableWidget展示数据列表,通过QDialog弹出编辑窗口。

  3. 负责数据库设计:设计并创建 SQLite 数据库,包含 `worker`、`owner`、`house`、`carstation`、`pay`、`issue` 等数据表,使用 `QSqlDatabase` 和 `QSqlQuery` 进行操作。

  4. 负责界面优化:使用 Qt Designer 设计友好的用户界面,优化用户体验。

项目功能演示

1. 登录界面

2. 尝试登录

你可以尝试以下默认账号(具体看数据库中有什么数据):

角色 用户名 密码
管理员 admin 123456(或 admin)
业主 1001 123456

没有注册账号的话会显示没有此账号

3. 探索功能模块

登录后,尝试以下操作:

  1. 业主管理 - 添加、编辑、删除业主

  2. 缴费管理 - 查看缴费记录

  3. 自助缴费 - 输入金额,选择类型,点击确认

核心功能测试清单

功能 测试步骤 预期结果
登录 输入正确的用户名密码 进入主界面
添加业主 点击"添加"→输入信息→保存 列表中出现新业主
自助缴费 选择类型→输入金额→点击确认 弹出"缴费成功"提示
退出 点击退出按钮 关闭窗口

代码

1.登录功能模块

logindialog.h

原始版本一

cpp 复制代码
#ifndef LOGINDIALOG_H
#define LOGINDIALOG_H

#include <QDialog>
#include <QMessageBox>
#include <QButtonGroup>
#include <QSqlQuery>
#include <QSqlTableModel>
#include <QSqlRecord>
#include <QDebug>
#include "managermanage.h"
#include "workermanage.h"
#include "ownermanage.h"

namespace Ui {
class LoginDialog;
}
//登录对话框LoginDialog类,公有继承自QDialog类
class LoginDialog : public QDialog
{
    Q_OBJECT

public:
    /***************explicit关键字********************
     *   explicit是C++语言关键字,用于组织函数的隐式转换
     * 调用。使用此关键词的构造函数,就不能再使用隐式转换
     * 了。
     *   在C++中,一个带参构造函数有两个作用,第一个充当
     * 构造器;第二个是默认且隐含的类型转换操作符。为了
     * 避免构造错误,很多时候我们需要禁止。
     * ************************************************/
    explicit LoginDialog(QWidget *parent = 0);  //构造函数
    ~LoginDialog();     //析构函数
    void clearAll();    //清除窗口用户输入内容函数
    bool judgeEmpty();  //判断用户输入内容是否为空函数

private:
    Ui::LoginDialog *ui;
    /***************主界面*****************************
     *  从登录对话框进入的界面,就三种,分别是管理员界面、
     *工作人员界面和用户界面,不同身份登陆不同的系统界面,
     *完成不同的应用功能。
     *************************************************/
    //定义指向 管理界面类对象 的指针manager
    ManagerManage *manager;
    //定义指向 工作人员界面类对象 的指针worker
    WorkerManage *worker;
    //定义指向 业主界面类对象 的指针owner
    OwnerManage *owner;
    /*定义按键组指针radioGroup,指向登陆对话框中,
     *由管理者、工作人员和用户共同组成的按键组**/
    QButtonGroup *radioGroup;
    QSqlTableModel *model;//该模式并未使用????????????????

signals:
    void toManagerManage(QString,QString);
    void toWorkerManage(QString,QString);
    void toOwnnerManage(QString,QString);

private slots:
    void exitbtnSlot(); //退出按键按下信号触发的槽函数
    void loginbtnSlot();//登录按键按下信号触发的槽函数

};

#endif // LOGINDIALOG_H

修复版本二

无注释版
cpp 复制代码
#ifndef LOGINDIALOG_H
#define LOGINDIALOG_H

#include <QDialog>
#include <QButtonGroup>
#include <QSqlQuery>
#include <QSettings>

class ManagerManage;
class WorkerManage;
class OwnerManage;

namespace Ui {
class LoginDialog;
}

class LoginDialog : public QDialog
{
    Q_OBJECT

public:
    explicit LoginDialog(QWidget *parent = 0);
    ~LoginDialog();

    void clearAll();
    bool judgeEmpty();

private slots:
    void exitbtnSlot();
    void loginbtnSlot();

private:
    Ui::LoginDialog *ui;

    ManagerManage *manager;
    WorkerManage *worker;
    OwnerManage *owner;

    QButtonGroup *radioGroup;

    void loginAsAdmin(const QString &username, const QString &password);
    void loginAsWorker(const QString &username, const QString &password);
    void loginAsOwner(const QString &username, const QString &password);
    void clearInput();

    void loadSettings();
    void saveSettings();
};

#endif // LOGINDIALOG_H
有注释版
cpp 复制代码
// ============================================================
// 文件:logindialog.h
// 功能:登录对话框类的头文件声明
// 说明:定义了登录对话框的类结构、成员变量和函数接口
// ============================================================

#ifndef LOGINDIALOG_H
// 作用:防止头文件被多次包含(Include Guard)
// 原理:如果 LOGINDIALOG_H 未定义,则定义它并包含头文件内容
//       如果已经定义,则跳过整个头文件,避免重复定义错误
// 这是 C/C++ 头文件的标准写法,避免编译错误

#define LOGINDIALOG_H
// 定义宏 LOGINDIALOG_H
// 与 #ifndef 配对,表示这个头文件已经被包含过一次
// 如果再次包含,由于 LOGINDIALOG_H 已定义,会跳过整个文件内容

// ============================================================
// 头文件包含
// ============================================================

#include <QDialog>
// 包含 QDialog 基类
// QDialog 是 Qt 中对话框的基类,提供模态/非模态显示、返回值(exec())等功能
// 继承自 QWidget,所以也拥有所有 QWidget 的特性(信号、槽、事件等)
// 本类 LoginDialog 需要继承 QDialog 来实现登录对话框

#include <QButtonGroup>
// 包含 QButtonGroup 类
// QButtonGroup 用于管理一组按钮,实现单选互斥效果
// 在本类中用于管理"管理员/工作人员/业主"三个单选按钮
// 通过 checkedId() 可以获取用户选中的角色 ID

#include <QSqlQuery>
// 包含 QSqlQuery 类
// QSqlQuery 用于执行 SQL 查询和操作数据库
// 在头文件中包含是为了类型完整性,实际使用在 .cpp 中
// 虽然不一定要在头文件中包含,但为了方便保留

#include <QSettings>
// 包含 QSettings 类,用于读写配置文件
// QSettings 是 Qt 提供的跨平台配置管理类
// Windows: 存储在注册表 HKEY_CURRENT_USER/Software/MyCompany/AppName
// Linux:   存储在 ~/.config/MyCompany/AppName.conf
// macOS:   存储在 ~/Library/Preferences/MyCompany/AppName.plist
// 本类用于实现"记住密码"功能

// ============================================================
// 前向声明(Forward Declaration)
// 作用:告诉编译器这些类存在,但不需要知道它们的完整定义
// 优点:
//   1. 减少编译依赖,加快编译速度
//   2. 避免循环包含(A 包含 B,B 又包含 A)
//   3. 降低头文件之间的耦合度
//   4. 因为这里只使用指针,不需要知道类的完整定义
// ============================================================

class ManagerManage;
// 前向声明 ManagerManage 类(管理员管理界面)
// 这里只需要知道它是一个类,用于声明指针
// 完整的定义在 managermanage.h 中,在 .cpp 中才包含
// 如果在这里包含 managermanage.h,会拖慢编译速度

class WorkerManage;
// 前向声明 WorkerManage 类(工作人员管理界面)
// 用于声明 WorkerManage 类型的指针 worker
// 同样,完整定义在 workermanage.h 中

class OwnerManage;
// 前向声明 OwnerManage 类(业主管理界面)
// 用于声明 OwnerManage 类型的指针 owner
// 完整定义在 ownermanage.h 中

// ============================================================
// UI 命名空间声明
// ============================================================

namespace Ui {
// 定义 Ui 命名空间,用于存放由 .ui 文件生成的类
// 这样可以将界面相关代码与业务逻辑代码分离

class LoginDialog;
// 声明 UI 类 LoginDialog
// 这个类由 Qt 的 uic 工具根据 logindialog.ui 文件自动生成
// 包含了界面上所有控件的指针(按钮、输入框、标签等)
// 通过 Ui::LoginDialog *ui 访问界面控件
// 例如:ui->userLine, ui->passwordLine, ui->loginBtn 等
}

// ============================================================
// LoginDialog 类定义
// 继承自 QDialog,所以拥有对话框的所有特性
// ============================================================

class LoginDialog : public QDialog
// class LoginDialog : 定义一个名为 LoginDialog 的类
// public QDialog : 公有继承自 QDialog 基类
// 公有继承意味着 QDialog 的所有公有成员在 LoginDialog 中也是公有的
// QDialog 提供 exec() 方法以模态方式显示对话框

{
    Q_OBJECT
    // Qt 元对象宏(Meta-Object Macro)
    // 作用:启用 Qt 的元对象系统(Meta-Object System)
    // 具体功能:
    //   1. 支持信号(signals)和槽(slots)机制
    //   2. 支持运行时类型信息(RTTI):qobject_cast<>
    //   3. 支持属性系统(Q_PROPERTY)
    //   4. 支持动态翻译(tr())
    //   5. 支持对象树内存管理
    // 注意:任何使用信号槽的类都必须包含 Q_OBJECT 宏
    //      且需要由 moc(元对象编译器)处理
    //      如果忘记写 Q_OBJECT,编译时会出现信号槽相关的错误

public:
    // ============================================================
    // public 区域:对外公开的接口
    // 其他类可以访问这些成员
    // ============================================================

    explicit LoginDialog(QWidget *parent = 0);
    // 构造函数
    // explicit: 禁止隐式类型转换
    //   例如:LoginDialog d = 0; 会编译错误
    //   必须显式调用:LoginDialog d(0); 或 new LoginDialog(this)
    //   这是 C++ 的最佳实践,避免意外的类型转换
    // QWidget *parent = 0: 父窗口指针,默认值为 nullptr(0)
    //   父对象为 nullptr 时,窗口独立显示
    //   父对象不为 nullptr 时,窗口作为子窗口,随父窗口一起销毁
    //   在 Qt 中,对象树由父对象管理内存

    ~LoginDialog();
    // 析构函数
    // 当对象被销毁时自动调用
    // 负责释放资源(如 delete ui)
    // 在 Qt 中,析构函数还会自动销毁所有子对象(Qt 对象树机制)

    void clearAll();
    // 清空所有输入框的内容
    // 公共函数,外部可以调用
    // 用于在登录失败或需要重置时清空用户输入
    // 实现:ui->userLine->clear() + ui->passwordLine->clear()
    // 并将焦点设置到用户名输入框

    bool judgeEmpty();
    // 判断用户名和密码是否为空
    // 返回值:true - 都不为空,false - 至少有一个为空
    // 公共函数,外部可以调用
    // 用于在登录前验证输入
    // 会弹出警告框提示用户输入完整信息

private slots:
    // ============================================================
    // private slots 区域:私有的槽函数
    // 特点:
    //   1. 只能在类内部被调用(外部不能直接调用)
    //   2. 可以连接到信号,当信号触发时被自动调用
    //   3. 在 Qt 中,槽函数可以是 public/protected/private
    //   4. 建议使用 private slots 来封装内部逻辑
    //      (外部可以通过信号间接调用,但无法直接调用)
    // ============================================================

    void exitbtnSlot();
    // 退出按钮的槽函数
    // 当用户点击"退出"按钮时,此函数被调用
    // 功能:显示确认对话框 → 用户确认后关闭登录对话框,退出程序
    // 通过 QMessageBox::question() 询问用户是否确认退出
    // 如果用户点击"是",则调用 this->close() 关闭窗口

    void loginbtnSlot();
    // 登录按钮的槽函数
    // 当用户点击"登录"按钮时,此函数被调用
    // 功能:验证用户名密码,根据角色跳转到对应的主界面
    // 这是整个登录流程的核心函数
    // 流程:
    //   1. 调用 judgeEmpty() 验证输入
    //   2. 获取用户名、密码、角色 ID
    //   3. 使用 switch 根据角色分发到三个具体登录函数
    //   4. 登录成功后隐藏登录对话框,显示主界面

private:
    // ============================================================
    // private 区域:私有的成员变量和函数
    // 只能在类内部访问,外部不可见
    // 体现了面向对象的封装性(Encapsulation)
    // 隐藏内部实现细节,只暴露必要的接口
    // ============================================================

    // ============================================================
    // UI 对象指针
    // ============================================================

    Ui::LoginDialog *ui;
    // UI 对象指针
    // 指向由 uic 工具生成的 UI 类对象
    // 通过这个指针可以访问界面上所有的控件
    // 例如:ui->userLine(用户名输入框)、ui->passwordLine(密码输入框)
    //       ui->loginBtn(登录按钮)、ui->exitBtn(退出按钮)
    //       ui->managerRadio(管理员单选按钮)
    //       ui->rememberPwdCheckBox(记住密码复选框)
    // 注意:这个指针需要在构造函数中用 new 创建,在析构函数中用 delete 释放
    // 这是 Qt 中 UI 指针的标准用法

    // ============================================================
    // 主界面指针(多态用法)
    // ============================================================

    ManagerManage *manager;
    // 管理员管理界面的指针
    // 当管理员登录成功后,创建 ManagerManage 对象
    // 指向管理员的主窗口
    // ManagerManage 是管理员功能的主界面,包含:业主管理、缴费管理、工作人员管理等
    // 类型为 ManagerManage*,实际指向一个 QWidget 子类对象

    WorkerManage *worker;
    // 工作人员管理界面的指针
    // 当工作人员登录成功后,创建 WorkerManage 对象
    // 指向工作人员的主窗口
    // WorkerManage 是工作人员功能的主界面,包含:工单处理、任务查看等
    // 类型为 WorkerManage*,实际指向一个 QWidget 子类对象

    OwnerManage *owner;
    // 业主管理界面的指针
    // 当业主登录成功后,创建 OwnerManage 对象
    // 指向业主的主窗口
    // OwnerManage 是业主功能的主界面,包含:信息查看、缴费、报修等
    // 类型为 OwnerManage*,实际指向一个 QWidget 子类对象

    // ============================================================
    // 按钮组
    // ============================================================

    QButtonGroup *radioGroup;
    // 角色选择按钮组
    // 管理三个单选按钮:管理员、工作人员、业主
    // 功能:
    //   1. 实现单选互斥(同一时间只能选一个)
    //   2. 通过 checkedId() 获取当前选中的角色 ID
    //   3. ID 值:0-管理员,1-工作人员,2-业主
    // 在构造函数中初始化:
    //   radioGroup->addButton(ui->managerRadio, 0);
    //   radioGroup->addButton(ui->workerRadio, 1);
    //   radioGroup->addButton(ui->ownerRadio, 2);

    // ============================================================
    // 私有辅助函数
    // 用于将复杂的登录逻辑拆分为多个小函数
    // 遵循单一职责原则(Single Responsibility Principle),每个函数只做一件事
    // ============================================================

    void loginAsAdmin(const QString &username, const QString &password);
    // 管理员登录逻辑
    // 参数:username - 用户名,password - 密码
    // const QString&:使用常量引用,避免复制,提高性能
    // 功能:
    //   1. 在 worker 表中查询用户(SELECT * FROM worker WHERE workernum = ?)
    //   2. 验证密码是否正确
    //   3. 验证是否为管理员(workertype = "是")
    //   4. 验证通过后创建 ManagerManage 主窗口
    //   5. 调用 saveSettings() 保存记住密码设置
    // 如果任何验证失败,弹出对应的错误提示

    void loginAsWorker(const QString &username, const QString &password);
    // 工作人员登录逻辑
    // 参数:username - 用户名,password - 密码
    // 功能:
    //   1. 在 worker 表中查询用户(SELECT * FROM worker WHERE workernum = ?)
    //   2. 验证密码是否正确
    //   3. 验证通过后创建 WorkerManage 主窗口
    //   4. 调用 saveSettings() 保存记住密码设置
    // 注意:不需要检查 workertype,任何 worker 表中的用户都可以登录为工作人员

    void loginAsOwner(const QString &username, const QString &password);
    // 业主登录逻辑
    // 参数:username - 用户名,password - 密码
    // 功能:
    //   1. 在 houseowner 表中查询用户(SELECT * FROM houseowner WHERE ownername = ?)
    //   2. 验证密码是否正确
    //   3. 验证通过后创建 OwnerManage 主窗口
    //   4. 调用 saveSettings() 保存记住密码设置
    // houseowner 表结构与 worker 表不同,单独查询

    void clearInput();
    // 清空输入框并设置焦点
    // 功能:
    //   1. 清空用户名输入框(ui->userLine->clear())
    //   2. 清空密码输入框(ui->passwordLine->clear())
    //   3. 将焦点设置到用户名输入框(ui->userLine->setFocus())
    // 使用场景:密码错误时调用,让用户重新输入
    // 与 clearAll() 的区别:clearAll() 是公共接口,clearInput() 是内部辅助

    // ============================================================
    // ✅ 新增:记住密码相关函数
    // ============================================================

    void loadSettings();
    // 加载保存的登录信息
    // 使用 QSettings 从配置文件/注册表读取:
    //   - username: 上次登录的用户名
    //   - password: 上次登录的密码
    //   - remember: 是否勾选了"记住密码"
    // 在构造函数中被调用,实现自动填充用户名和密码
    // 如果 remember 为 true,则自动填入密码并勾选复选框
    // 如果 remember 为 false,只填入用户名(不自动登录)

    void saveSettings();
    // 保存登录信息到配置文件
    // 使用 QSettings 写入配置文件/注册表:
    //   - 如果勾选了"记住密码":保存 username、password、remember=true
    //   - 如果取消了"记住密码":清除 username、password,保存 remember=false
    // 在登录成功后被调用,由三个登录函数触发
    // 保证用户下次打开程序时能自动填充
};

#endif // LOGINDIALOG_H
// 结束 #ifndef LOGINDIALOG_H 条件编译
// 如果头文件被重复包含,从 #ifndef 到 #endif 之间的内容会被跳过
// 这是 C/C++ 头文件的标准写法,确保头文件只被编译一次

1.logindialog.cpp

原始版本一

cpp 复制代码
#include "logindialog.h"
#include "ui_logindialog.h"

/************登录对话框类LoginDialog的构造函数****************/
LoginDialog::LoginDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::LoginDialog)
{
    ui->setupUi(this);

    //新建一个按键组空间并赋值给radioGroup。父类为登录对话框
    radioGroup=new QButtonGroup(this);
    //添加"管理者"  按键,ID设置为0.
    radioGroup->addButton(ui->managerRadio,0);
    //添加"工作人员"按键,ID设置为1.
    radioGroup->addButton(ui->workerRadio,1);
    //添加"业主"    按键,ID设置为2.
    radioGroup->addButton(ui->ownerRadio,2);

    //为登录按钮和退出按钮的"按下信号",设置对应槽函数。
    connect(ui->loginBtn,SIGNAL(clicked()),this,SLOT(loginbtnSlot()));
    connect(ui->exitBtn,SIGNAL(clicked()),this,SLOT(exitbtnSlot()));

}
/************登录对话框类LoginDialog的析构函数****************/
LoginDialog::~LoginDialog()
{
    delete ui;
}

/************《槽函数》登录窗口的用户登录操作*****************/
void LoginDialog::loginbtnSlot()
{
    if(!this->judgeEmpty()) //判断用户名和密码输入是否为空
    {
        ui->passwordLine->clear();  //有一个为空,则清除密码区内容
        return;
    }

    //输出当前身份按键的ID编号,管理者为0,工作人员为1,业主为2
    qDebug() << "radioGroup->checkedId() :" << radioGroup->checkedId();

    //判断身份为"管理员"登录
    if(radioGroup->checkedId()==0)
    {
        //创建数据库操作对象,操作的数据库为默认数据库
        QSqlQuery query;
        //使用位置绑定方式,将userLine账号内容放入select语句的?位置做替换
        query.prepare("select * from worker where workernum=?");
        query.addBindValue(ui->userLine->text().trimmed());
        query.exec();   //执行SQL语句,将用户输入名与数据库中一致的数据筛选出来。
        if(query.next())//select筛选的结果中,一直有数据取出
        {
            /*********worker表结构**********************************
             *  数据库中worker表共有4字段(列),从左向右依此表示为
             *  workernum   workerpass   workerphone   workertypr
             *   用户名        密码          电话       是/否管理员
             *******************************************************/
            //判断用户输入密码与数据库中该用户密码是否一致。是,进入执行语句
            if (query.value(1).toString() == ui->passwordLine->text())
            {
                //如果账户和密码正确,则判断一下,该账户是否是管理员账户
                if(query.value(3).toString()=="否")
                {
                    //虽然账户密码正确,但不是管理员账户,则输出警告窗口
                    QMessageBox::warning(this, tr("此用户非管理员"),
                                         tr("请选择合适权限用户登录"), QMessageBox::Ok);
                  return;
                 }
                //账号密码正确,且是管理员账户。则创建管理员登录窗口
                manager=new ManagerManage;   //创建管理员窗口
                manager->show();    //显示管理员窗口
                this->hide();       //隐藏当前登录对话框
                return;

            }
            //判断账号或密码不一致
            else
            {
                //输出警告窗口,提示账号或密码错误信息
                QMessageBox::warning(this, tr("账号密码错误"),
                                     tr("请输入正确的账号密码再登录!"), QMessageBox::Ok);
                ui->userLine->clear();    //清空用户在账户区输入内容
                ui->passwordLine->clear();//清空用户在密码区输入的内容
                ui->userLine->setFocus(); //将光标定位到用户名输入区
            }
        }
        else //select筛选的结果中,已经没有数据取出,则显示信息窗口,提示没有账号。
            QMessageBox::information(this,tr("提示"),tr("没有此账号!"),QMessageBox::Ok);
    }

    //判断是"工作人员"登录
    else if(radioGroup->checkedId()==1)
    {
        QSqlQuery query;
        query.prepare("select * from worker where workernum=?");
        query.addBindValue(ui->userLine->text());
        query.exec();
        if(query.next())
        {
            if (query.value(1).toString() == ui->passwordLine->text())
            {
                //创建工作人员登录窗口
                worker=new WorkerManage;
                worker->setWindowTitle(ui->userLine->text());
                worker->show();
                this->hide();
                return;
            }
            else
            {
                QMessageBox::warning(this, tr("账号密码错误"),
                                     tr("请输入正确的账号密码再登录!"), QMessageBox::Ok);
                ui->userLine->clear();
                ui->passwordLine->clear();
                ui->userLine->setFocus();
            }
        }
        else
            QMessageBox::information(this,tr("提示"),tr("没有此账号!"),QMessageBox::Ok);
    }

    //判断是业主登录
    else if(radioGroup->checkedId()==2)
    {
        QSqlQuery query;
        query.prepare("select * from houseowner where ownername=?");
        query.addBindValue(ui->userLine->text());
        query.exec();
        if(query.next())
        {
            if (query.value(1).toString() == ui->passwordLine->text())
            {

                //创建业主登录窗口
                owner=new OwnerManage;
                owner->setWindowTitle(ui->userLine->text());
                owner->show();
                this->hide();
                return;
            }
            else
            {
                QMessageBox::warning(this, tr("账号密码错误"),
                                     tr("请输入正确的账号密码再登录!"), QMessageBox::Ok);
                ui->userLine->clear();
                ui->passwordLine->clear();
                ui->userLine->setFocus();
            }
        }
        else
            QMessageBox::information(this,tr("提示"),tr("没有此账号!"),QMessageBox::Ok);
    }
    else
        QMessageBox::warning(this,"警告","请选择登录方式",QMessageBox::Yes);
}

/************《槽函数》关闭登录窗口**************************/
void LoginDialog::exitbtnSlot()
{
     this->close(); //关闭串口
}

/************清除登录窗口中用户输入的内容************/
void LoginDialog::clearAll()
{
    ui->userLine->clear();      //清除ui中"userLine"对象的数据内容
    ui->passwordLine->clear();  //清除密码
}
/************判断用户输入的内容是否为空**************/
bool LoginDialog::judgeEmpty()
{
    if(ui->userLine->text().isEmpty())  //如果用户名内容为空
    {
        //为登录对话框,创建警告窗口,内容为:"用户名不能为空"
        QMessageBox::warning(this,"警告","用户名不能为空");
        return false;   //返回错误
    }
    if(ui->passwordLine->text().isEmpty())  //密码为空
    {
        QMessageBox::warning(this,"警告","密码不能为空");
        return false;
    }
    else    //如果用户名区域和密码区域都有内容,返回true
        return true;
}

修复版本二

无注释版
cpp 复制代码
#include "logindialog.h"
#include "ui_logindialog.h"

#include <QSqlQuery>
#include <QSqlError>
#include <QMessageBox>
#include <QDebug>

#include "managermanage.h"
#include "workermanage.h"
#include "ownermanage.h"

#include <QSettings>

LoginDialog::LoginDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::LoginDialog)
{
    ui->setupUi(this);

    radioGroup = new QButtonGroup(this);
    radioGroup->addButton(ui->managerRadio, 0);
    radioGroup->addButton(ui->workerRadio, 1);
    radioGroup->addButton(ui->ownerRadio, 2);

    connect(ui->loginBtn, &QPushButton::clicked,
            this, &LoginDialog::loginbtnSlot);
    connect(ui->exitBtn, &QPushButton::clicked,
            this, &LoginDialog::exitbtnSlot);

    ui->managerRadio->setChecked(true);

    ui->passwordLine->setEchoMode(QLineEdit::Password);
    ui->passwordLine->setPlaceholderText("请输入密码");
    ui->userLine->setPlaceholderText("请输入用户名");

    loadSettings();
}

LoginDialog::~LoginDialog()
{
    delete ui;
}

void LoginDialog::loadSettings()
{
    QSettings settings("MyCompany", "IntelligentCommunity");

    QString username = settings.value("username", "").toString();
    QString password = settings.value("password", "").toString();
    bool remember = settings.value("remember", false).toBool();

    if (!username.isEmpty()) {
        ui->userLine->setText(username);
    }

    if (remember) {
        ui->passwordLine->setText(password);
        ui->rememberPwdCheckBox->setChecked(true);
    }

    qDebug() << "加载配置: 用户名=" << username << ", 记住密码=" << remember;
}

void LoginDialog::saveSettings()
{
    QSettings settings("MyCompany", "IntelligentCommunity");

    if (ui->rememberPwdCheckBox->isChecked()) {
        settings.setValue("username", ui->userLine->text().trimmed());
        settings.setValue("password", ui->passwordLine->text().trimmed());
        settings.setValue("remember", true);
        qDebug() << "保存密码到配置";
    } else {
        settings.remove("username");
        settings.remove("password");
        settings.setValue("remember", false);
        qDebug() << "清除保存的密码";
    }
}

void LoginDialog::loginbtnSlot()
{
    if (!judgeEmpty()) {
        ui->passwordLine->clear();
        ui->passwordLine->setFocus();
        return;
    }

    QString username = ui->userLine->text().trimmed();
    QString password = ui->passwordLine->text().trimmed();

    int roleId = radioGroup->checkedId();

    qDebug() << "当前选中角色 ID:" << roleId;

    switch (roleId) {
    case 0:
        loginAsAdmin(username, password);
        break;
    case 1:
        loginAsWorker(username, password);
        break;
    case 2:
        loginAsOwner(username, password);
        break;
    default:
        QMessageBox::warning(this, "警告", "请选择登录身份!", QMessageBox::Ok);
        break;
    }
}

void LoginDialog::loginAsAdmin(const QString &username, const QString &password)
{
    QSqlQuery query;
    query.prepare("SELECT * FROM worker WHERE workernum = ?");
    query.addBindValue(username);

    if (!query.exec()) {
        qDebug() << "SQL 查询失败:" << query.lastError().text();
        QMessageBox::critical(this, "错误", "数据库查询失败!");
        return;
    }

    if (!query.next()) {
        QMessageBox::information(this, "提示", "没有此账号!", QMessageBox::Ok);
        return;
    }

    if (query.value(1).toString() != password) {
        QMessageBox::warning(this, "账号密码错误",
                            "请输入正确的账号密码再登录!", QMessageBox::Ok);
        clearInput();
        return;
    }

    if (query.value(3).toString() == "否") {
        QMessageBox::warning(this, "权限不足",
                            "该账号不是管理员,请选择合适权限登录!", QMessageBox::Ok);
        return;
    }

    saveSettings();

    manager = new ManagerManage;
    manager->show();
    this->hide();

    qDebug() << "管理员登录成功:" << username;
}

void LoginDialog::loginAsWorker(const QString &username, const QString &password)
{
    QSqlQuery query;
    query.prepare("SELECT * FROM worker WHERE workernum = ?");
    query.addBindValue(username);

    if (!query.exec()) {
        qDebug() << "SQL 查询失败:" << query.lastError().text();
        QMessageBox::critical(this, "错误", "数据库查询失败!");
        return;
    }

    if (!query.next()) {
        QMessageBox::information(this, "提示", "没有此账号!", QMessageBox::Ok);
        return;
    }

    if (query.value(1).toString() != password) {
        QMessageBox::warning(this, "账号密码错误",
                            "请输入正确的账号密码再登录!", QMessageBox::Ok);
        clearInput();
        return;
    }

    saveSettings();

    worker = new WorkerManage;
    worker->setWindowTitle(username);
    worker->show();
    this->hide();

    qDebug() << "工作人员登录成功:" << username;
}

void LoginDialog::loginAsOwner(const QString &username, const QString &password)
{
    QSqlQuery query;
    query.prepare("SELECT * FROM houseowner WHERE ownername = ?");
    query.addBindValue(username);

    if (!query.exec()) {
        qDebug() << "SQL 查询失败:" << query.lastError().text();
        QMessageBox::critical(this, "错误", "数据库查询失败!");
        return;
    }

    if (!query.next()) {
        QMessageBox::information(this, "提示", "没有此账号!", QMessageBox::Ok);
        return;
    }

    if (query.value(1).toString() != password) {
        QMessageBox::warning(this, "账号密码错误",
                            "请输入正确的账号密码再登录!", QMessageBox::Ok);
        clearInput();
        return;
    }

    saveSettings();

    owner = new OwnerManage;
    owner->setWindowTitle(username);
    owner->show();
    this->hide();

    qDebug() << "业主登录成功:" << username;
}

void LoginDialog::exitbtnSlot()
{
    int ret = QMessageBox::question(this, "确认退出",
                                    "确定要退出程序吗?",
                                    QMessageBox::Yes | QMessageBox::No);
    if (ret == QMessageBox::Yes) {
        this->close();
    }
}

void LoginDialog::clearAll()
{
    ui->userLine->clear();
    ui->passwordLine->clear();
    ui->userLine->setFocus();
}

bool LoginDialog::judgeEmpty()
{
    if (ui->userLine->text().trimmed().isEmpty()) {
        QMessageBox::warning(this, "警告", "用户名不能为空!");
        ui->userLine->setFocus();
        return false;
    }

    if (ui->passwordLine->text().isEmpty()) {
        QMessageBox::warning(this, "警告", "密码不能为空!");
        ui->passwordLine->setFocus();
        return false;
    }

    return true;
}

void LoginDialog::clearInput()
{
    ui->userLine->clear();
    ui->passwordLine->clear();
    ui->userLine->setFocus();
}
有注释版
cpp 复制代码
// ============================================================
// 文件:logindialog.cpp
// 功能:登录对话框实现 - 支持三种角色登录
// 作者:IntelligentCommunity 项目
// 说明:管理员、工作人员、业主三种身份登录验证
// ============================================================
 
// ============================================================
// 头文件包含
// ============================================================
#include "logindialog.h"        // 包含自己的头文件声明
#include "ui_logindialog.h"     // 包含由 .ui 文件生成的 UI 类头文件
 
#include <QSqlQuery>            // SQL 查询类,用于执行 SQL 语句
#include <QSqlError>            // SQL 错误类,用于获取错误信息
#include <QMessageBox>          // 消息框类,用于显示提示/警告/错误对话框
#include <QDebug>               // 调试输出类,用于在控制台打印调试信息

// ============================================================
// ✅ 新增:包含主窗口类的完整定义
// ============================================================
#include "managermanage.h"
#include "workermanage.h"
#include "ownermanage.h"

// ✅ 新增:配置文件读写
#include <QSettings>
 
// ============================================================
// 构造函数 - 初始化界面和按钮组
// 参数:parent - 父窗口指针,默认 nullptr
// ============================================================
LoginDialog::LoginDialog(QWidget *parent) :
    QDialog(parent),            // 调用父类 QDialog 的构造函数,传入父窗口
    ui(new Ui::LoginDialog)     // 创建 UI 对象(由 Qt Designer 生成的界面)
{
    // --------------------------------------------------------
    // 1. 设置 UI 界面
    //    setupUi() 会创建所有控件并设置布局
    //    相当于调用 ui->setupUi(this),把界面加载到当前对话框
    // --------------------------------------------------------
    ui->setupUi(this);
 
    // --------------------------------------------------------
    // 2. 创建按钮组(实现单选互斥)
    //    QButtonGroup 可以将多个单选按钮逻辑分组
    //    同一组内只能选中一个按钮,实现互斥效果
    //    父对象设置为 this,由 Qt 自动管理内存
    // --------------------------------------------------------
    radioGroup = new QButtonGroup(this);
    
    // addButton(按钮指针, ID号)
    // 将"管理员"单选按钮加入组,分配 ID 为 0
    radioGroup->addButton(ui->managerRadio, 0);
    
    // 将"工作人员"单选按钮加入组,分配 ID 为 1
    radioGroup->addButton(ui->workerRadio, 1);
    
    // 将"业主"单选按钮加入组,分配 ID 为 2
    radioGroup->addButton(ui->ownerRadio, 2);
    // 这样通过 checkedId() 就能知道用户选了哪个身份
 
    // --------------------------------------------------------
    // 3. 信号槽连接(Qt 5 新语法)
    //    将按钮的 clicked() 信号连接到对应的槽函数
    //    当按钮被点击时,槽函数会被自动调用
    //    优点:编译期检查,类型安全
    // --------------------------------------------------------
    
    // 登录按钮的 clicked 信号 → 连接到 loginbtnSlot 槽函数
    // 用户点击登录按钮时,执行登录验证逻辑
    connect(ui->loginBtn, &QPushButton::clicked, 
            this, &LoginDialog::loginbtnSlot);
    
    // 退出按钮的 clicked 信号 → 连接到 exitbtnSlot 槽函数
    // 用户点击退出按钮时,关闭程序
    connect(ui->exitBtn, &QPushButton::clicked, 
            this, &LoginDialog::exitbtnSlot);
 
    // 注意:下面这行是 Qt 4 旧语法,已被注释掉
    // 旧语法使用 SIGNAL 和 SLOT 宏,运行时字符串匹配,不安全
    // connect(ui->loginBtn, SIGNAL(clicked()), this, SLOT(loginbtnSlot()));
 
    // --------------------------------------------------------
    // 4. 设置默认选中状态
    //    默认选中"管理员"单选按钮
    //    这样用户打开对话框时,管理员身份已经被选中
    //    提升用户体验,减少操作步骤
    // --------------------------------------------------------
    ui->managerRadio->setChecked(true);
 
    // --------------------------------------------------------
    // 5. 设置密码输入框的掩码
    //    setEchoMode() 设置文本显示模式
    //    Password 模式:输入时显示为 ● 符号
    //    保护密码不被旁边的人看到
    // --------------------------------------------------------
    ui->passwordLine->setEchoMode(QLineEdit::Password);
    
    // 额外优化:设置密码框的提示文本
    ui->passwordLine->setPlaceholderText("请输入密码");
    
    // 额外优化:设置用户框的提示文本
    ui->userLine->setPlaceholderText("请输入用户名");

    // ============================================================
    // ✅ 新增:6. 加载记住的密码
    // ============================================================
    loadSettings();
}
 
// ============================================================
// 析构函数 - 释放 UI 资源
// 当 LoginDialog 对象被销毁时自动调用
// ============================================================
LoginDialog::~LoginDialog()
{
    // 删除 UI 对象,释放界面上所有控件的内存
    // 这是必须的,因为 ui 是在构造函数中用 new 创建的
    delete ui;
    
    // 注意:radioGroup、manager、worker、owner 不需要手动 delete
    // 原因:它们都有父对象 this(在构造函数中设置了 parent)
    // Qt 的对象树机制会在父对象销毁时自动删除所有子对象
    // 这是 Qt 自动内存管理的重要特性,避免了内存泄漏
}

// ============================================================
// ✅ 新增:加载记住的密码
// ============================================================
void LoginDialog::loadSettings()
{
    // QSettings: 跨平台的配置文件管理
    // 参数1:公司名  参数2:应用名
    // Windows 上保存位置:注册表 HKEY_CURRENT_USER/Software/MyCompany/IntelligentCommunity
    // Linux 上保存位置:~/.config/MyCompany/IntelligentCommunity.conf
    QSettings settings("MyCompany", "IntelligentCommunity");

    // 读取保存的用户名和密码
    QString username = settings.value("username", "").toString();
    QString password = settings.value("password", "").toString();
    bool remember = settings.value("remember", false).toBool();

    // 如果有保存的用户名,填入输入框
    if (!username.isEmpty()) {
        ui->userLine->setText(username);
    }

    // 如果勾选了"记住密码",填入密码并勾选复选框
    if (remember) {
        ui->passwordLine->setText(password);
        ui->rememberPwdCheckBox->setChecked(true);
    }

    qDebug() << "加载配置: 用户名=" << username << ", 记住密码=" << remember;
}

// ============================================================
// ✅ 新增:保存密码到配置文件
// ============================================================
void LoginDialog::saveSettings()
{
    QSettings settings("MyCompany", "IntelligentCommunity");

    // 判断是否勾选了"记住密码"
    if (ui->rememberPwdCheckBox->isChecked()) {
        // 保存用户名、密码、记住状态
        settings.setValue("username", ui->userLine->text().trimmed());
        settings.setValue("password", ui->passwordLine->text().trimmed());
        settings.setValue("remember", true);
        qDebug() << "保存密码到配置";
    } else {
        // 清除保存的信息
        settings.remove("username");
        settings.remove("password");
        settings.setValue("remember", false);
        qDebug() << "清除保存的密码";
    }
}
 
// ============================================================
// 登录按钮槽函数 - 核心登录逻辑
// 当用户点击"登录"按钮时,此函数被调用
// ============================================================
void LoginDialog::loginbtnSlot()
{
    // --------------------------------------------------------
    // 1. 输入验证
    //    调用 judgeEmpty() 检查用户名和密码是否为空
    //    如果为空,judgeEmpty() 会弹出警告框并返回 false
    // --------------------------------------------------------
    if (!judgeEmpty()) {
        // 密码为空或用户名为空,清空密码框
        ui->passwordLine->clear();
        // 将焦点设置到密码框,让用户重新输入
        ui->passwordLine->setFocus();
        // 退出函数,不继续执行登录逻辑
        return;
    }
 
    // --------------------------------------------------------
    // 2. 获取用户输入
    //    text() 获取输入框中的文本
    //    trimmed() 去除字符串首尾的空白字符(空格、制表符等)
    // --------------------------------------------------------
    QString username = ui->userLine->text().trimmed();
    QString password = ui->passwordLine->text().trimmed();
 
    // --------------------------------------------------------
    // 3. 获取选中的角色 ID
    //    checkedId() 返回当前选中按钮的 ID
    //    如果没有任何按钮被选中,返回 -1
    // --------------------------------------------------------
    int roleId = radioGroup->checkedId();
    
    // qDebug() 是 Qt 的调试输出工具
    // 在控制台打印信息,方便开发和调试
    // 正式发布时可以关闭
    qDebug() << "当前选中角色 ID:" << roleId;
 
    // --------------------------------------------------------
    // 4. 根据角色执行登录验证
    //    使用 switch 语句根据不同的角色 ID 执行不同的登录逻辑
    // --------------------------------------------------------
    switch (roleId) {
    case 0:  // ========== 管理员登录 ==========
        // 调用管理员登录函数,传入用户名和密码
        loginAsAdmin(username, password);
        break;  // 跳出 switch
        
    case 1:  // ========== 工作人员登录 ==========
        // 调用工作人员登录函数
        loginAsWorker(username, password);
        break;
        
    case 2:  // ========== 业主登录 ==========
        // 调用业主登录函数
        loginAsOwner(username, password);
        break;
        
    default:  // ========== 未选择任何角色 ==========
        // roleId 为 -1 或其他值,说明用户没有选择身份
        // 弹出警告框提示用户
        QMessageBox::warning(this, "警告", "请选择登录身份!", QMessageBox::Ok);
        break;
    }
}
 
// ============================================================
// 管理员登录逻辑
// 参数:username - 用户名,password - 密码
// ============================================================
void LoginDialog::loginAsAdmin(const QString &username, const QString &password)
{
    // --------------------------------------------------------
    // 1. 创建 SQL 查询对象
    //    QSqlQuery 用于执行 SQL 语句和获取结果
    // --------------------------------------------------------
    QSqlQuery query;
    
    // --------------------------------------------------------
    // 2. 准备 SQL 查询语句
    //    prepare() 预编译 SQL 语句,提高性能和安全性
    //    ? 是占位符,后续用 addBindValue() 绑定值
    //    使用参数绑定可以有效防止 SQL 注入攻击
    // --------------------------------------------------------
    query.prepare("SELECT * FROM worker WHERE workernum = ?");
    
    // --------------------------------------------------------
    // 3. 绑定查询参数
    //    addBindValue() 将用户名绑定到 ? 占位符
    //    这样即使用户名包含特殊字符,也不会被当作 SQL 执行
    // --------------------------------------------------------
    query.addBindValue(username);
 
    // --------------------------------------------------------
    // 4. 执行 SQL 查询
    //    exec() 执行准备好的 SQL 语句
    //    如果执行失败,返回 false
    // --------------------------------------------------------
    if (!query.exec()) {
        // 查询失败,打印错误信息到控制台
        qDebug() << "SQL 查询失败:" << query.lastError().text();
        // 弹出错误对话框
        QMessageBox::critical(this, "错误", "数据库查询失败!");
        return;  // 退出函数
    }
 
    // --------------------------------------------------------
    // 5. 检查查询结果
    //    next() 移动到结果集的下一行
    //    第一次调用时移动到第一行
    //    如果没有数据,返回 false
    // --------------------------------------------------------
    if (!query.next()) {
        // 没有找到该用户名的记录
        QMessageBox::information(this, "提示", "没有此账号!", QMessageBox::Ok);
        return;  // 退出函数
    }

     /*********worker表结构**********************************
             *  数据库中worker表共有4字段(列),从左向右依此表示为
             *  workernum   workerpass   workerphone   workertype
             *   用户名        密码          电话       是/否管理员
             *******************************************************/
    // --------------------------------------------------------
    // 6. 验证密码
    //    query.value(列索引) 获取当前行的指定列数据
    //    value(0) 是 workernum (用户名)
    //    value(1) 是 workerpass (密码)
    //    value(2) 是 workerphone (电话)
    //    value(3) 是 workertype (是否管理员:"是"/"否")
    //    将数据库中存储的密码与用户输入的密码进行比较
    // --------------------------------------------------------
    if (query.value(1).toString() != password) {
        // 密码不匹配
        QMessageBox::warning(this, "账号密码错误", 
                            "请输入正确的账号密码再登录!", QMessageBox::Ok);
        // 清空输入框,让用户重新输入
        // clearInput() 是私有辅助函数,清空用户名和密码框
        clearInput();
        return;  // 退出函数
    }
 
    // --------------------------------------------------------
    // 7. 检查是否为管理员
    //    value(3) 是 workertype 字段
    //    值为"是"表示管理员,"否"表示普通工作人员
    // --------------------------------------------------------
    if (query.value(3).toString() == "否") {
        // 账号和密码正确,但不是管理员
        QMessageBox::warning(this, "权限不足", 
                            "该账号不是管理员,请选择合适权限登录!", QMessageBox::Ok);
        return;  // 退出函数
    }
 
    // --------------------------------------------------------
    // 8. ✅ 登录成功
    //    创建管理员主界面对象
    //    ManagerManage 是管理员的主窗口类
    // --------------------------------------------------------

    // ✅ 新增:登录成功:保存密码到配置文件
    saveSettings();

    manager = new ManagerManage;
    
    // 显示管理员主窗口
    manager->show();
    
    // 隐藏当前登录对话框
    // 注意:不是关闭,是隐藏,这样登录对话框还在内存中
    // 当主窗口关闭时,可以重新显示登录对话框
    this->hide();
    
    // 在控制台打印登录成功信息
    qDebug() << "管理员登录成功:" << username;
}
 
// ============================================================
// 工作人员登录逻辑
// 参数:username - 用户名,password - 密码
// ============================================================
void LoginDialog::loginAsWorker(const QString &username, const QString &password)
{
    // --------------------------------------------------------
    // 1. 创建 SQL 查询对象并准备查询
    //    从 worker 表中查询匹配 workernum 的记录
    //    使用 ? 占位符防止 SQL 注入
    // --------------------------------------------------------
    QSqlQuery query;
    query.prepare("SELECT * FROM worker WHERE workernum = ?");
    query.addBindValue(username);
 
    // --------------------------------------------------------
    // 2. 执行查询并检查错误
    // --------------------------------------------------------
    if (!query.exec()) {
        qDebug() << "SQL 查询失败:" << query.lastError().text();
        QMessageBox::critical(this, "错误", "数据库查询失败!");
        return;
    }
 
    // --------------------------------------------------------
    // 3. 检查用户是否存在
    // --------------------------------------------------------
    if (!query.next()) {
        QMessageBox::information(this, "提示", "没有此账号!", QMessageBox::Ok);
        return;
    }
 
    // --------------------------------------------------------
    // 4. 验证密码
    //    value(1) 是密码字段
    // --------------------------------------------------------
    if (query.value(1).toString() != password) {
        QMessageBox::warning(this, "账号密码错误", 
                            "请输入正确的账号密码再登录!", QMessageBox::Ok);
        clearInput();  // 清空输入框
        return;
    }
 
    // --------------------------------------------------------
    // 5. ✅ 登录成功
    //    创建工作人员主界面
    //    setWindowTitle() 设置窗口标题为当前用户名
    //    这样工作人员可以在标题栏看到自己的名字
    // --------------------------------------------------------

    // ✅ 新增:登录成功:保存密码到配置文件
    saveSettings();

    worker = new WorkerManage;
    worker->setWindowTitle(username);  // 将用户名设为窗口标题
    worker->show();      // 显示工作人员主窗口
    this->hide();        // 隐藏登录对话框
    
    qDebug() << "工作人员登录成功:" << username;
}
 
// ============================================================
// 业主登录逻辑
// 参数:username - 用户名,password - 密码
// ============================================================
void LoginDialog::loginAsOwner(const QString &username, const QString &password)
{
    // --------------------------------------------------------
    // 1. 创建 SQL 查询对象
    //    从 houseowner 表中查询匹配 ownername 的记录
    //    houseowner 是业主信息表
    // --------------------------------------------------------
    QSqlQuery query;
    query.prepare("SELECT * FROM houseowner WHERE ownername = ?");
    query.addBindValue(username);
 
    // --------------------------------------------------------
    // 2. 执行查询并检查错误
    // --------------------------------------------------------
    if (!query.exec()) {
        qDebug() << "SQL 查询失败:" << query.lastError().text();
        QMessageBox::critical(this, "错误", "数据库查询失败!");
        return;
    }
 
    // --------------------------------------------------------
    // 3. 检查用户是否存在
    // --------------------------------------------------------
    if (!query.next()) {
        QMessageBox::information(this, "提示", "没有此账号!", QMessageBox::Ok);
        return;
    }
 
    // --------------------------------------------------------
    // 4. 验证密码
    //    假设 houseowner 表结构:
    //    value(0): ownername (业主姓名)
    //    value(1): password (密码)
    //    value(2): phone (电话)
    //    value(3): house_id (房屋编号)
    //    这里用 value(1) 获取密码进行比较
    // --------------------------------------------------------
    if (query.value(1).toString() != password) {
        QMessageBox::warning(this, "账号密码错误", 
                            "请输入正确的账号密码再登录!", QMessageBox::Ok);
        clearInput();
        return;
    }
 
    // --------------------------------------------------------
    // 5. ✅ 登录成功
    //    创建业主主界面
    // --------------------------------------------------------

    // ✅ 新增:登录成功:保存密码到配置文件
    saveSettings();

    owner = new OwnerManage;
    owner->setWindowTitle(username);  // 窗口标题显示用户名
    owner->show();      // 显示业主主窗口
    this->hide();       // 隐藏登录对话框
    
    qDebug() << "业主登录成功:" << username;
}
 
// ============================================================
// 退出按钮槽函数
// 当用户点击"退出"按钮时调用
// ============================================================
void LoginDialog::exitbtnSlot()
{
    // --------------------------------------------------------
    // 显示确认退出对话框
    // question() 是 QMessageBox 的静态方法,用于显示询问对话框
    // 参数说明:
    //   this: 父窗口
    //   "确认退出": 对话框标题
    //   "确定要退出程序吗?": 对话框内容
    //   QMessageBox::Yes | QMessageBox::No: 显示"是"和"否"两个按钮
    // 返回值:用户点击的按钮(Yes 或 No)
    // --------------------------------------------------------
    int ret = QMessageBox::question(this, "确认退出", 
                                    "确定要退出程序吗?",
                                    QMessageBox::Yes | QMessageBox::No);
    
    // --------------------------------------------------------
    // 判断用户的选择
    // 如果用户点击了"是"(Yes),则关闭对话框
    // 如果用户点击了"否"(No),什么也不做
    // --------------------------------------------------------
    if (ret == QMessageBox::Yes) {
        // close() 关闭当前对话框
        // 由于这是主窗口,关闭对话框会导致程序退出
        this->close();
    }
}
 
// ============================================================
// 清空所有输入框
// 公共函数,外部可以调用
// ============================================================
void LoginDialog::clearAll()
{
    // 清空用户名输入框
    ui->userLine->clear();
    
    // 清空密码输入框
    ui->passwordLine->clear();
    
    // 将焦点设置到用户名输入框
    // 方便用户直接输入
    ui->userLine->setFocus();
}
 
// ============================================================
// 判断输入是否为空
// 返回值:true - 用户名和密码都不为空
//         false - 用户名或密码为空
// ============================================================
bool LoginDialog::judgeEmpty()
{
    // --------------------------------------------------------
    // 1. 检查用户名是否为空
    //    trimmed() 去除首尾空格后再判断
    //    如果用户只输入了空格,也被视为空
    // --------------------------------------------------------
    if (ui->userLine->text().trimmed().isEmpty()) {
        // 用户名空,弹出警告框
        QMessageBox::warning(this, "警告", "用户名不能为空!");
        // 将焦点设置到用户名输入框,让用户输入
        ui->userLine->setFocus();
        return false;  // 返回 false 表示验证失败
    }
    
    // --------------------------------------------------------
    // 2. 检查密码是否为空
    //    注意:密码不 trim(),因为密码可能包含空格
    //    但实际项目中密码通常不允许空格
    // --------------------------------------------------------
    if (ui->passwordLine->text().isEmpty()) {
        // 密码为空,弹出警告框
        QMessageBox::warning(this, "警告", "密码不能为空!");
        // 将焦点设置到密码输入框
        ui->passwordLine->setFocus();
        return false;  // 返回 false 表示验证失败
    }
    
    // --------------------------------------------------------
    // 3. 用户名和密码都不为空
    //    返回 true 表示验证通过
    // --------------------------------------------------------
    return true;
}
 
// ============================================================
// 私有辅助函数:清空输入并聚焦
// 在密码错误时调用,让用户重新输入
// ============================================================
void LoginDialog::clearInput()
{
    // 清空用户名输入框
    ui->userLine->clear();
    
    // 清空密码输入框
    ui->passwordLine->clear();
    
    // 将焦点设置到用户名输入框
    // 用户可以直接重新输入,不需要用鼠标点击
    ui->userLine->setFocus();
}

1.logindialog.ui

原始版

修复版

业主管理模块

2.ownermanage.h

原始版本一

cpp 复制代码
#ifndef OWNERMANAGE_H
#define OWNERMANAGE_H

#include <QMainWindow>
#include <QTableView>
#include <QSqlTableModel>
#include <QSqlQuery>
#include <QSqlQueryModel>

#include "issueinfo.h"
#include "applycarstation.h"
#include "ownerpayself.h"
#include "issueassessment.h"

namespace Ui {
class OwnerManage;
}
//业主管理类,共有继承QMainWindow
//使用UI设计师设计界面
class OwnerManage : public QMainWindow
{
    Q_OBJECT

public:
    explicit OwnerManage(QWidget *parent = 0);
    ~OwnerManage();

private:
    Ui::OwnerManage *ui;
    //表预览
    QTableView *ownerTableView;     //创建表格预览对象指针
    QSqlQueryModel *ownerQueryModel;//创建SQL查询模型对象指针
    QSqlTableModel *ownerModel;     //创建SQL表格模型对象指针
    ApplyCarStation *applyCarStation;   //创建车位申请窗口对象指针
    ownerPaySelf *pPay;                 //创建自助缴费窗口对象指针
    IssueInfo *issue;                   //创建故障报修窗口对象指针
    issueAssessment *p;                 //创建用户评价窗口对象指针
    int ownerState;                     //业主是否查看维修进度,是=2

signals:
    //void EmitToManagerManage();
    void EmitOwnerChanged();

private slots:

    void on_applyCarStationAct_triggered(); //"车位申请"按钮槽函数
    void on_showcCarStationAct_triggered(); //"车位查看"按键槽函数
    void on_payShowAct_triggered();         //"缴费查询"按键槽函数
    void on_payAct_triggered();             //"自助缴费"按键槽函数
    void on_issueReportAct_triggered();     //"故障保修"按键槽函数
    void on_issueProcessAct_triggered();    //"故障进度"按键槽函数
    void on_issueEvaluateAct_triggered();   //"维修评价"按键槽函数

};

#endif // OWNERMANAGE_H

修复版本二

无注释版
cpp 复制代码
#ifndef OWNERMANAGE_H
#define OWNERMANAGE_H

#include <QMainWindow>
#include <QTableView>
#include <QSqlTableModel>
#include <QSqlQuery>
#include <QSqlQueryModel>

#include "issueinfo.h"
#include "applycarstation.h"
#include "ownerpayself.h"
#include "issueassessment.h"

namespace Ui {
class OwnerManage;
}

class OwnerManage : public QMainWindow
{
    Q_OBJECT

public:
    explicit OwnerManage(QWidget *parent = 0);
    ~OwnerManage();

private:
    Ui::OwnerManage *ui;

    QTableView *ownerTableView;
    QSqlQueryModel *ownerQueryModel;
    QSqlTableModel *ownerModel;

    ApplyCarStation *applyCarStation;
    ownerPaySelf *pPay;
    IssueInfo *issue;
    issueAssessment *p;

    int ownerState;

signals:
    void EmitOwnerChanged();

private slots:
    void on_applyCarStationAct_triggered();
    void on_showcCarStationAct_triggered();
    void on_payShowAct_triggered();
    void on_payAct_triggered();
    void on_issueReportAct_triggered();
    void on_issueProcessAct_triggered();
    void on_issueEvaluateAct_triggered();
};

#endif // OWNERMANAGE_H
有注释版
cpp 复制代码
// ============================================================
// 文件:ownermanage.h
// 功能:业主管理界面的头文件声明
// 说明:业主登录后的主界面,包含车位申请、缴费、报修等功能
// ============================================================

#ifndef OWNERMANAGE_H
// 作用:防止头文件被多次包含(Include Guard)
// 如果 OWNERMANAGE_H 未定义,则定义它并包含头文件内容
// 如果已定义,则跳过整个头文件内容

#define OWNERMANAGE_H
// 定义宏 OWNERMANAGE_H,标记这个头文件已经被包含

// ============================================================
// 头文件包含
// ============================================================

#include <QMainWindow>
// 包含 QMainWindow 基类
// QMainWindow 是 Qt 中主窗口的基类,提供菜单栏、工具栏、状态栏等
// 业主管理界面是一个主窗口,所以继承 QMainWindow

#include <QTableView>
// 包含 QTableView 类
// QTableView 是表格视图,用于以表格形式显示数据
// 本类中用于显示业主信息列表

#include <QSqlTableModel>
// 包含 QSqlTableModel 类
// QSqlTableModel 是可读写的数据库表模型
// 用于在表格中显示和编辑数据库表中的数据

#include <QSqlQuery>
// 包含 QSqlQuery 类
// 用于执行 SQL 查询语句

#include <QSqlQueryModel>
// 包含 QSqlQueryModel 类
// QSqlQueryModel 是只读的 SQL 查询模型
// 用于执行自定义 SQL 查询并显示结果

// ============================================================
// 包含其他功能模块的头文件
// ============================================================

#include "issueinfo.h"
// 包含报修信息模块
// issueinfo.h 定义了 IssueInfo 类
// 用于故障报修功能

#include "applycarstation.h"
// 包含车位申请模块
// applycarstation.h 定义了 ApplyCarStation 类
// 用于车位申请功能

#include "ownerpayself.h"
// 包含业主自助缴费模块
// ownerpayself.h 定义了 ownerPaySelf 类
// 用于业主自助缴费功能

#include "issueassessment.h"
// 包含报修评估模块
// issueassessment.h 定义了 issueAssessment 类
// 用于维修评价功能

// ============================================================
// UI 命名空间声明
// ============================================================

namespace Ui {
class OwnerManage;
// 声明 UI 类
// 这个类由 Qt 的 uic 工具根据 ownermanage.ui 文件自动生成
// 包含了界面上所有控件的指针
}

// ============================================================
// OwnerManage 类定义
// 业主管理主窗口,继承自 QMainWindow
// ============================================================

class OwnerManage : public QMainWindow
// class OwnerManage : 定义一个名为 OwnerManage 的类
// public QMainWindow : 公有继承自 QMainWindow 基类
// QMainWindow 提供主窗口的完整功能:菜单栏、工具栏、状态栏、中央部件

{
    Q_OBJECT
    // Qt 元对象宏
    // 启用信号槽机制、运行时类型信息等 Qt 元对象功能
    // 因为类中使用了 signals 和 private slots,必须包含此宏

public:
    // ============================================================
    // public 区域:对外公开的接口
    // ============================================================

    explicit OwnerManage(QWidget *parent = 0);
    // 构造函数
    // explicit: 防止隐式类型转换
    // QWidget *parent = 0: 父窗口指针,默认值为 nullptr

    ~OwnerManage();
    // 析构函数
    // 当对象被销毁时自动调用,释放资源

private:
    // ============================================================
    // private 区域:私有的成员变量和函数
    // 只能在类内部访问,外部不可见
    // ============================================================

    Ui::OwnerManage *ui;
    // UI 对象指针
    // 指向由 uic 工具生成的 UI 类对象
    // 通过这个指针可以访问界面上所有的控件

    // ============================================================
    // 表格相关成员变量
    // ============================================================

    QTableView *ownerTableView;
    // 表格视图对象指针
    // 用于在界面上以表格形式显示业主数据
    // 通过 setModel() 绑定数据模型

    QSqlQueryModel *ownerQueryModel;
    // SQL 查询模型对象指针(只读)
    // 用于执行自定义 SQL 查询
    // 适用于不需要编辑数据的场景

    QSqlTableModel *ownerModel;
    // SQL 表格模型对象指针(可读写)
    // 用于与数据库表直接绑定
    // 支持增删改查操作

    // ============================================================
    // 功能模块窗口指针
    // ============================================================

    ApplyCarStation *applyCarStation;
    // 车位申请窗口对象指针
    // 当用户点击"车位申请"时,创建并显示此窗口

    ownerPaySelf *pPay;
    // 自助缴费窗口对象指针
    // 当用户点击"自助缴费"时,创建并显示此窗口

    IssueInfo *issue;
    // 故障报修窗口对象指针
    // 当用户点击"故障报修"时,创建并显示此窗口

    issueAssessment *p;
    // 用户评价窗口对象指针
    // 当用户点击"维修评价"时,创建并显示此窗口

    int ownerState;
    // 业主状态标记
    // 用于记录业主是否正在查看维修进度
    // 值 2 表示正在查看维修进度

signals:
    // ============================================================
    // 信号区域
    // ============================================================

    //void EmitToManagerManage();
    // 已注释掉的信号
    // 推测:用于向管理员管理界面发送信号
    // 但目前未被使用

    void EmitOwnerChanged();
    // 业主信息变更信号
    // 当业主信息发生变化时发射此信号
    // 用于通知其他模块更新数据

private slots:
    // ============================================================
    // 私有槽函数区域
    // 响应菜单/按钮的点击事件
    // ============================================================

    void on_applyCarStationAct_triggered();
    // "车位申请"菜单/按钮的槽函数
    // 当用户点击"车位申请"时被调用
    // 功能:创建并显示 ApplyCarStation 窗口

    void on_showcCarStationAct_triggered();
    // "车位查看"菜单/按钮的槽函数
    // 当用户点击"车位查看"时被调用
    // 功能:显示当前业主的车位信息

    void on_payShowAct_triggered();
    // "缴费查询"菜单/按钮的槽函数
    // 当用户点击"缴费查询"时被调用
    // 功能:显示业主的缴费记录

    void on_payAct_triggered();
    // "自助缴费"菜单/按钮的槽函数
    // 当用户点击"自助缴费"时被调用
    // 功能:创建并显示 ownerPaySelf 缴费窗口

    void on_issueReportAct_triggered();
    // "故障报修"菜单/按钮的槽函数
    // 当用户点击"故障报修"时被调用
    // 功能:创建并显示 IssueInfo 报修窗口

    void on_issueProcessAct_triggered();
    // "故障进度"菜单/按钮的槽函数
    // 当用户点击"故障进度"时被调用
    // 功能:查看当前报修的处理进度

    void on_issueEvaluateAct_triggered();
    // "维修评价"菜单/按钮的槽函数
    // 当用户点击"维修评价"时被调用
    // 功能:创建并显示 issueAssessment 评价窗口
};

#endif // OWNERMANAGE_H
// 结束条件编译块

2.ownermanage.cpp

原始版本一

cpp 复制代码
#include "ownermanage.h"
#include "ui_ownermanage.h"
#include "ownerpayself.h"
#include "issueassessment.h"

/********业主管理类OwnerManage构造函数************************************************/
OwnerManage::OwnerManage(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::OwnerManage)
{
    ui->setupUi(this);
    ui->toolBar->setIconSize(QSize(50,50)); //设置工具栏图标大小
    ownerTableView=new QTableView;          //创建一个文本编辑器
    //textEdit=new QPlainTextEdit;    
    setCentralWidget(ownerTableView);       //设置文本编辑器为中心部件

    //问题?业主窗口,有没有必要显示业主的详细信息,单独建一个表.............................?
    ownerModel=new QSqlTableModel(this);    //创建SQL表格模型
    ownerQueryModel = new QSqlQueryModel;   //创建SQL查询模型
    ownerModel->setTable("owner");          //设置连接数据表"owner"
    ownerModel->setEditStrategy(QSqlTableModel::OnManualSubmit);    //设置编辑模式
    ownerModel->removeColumns(5,5);/*?*/
}
/********业主管理类OwnerManage析构函数************************************************/
OwnerManage::~OwnerManage()
{
    delete ui;
}
/********《槽函数》"车位申请"按键执行函数*******************************************/
void OwnerManage::on_applyCarStationAct_triggered()
{
    applyCarStation=new ApplyCarStation;    //创建车位申请窗口对象
    applyCarStation->show();                //显示对象
}
/********《槽函数》"车位查看"按键执行函数*******************************************/
void OwnerManage::on_showcCarStationAct_triggered()
{
    ownerModel->setTable("carstation");     //设置连接数据表"carstation"
    //获取当前业主名
    QString strFilter = QString("ownername = '%1'").arg(this->windowTitle().trimmed());
    qDebug() << "strFilter:" << strFilter;  //输出业主名信息
    ownerModel->setFilter(strFilter);       //设置过滤器
    ownerModel->select();                   //数据库查询
    ownerModel->setHeaderData(0,Qt::Horizontal,tr("车位号"));  //设置字段名,0为最左边位置
    ownerModel->setHeaderData(1,Qt::Horizontal,tr("地上/地下"));
    ownerModel->setHeaderData(2,Qt::Horizontal,tr("大/小"));
    ownerModel->setHeaderData(3,Qt::Horizontal,tr("能否充电"));
    ownerModel->setHeaderData(4,Qt::Horizontal,tr("所属业主"));
    ownerModel->setHeaderData(5,Qt::Horizontal,tr("缴费状态"));
    ownerTableView->setModel(ownerModel);
}
/********《槽函数》"缴费查询"按键执行函数*******************************************/
void OwnerManage::on_payShowAct_triggered()
{
    ownerModel->setTable("priceRecord");
    QString strFilter = QString("ownername = '%1'").arg(this->windowTitle().trimmed());
    ownerModel->setFilter(strFilter);
    ownerModel->select();

    ownerModel->setHeaderData(0,Qt::Horizontal,tr("缴费人"));
    ownerModel->setHeaderData(1,Qt::Horizontal,tr("缴费类型"));
    ownerModel->setHeaderData(2,Qt::Horizontal,tr("缴费金额"));
    ownerModel->setHeaderData(3,Qt::Horizontal,tr("缴费时间"));
    ownerTableView->setModel(ownerModel);
}
/********《槽函数》"自助缴费"按键执行函数*******************************************/
void OwnerManage::on_payAct_triggered()
{
    pPay = new ownerPaySelf();              //创建自助缴费窗口对象
    QString strOwner = this->windowTitle(); //获取业主名
    pPay->setWindowTitle(strOwner);         //设置窗口标题为业主名
    pPay->show();       //窗口显示
}
/********《槽函数》"故障报修"按键执行函数*******************************************/
void OwnerManage::on_issueReportAct_triggered()
{
    issue=new IssueInfo;                                //创建故障报修窗口对象
    issue->setUserName(this->windowTitle().trimmed());  //设置业主名为当前登录名
    issue->show();      //窗口显示
}
/********《槽函数》"维修进度"按键执行函数*******************************************/
void OwnerManage::on_issueProcessAct_triggered()
{
    ownerState = 2; //标识2,标识业主已查看维修进度
    QString strSql = QString("owner = '%1'").arg(this->windowTitle().trimmed());
    ownerModel->setTable("errorinfo");                          //设置连接数据表"errorinfo"
    ownerModel->setFilter(strSql);                              //设置过滤器
    ownerModel->select();                                       //数据查询
    ownerModel->setHeaderData(0,Qt::Horizontal,tr("序号"));     //设置字段,0为最左边
    ownerModel->setHeaderData(1,Qt::Horizontal,tr("申请人"));
    ownerModel->setHeaderData(2,Qt::Horizontal,tr("故障描述"));
    ownerModel->setHeaderData(3,Qt::Horizontal,tr("申请时间"));
    ownerModel->setHeaderData(4,Qt::Horizontal,tr("维修进度"));
    ownerModel->setHeaderData(4,Qt::Horizontal,tr("维修评价"));
    ownerTableView->setEditTriggers(QAbstractItemView::NoEditTriggers);//设置编辑模式
    ownerTableView->setModel(ownerModel);                               //显示数据表
}
/********《槽函数》"维修评价"按键执行函数*******************************************/
void OwnerManage::on_issueEvaluateAct_triggered()
{
    if(2 ==  ownerState)                                //业主已查看维修进度
    {
        int n = ownerTableView->currentIndex().row();   //获取当前指向的行索引
        //获取当前行errornum字段数据
        QString strInfo = ownerModel->record(n).value("errornum").toString();
        p = new issueAssessment(this);  //创建用户评价对象
        p->setMessageIndex(strInfo);    //传递行索引
        p->exec();                      //设置窗口为模态对话框

    }
    ownerModel->select();   //数据查询
}

修复版本二

无注释版
cpp 复制代码
#include "ownermanage.h"
#include "ui_ownermanage.h"
#include "ownerpayself.h"
#include "issueassessment.h"

OwnerManage::OwnerManage(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::OwnerManage)
{
    ui->setupUi(this);
    ui->toolBar->setIconSize(QSize(50,50));
    ownerTableView = new QTableView;
    setCentralWidget(ownerTableView);

    ownerModel = new QSqlTableModel(this);
    ownerQueryModel = new QSqlQueryModel;
    ownerModel->setTable("owner");
    ownerModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
    ownerModel->removeColumns(5,5);
}

OwnerManage::~OwnerManage()
{
    delete ui;
}

void OwnerManage::on_applyCarStationAct_triggered()
{
    applyCarStation = new ApplyCarStation;
    applyCarStation->show();
}

void OwnerManage::on_showcCarStationAct_triggered()
{
    ownerModel->setTable("carstation");
    QString strFilter = QString("ownername = '%1'").arg(this->windowTitle().trimmed());
    qDebug() << "strFilter:" << strFilter;
    ownerModel->setFilter(strFilter);
    ownerModel->select();
    ownerModel->setHeaderData(0, Qt::Horizontal, tr("车位号"));
    ownerModel->setHeaderData(1, Qt::Horizontal, tr("地上/地下"));
    ownerModel->setHeaderData(2, Qt::Horizontal, tr("大/小"));
    ownerModel->setHeaderData(3, Qt::Horizontal, tr("能否充电"));
    ownerModel->setHeaderData(4, Qt::Horizontal, tr("所属业主"));
    ownerModel->setHeaderData(5, Qt::Horizontal, tr("缴费状态"));
    ownerTableView->setModel(ownerModel);
}

void OwnerManage::on_payShowAct_triggered()
{
    ownerModel->setTable("priceRecord");
    QString strFilter = QString("ownername = '%1'").arg(this->windowTitle().trimmed());
    ownerModel->setFilter(strFilter);
    ownerModel->select();
    ownerModel->setHeaderData(0, Qt::Horizontal, tr("缴费人"));
    ownerModel->setHeaderData(1, Qt::Horizontal, tr("缴费类型"));
    ownerModel->setHeaderData(2, Qt::Horizontal, tr("缴费金额"));
    ownerModel->setHeaderData(3, Qt::Horizontal, tr("缴费时间"));
    ownerTableView->setModel(ownerModel);
}

void OwnerManage::on_payAct_triggered()
{
    pPay = new ownerPaySelf();
    QString strOwner = this->windowTitle();
    pPay->setWindowTitle(strOwner);
    pPay->show();
}

void OwnerManage::on_issueReportAct_triggered()
{
    issue = new IssueInfo;
    issue->setUserName(this->windowTitle().trimmed());
    issue->show();
}

void OwnerManage::on_issueProcessAct_triggered()
{
    ownerState = 2;
    QString strSql = QString("owner = '%1'").arg(this->windowTitle().trimmed());
    ownerModel->setTable("errorinfo");
    ownerModel->setFilter(strSql);
    ownerModel->select();
    ownerModel->setHeaderData(0, Qt::Horizontal, tr("序号"));
    ownerModel->setHeaderData(1, Qt::Horizontal, tr("申请人"));
    ownerModel->setHeaderData(2, Qt::Horizontal, tr("故障描述"));
    ownerModel->setHeaderData(3, Qt::Horizontal, tr("申请时间"));
    ownerModel->setHeaderData(4, Qt::Horizontal, tr("维修进度"));
    ownerModel->setHeaderData(4, Qt::Horizontal, tr("维修评价"));
    ownerTableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ownerTableView->setModel(ownerModel);
}

void OwnerManage::on_issueEvaluateAct_triggered()
{
    if (2 == ownerState) {
        int n = ownerTableView->currentIndex().row();
        QString strInfo = ownerModel->record(n).value("errornum").toString();
        p = new issueAssessment(this);
        p->setMessageIndex(strInfo);
        p->exec();
    }
    ownerModel->select();
}
有注释版
cpp 复制代码
// ============================================================
// 文件:ownermanage.cpp
// 功能:业主管理界面的实现
// 说明:业主登录后的主界面,包含车位、缴费、报修等功能
// ============================================================

#include "ownermanage.h"
// 包含自己的头文件声明
// 让编译器知道类 OwnerManage 的结构、成员函数和成员变量

#include "ui_ownermanage.h"
// 包含由 .ui 文件生成的 UI 类头文件
// 包含了 Ui::OwnerManage 类的定义,其中有所有控件的指针

#include "ownerpayself.h"
// 包含自助缴费模块的头文件
// 用于创建 ownerPaySelf 缴费窗口对象

#include "issueassessment.h"
// 包含报修评估模块的头文件
// 用于创建 issueAssessment 评价窗口对象

// ============================================================
// 构造函数 - 初始化业主管理界面
// 参数:parent - 父窗口指针,默认 nullptr
// 当业主登录成功后,此构造函数被调用
// ============================================================

OwnerManage::OwnerManage(QWidget *parent) :
    QMainWindow(parent),
    // 调用父类 QMainWindow 的构造函数,传入父窗口指针
    // QMainWindow 提供菜单栏、工具栏、状态栏等主窗口功能

    ui(new Ui::OwnerManage)
    // 创建 UI 对象(由 Qt Designer 生成的界面类)
    // 使用 new 在堆上分配内存,必须在析构函数中用 delete 释放
{
    ui->setupUi(this);
    // setupUi() 加载 .ui 文件,创建所有控件并设置布局
    // 相当于把 UI 设计师设计的界面加载到当前窗口

    ui->toolBar->setIconSize(QSize(50,50));
    // 设置工具栏中图标的大小为 50x50 像素
    // QSize(50,50) 表示宽度和高度都是 50 像素
    // 让工具栏图标更大,方便触摸操作

    ownerTableView = new QTableView;
    // 创建 QTableView 对象(表格视图)
    // 用于以表格形式显示各种数据(车位、缴费、报修等)
    // 在堆上分配内存,由 Qt 对象树管理

    //textEdit=new QPlainTextEdit;    // 已注释:原本可能用文本编辑器

    setCentralWidget(ownerTableView);
    // setCentralWidget() 设置窗口的中央部件
    // QMainWindow 有中央区域,只能有一个中央部件
    // 这里将表格视图设置为中央部件,占据窗口主要区域
    // 所有数据显示在这个表格中

    //问题?业主窗口,有没有必要显示业主的详细信息,单独建一个表.............................?
    // 这是开发者的注释:考虑是否需要单独显示业主信息

    ownerModel = new QSqlTableModel(this);
    // 创建 SQL 表格模型(可读写)
    // 参数 this 表示父对象是当前窗口,由 Qt 自动管理内存
    // 用于与数据库表绑定,支持增删改查操作

    ownerQueryModel = new QSqlQueryModel;
    // 创建 SQL 查询模型(只读)
    // 用于执行自定义 SQL 查询
    // ⚠️ 问题:从未被使用,是死代码

    ownerModel->setTable("owner");
    // setTable() 设置要操作的数据库表名
    // 初始绑定到 "owner" 表
    // 后续会根据用户点击动态切换到其他表

    ownerModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
    // setEditStrategy() 设置编辑策略
    // OnManualSubmit: 手动提交模式
    // 修改后需要调用 submitAll() 才会保存到数据库
    // 优点:可以批量修改,确认后再提交
    // 缺点:需要手动调用 submitAll()

    ownerModel->removeColumns(5,5);
    // removeColumns(列索引, 列数)
    // 从第 5 列开始,移除 5 列(隐藏这些列)
    // 例如:移除第 5、6、7、8、9 列
    // ⚠️ 问题:开发者自己加了 "/*?*/" 表示不确定为什么这样做
    // 可能因为某些列不需要显示给业主看
}

// ============================================================
// 析构函数 - 释放资源
// 当窗口关闭时自动调用
// ============================================================

OwnerManage::~OwnerManage()
{
    delete ui;
    // 删除 UI 对象,释放界面上所有控件的内存
    // 这是必须的,因为 ui 是在构造函数中用 new 创建的
    // Qt 的对象树机制会自动释放子对象,但 ui 本身需要手动释放
}

// ============================================================
// "车位申请"按钮槽函数
// 当用户点击工具栏/菜单的"车位申请"时被调用
// ============================================================

void OwnerManage::on_applyCarStationAct_triggered()
{
    applyCarStation = new ApplyCarStation;
    // 创建车位申请窗口对象
    // 在堆上分配内存
    // ⚠️ 问题:没有设置父对象,可能导致内存泄漏
    // 建议:添加 this 作为父对象,或设置 WA_DeleteOnClose

    applyCarStation->show();
    // 显示车位申请窗口
    // show() 是非模态显示,不阻塞主窗口
    // 用户可以在两个窗口间切换
}

// ============================================================
// "车位查看"按钮槽函数
// 当用户点击"车位查看"时被调用
// 功能:显示当前业主的车位信息
// ============================================================

void OwnerManage::on_showcCarStationAct_triggered()
{
    ownerModel->setTable("carstation");
    // 切换数据表到 "carstation"(车位表)
    // 之前绑定的是 "owner" 表,现在切换到车位表

    // 获取当前业主名
    QString strFilter = QString("ownername = '%1'").arg(this->windowTitle().trimmed());
    // 构建查询条件:筛选该业主的车位
    // this->windowTitle() 获取窗口标题,即业主名
    // trimmed() 去除首尾空格
    // 例如:窗口标题是 "张三",则 strFilter = "ownername = '张三'"
    // ⚠️ SQL 注入风险!使用字符串拼接

    qDebug() << "strFilter:" << strFilter;
    // 输出过滤条件到控制台
    // 用于调试,检查生成的 SQL 条件是否正确

    ownerModel->setFilter(strFilter);
    // 设置过滤条件
    // 相当于执行:SELECT * FROM carstation WHERE ownername = '张三'

    ownerModel->select();
    // 执行查询,从数据库获取数据
    // 查询结果存储在 ownerModel 中

    // 设置表头显示名称(用户看到的列名)
    ownerModel->setHeaderData(0, Qt::Horizontal, tr("车位号"));
    // 第0列显示为"车位号"
    // Qt::Horizontal 表示水平方向(列)

    ownerModel->setHeaderData(1, Qt::Horizontal, tr("地上/地下"));
    // 第1列显示为"地上/地下"

    ownerModel->setHeaderData(2, Qt::Horizontal, tr("大/小"));
    // 第2列显示为"大/小"

    ownerModel->setHeaderData(3, Qt::Horizontal, tr("能否充电"));
    // 第3列显示为"能否充电"

    ownerModel->setHeaderData(4, Qt::Horizontal, tr("所属业主"));
    // 第4列显示为"所属业主"

    ownerModel->setHeaderData(5, Qt::Horizontal, tr("缴费状态"));
    // 第5列显示为"缴费状态"

    ownerTableView->setModel(ownerModel);
    // 将数据模型设置到表格视图
    // 表格现在显示车位信息
}

// ============================================================
// "缴费查询"按钮槽函数
// 当用户点击"缴费查询"时被调用
// 功能:显示当前业主的缴费记录
// ============================================================

void OwnerManage::on_payShowAct_triggered()
{
    ownerModel->setTable("priceRecord");
    // 切换到 "priceRecord"(缴费记录表)

    QString strFilter = QString("ownername = '%1'").arg(this->windowTitle().trimmed());
    // 构建过滤条件:筛选该业主的缴费记录
    // ⚠️ 同样的 SQL 注入风险

    ownerModel->setFilter(strFilter);
    // 设置过滤条件

    ownerModel->select();
    // 执行查询

    // 设置表头
    ownerModel->setHeaderData(0, Qt::Horizontal, tr("缴费人"));
    ownerModel->setHeaderData(1, Qt::Horizontal, tr("缴费类型"));
    ownerModel->setHeaderData(2, Qt::Horizontal, tr("缴费金额"));
    ownerModel->setHeaderData(3, Qt::Horizontal, tr("缴费时间"));

    ownerTableView->setModel(ownerModel);
    // 表格现在显示缴费记录
}

// ============================================================
// "自助缴费"按钮槽函数
// 当用户点击"自助缴费"时被调用
// 功能:打开自助缴费窗口
// ============================================================

void OwnerManage::on_payAct_triggered()
{
    pPay = new ownerPaySelf();
    // 创建自助缴费窗口对象
    // ⚠️ 没有设置父对象,可能内存泄漏

    QString strOwner = this->windowTitle();
    // 获取业主名

    pPay->setWindowTitle(strOwner);
    // 将业主名设置为缴费窗口的标题
    // 这样缴费窗口知道是谁在缴费

    pPay->show();
    // 显示缴费窗口(非模态)
}

// ============================================================
// "故障报修"按钮槽函数
// 当用户点击"故障报修"时被调用
// 功能:打开故障报修窗口
// ============================================================

void OwnerManage::on_issueReportAct_triggered()
{
    issue = new IssueInfo;
    // 创建故障报修窗口对象
    // ⚠️ 没有设置父对象

    issue->setUserName(this->windowTitle().trimmed());
    // 将业主名传递给报修窗口
    // 报修窗口知道是谁在报修

    issue->show();
    // 显示报修窗口
}

// ============================================================
// "维修进度"按钮槽函数
// 当用户点击"维修进度"时被调用
// 功能:查看当前业主的报修处理进度
// ============================================================

void OwnerManage::on_issueProcessAct_triggered()
{
    ownerState = 2;
    // 设置状态标记为 2
    // 表示"业主已查看维修进度"
    // ⚠️ 问题:使用硬编码数字 2,不清晰
    // 建议:使用枚举,如 enum { NotViewed, Viewed }

    QString strSql = QString("owner = '%1'").arg(this->windowTitle().trimmed());
    // 构建查询条件
    // ⚠️ SQL 注入风险

    ownerModel->setTable("errorinfo");
    // 切换到 "errorinfo"(报修信息表)

    ownerModel->setFilter(strSql);
    // 设置过滤条件

    ownerModel->select();
    // 执行查询

    ownerModel->setHeaderData(0, Qt::Horizontal, tr("序号"));
    // 第0列显示为"序号"

    ownerModel->setHeaderData(1, Qt::Horizontal, tr("申请人"));
    // 第1列显示为"申请人"

    ownerModel->setHeaderData(2, Qt::Horizontal, tr("故障描述"));
    // 第2列显示为"故障描述"

    ownerModel->setHeaderData(3, Qt::Horizontal, tr("申请时间"));
    // 第3列显示为"申请时间"

    ownerModel->setHeaderData(4, Qt::Horizontal, tr("维修进度"));
    // 第4列显示为"维修进度"

    ownerModel->setHeaderData(4, Qt::Horizontal, tr("维修评价"));
    // ❌ BUG!再次设置第4列,覆盖了上一行
    // 第4列应该显示"维修评价",但被设置为"维修评价"(重复)
    // 应该是第5列设置"维修评价"

    ownerTableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    // 禁止用户编辑表格内容
    // NoEditTriggers:任何操作都不能触发编辑
    // 用户只能查看,不能修改

    ownerTableView->setModel(ownerModel);
    // 表格现在显示报修进度
}

// ============================================================
// "维修评价"按钮槽函数
// 当用户点击"维修评价"时被调用
// 功能:对完成的维修进行评价
// 前提:必须先查看过维修进度(ownerState == 2)
// ============================================================

void OwnerManage::on_issueEvaluateAct_triggered()
{
    if (2 == ownerState) {
        // 检查是否已查看维修进度
        // 只有查看过进度才能评价
        // ⚠️ 使用硬编码数字 2

        int n = ownerTableView->currentIndex().row();
        // 获取当前选中的行索引
        // currentIndex() 返回当前选中的单元格索引
        // row() 获取行号

        QString strInfo = ownerModel->record(n).value("errornum").toString();
        // 获取当前行中 "errornum" 字段的值
        // record(n) 获取第 n 行的记录
        // value("errornum") 获取该字段的值
        // toString() 转换为字符串
        // 这个值用于标识是哪条报修记录

        p = new issueAssessment(this);
        // 创建评价窗口对象
        // ✅ 设置了父对象 this,由 Qt 管理内存

        p->setMessageIndex(strInfo);
        // 传递报修记录编号给评价窗口
        // 评价窗口知道要评价哪条记录

        p->exec();
        // 模态显示评价窗口
        // exec() 会阻塞当前窗口,直到评价窗口关闭
        // 用户必须先完成评价才能继续操作

    }

    ownerModel->select();
    // 刷新数据
    // 重新查询数据库,更新表格显示
}

业主界面功能流程图

cpp 复制代码
业主登录成功
    ↓
显示 OwnerManage 主窗口
    ↓
┌─────────────────────────────────────────────────────────────┐
│                    菜单/工具栏                              │
│                                                             │
│  车位申请 → ApplyCarStation(车位申请窗口)                 │
│  车位查看 → 显示当前业主的车位信息                         │
│  缴费查询 → 显示缴费记录列表                               │
│  自助缴费 → ownerPaySelf(缴费窗口)                       │
│  故障报修 → IssueInfo(报修窗口)                          │
│  故障进度 → 查看报修处理进度                               │
│  维修评价 → issueAssessment(评价窗口)                    │
└─────────────────────────────────────────────────────────────┘

整体运行流程图

cpp 复制代码
用户登录成功
    ↓
创建 OwnerManage 主窗口
    ↓
┌─────────────────────────────────────────────────────────────────┐
│                   主窗口显示                                    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  菜单栏/工具栏:车位申请 | 车位查看 | 缴费查询         │    │
│  │  自助缴费 | 故障报修 | 故障进度 | 维修评价             │    │
│  ├─────────────────────────────────────────────────────────┤    │
│  │                                                         │    │
│  │              中央表格区域 (空)                          │    │
│  │             等待用户点击功能按钮                       │    │
│  │                                                         │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

详细运行过程

阶段一:启动初始化(构造函数执行)

cpp 复制代码
// ============================================================
// 第1步:用户登录成功,创建 OwnerManage 对象
// ============================================================

// 在 logindialog.cpp 中
void LoginDialog::loginAsOwner(const QString &username, const QString &password)
{
    // ... 验证通过 ...
    owner = new OwnerManage;        // ← 第1步:创建对象
    owner->setWindowTitle(username); // 设置窗口标题为业主名
    owner->show();                  // ← 第2步:显示窗口
    this->hide();
}

构造函数内部执行过程:

cpp 复制代码
OwnerManage::OwnerManage(QWidget *parent)
    ↓
1. QMainWindow(parent)        // 调用父类构造函数
    ↓
2. ui(new Ui::OwnerManage)    // 创建 UI 对象
    ↓
3. ui->setupUi(this)          // 加载 .ui 界面文件
    ↓
4. ui->toolBar->setIconSize(QSize(50,50))  // 设置工具栏图标大小
    ↓
5. ownerTableView = new QTableView        // 创建表格视图
    ↓
6. setCentralWidget(ownerTableView)       // 设置为中央部件
    ↓
7. ownerModel = new QSqlTableModel(this)  // 创建数据模型
    ↓
8. ownerQueryModel = new QSqlQueryModel   // 创建查询模型(未使用)
    ↓
9. ownerModel->setTable("owner")          // 设置表名为 owner
    ↓
10. ownerModel->setEditStrategy(OnManualSubmit)  // 手动提交模式
    ↓
11. ownerModel->removeColumns(5,5)        // 隐藏第5-9列
    ↓
12. 构造函数结束,窗口显示

此时窗口状态:

cpp 复制代码
┌─────────────────────────────────────────────────────────────────┐
│  IntelligentCommunity - 张三(业主)                           │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  车位申请 │ 车位查看 │ 缴费查询 │ 自助缴费 │ 故障报修  │    │
│  │  故障进度 │ 维修评价                                  │    │
│  ├─────────────────────────────────────────────────────────┤    │
│  │                                                         │    │
│  │              (中央表格区域为空)                        │    │
│  │                                                         │    │
│  └─────────────────────────────────────────────────────────┘    │
│  状态栏:就绪                                                │
└─────────────────────────────────────────────────────────────────┘

阶段二:用户操作 - 车位查看

用户点击"车位查看"按钮

cpp 复制代码
┌─────────────────────────────────────────────────────────────────┐
│  用户点击 "车位查看" 按钮                                      │
│                          ↓                                     │
│  触发 clicked() 信号                                           │
│                          ↓                                     │
│  自动调用 on_showcCarStationAct_triggered() 槽函数            │
└─────────────────────────────────────────────────────────────────┘

槽函数执行过程:

cpp 复制代码
void OwnerManage::on_showcCarStationAct_triggered()
{
    // ============================================================
    // 第1步:切换数据表
    // ============================================================
    ownerModel->setTable("carstation");
    // 原来 ownerModel 绑定的是 "owner" 表
    // 现在切换到 "carstation" 表

    // ============================================================
    // 第2步:构建查询条件(⚠️ SQL 注入风险)
    // ============================================================
    QString strFilter = QString("ownername = '%1'")
                        .arg(this->windowTitle().trimmed());
    // 假设窗口标题是 "张三"
    // strFilter = "ownername = '张三'"
    
    qDebug() << "strFilter:" << strFilter;

    // ============================================================
    // 第3步:设置过滤条件并查询
    // ============================================================
    ownerModel->setFilter(strFilter);
    // 相当于执行:SELECT * FROM carstation WHERE ownername = '张三'
    
    ownerModel->select();
    // 执行查询,从数据库获取数据

    // ============================================================
    // 第4步:设置表头显示名称
    // ============================================================
    ownerModel->setHeaderData(0, Qt::Horizontal, tr("车位号"));
    ownerModel->setHeaderData(1, Qt::Horizontal, tr("地上/地下"));
    ownerModel->setHeaderData(2, Qt::Horizontal, tr("大/小"));
    ownerModel->setHeaderData(3, Qt::Horizontal, tr("能否充电"));
    ownerModel->setHeaderData(4, Qt::Horizontal, tr("所属业主"));
    ownerModel->setHeaderData(5, Qt::Horizontal, tr("缴费状态"));

    // ============================================================
    // 第5步:将模型绑定到表格视图
    // ============================================================
    ownerTableView->setModel(ownerModel);
    // 表格显示查询结果
}

运行后的界面变化:

cpp 复制代码
┌─────────────────────────────────────────────────────────────────┐
│  IntelligentCommunity - 张三(业主)                           │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  车位申请 │ 车位查看 │ 缴费查询 │ 自助缴费 │ 故障报修  │    │
│  │  故障进度 │ 维修评价                                  │    │
│  ├─────────────────────────────────────────────────────────┤    │
│  │                                                         │    │
│  │  车位号 │ 地上/地下 │ 大/小 │ 能否充电 │ 所属业主 │ 缴费状态│
│  │  ──────┼─────────┼──────┼─────────┼─────────┼─────────┤    │
│  │  A001  │  地下   │  大  │   是    │  张三   │  已缴费  │    │
│  │  A002  │  地上   │  小  │   否    │  张三   │  未缴费  │    │
│  │                                                         │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

阶段三:用户操作 - 缴费查询

cpp 复制代码
用户点击 "缴费查询"
    ↓
on_payShowAct_triggered() 被调用
    ↓
切换到 priceRecord 表
    ↓
过滤:ownername = '张三'
    ↓
显示缴费记录

界面变化:

cpp 复制代码
┌─────────────────────────────────────────────────────────────────┐
│  IntelligentCommunity - 张三(业主)                           │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  车位申请 │ 车位查看 │ 缴费查询 │ 自助缴费 │ 故障报修  │    │
│  │  故障进度 │ 维修评价                                  │    │
│  ├─────────────────────────────────────────────────────────┤    │
│  │                                                         │    │
│  │  缴费人 │ 缴费类型 │ 缴费金额 │ 缴费时间              │    │
│  │  ──────┼─────────┼─────────┼───────────────────────  │    │
│  │  张三   │ 物业费  │ 500.00  │ 2026-08-01 10:30:00   │    │
│  │  张三   │ 车位费  │ 200.00  │ 2026-08-15 14:20:00   │    │
│  │                                                         │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

阶段四:用户操作 - 自助缴费

cpp 复制代码
用户点击 "自助缴费"
    ↓
on_payAct_triggered() 被调用
    ↓
创建 ownerPaySelf 窗口
    ↓
设置窗口标题为业主名
    ↓
显示缴费窗口(不阻塞主窗口)

弹出新窗口:

cpp 复制代码
┌─────────────────────────────────────────────────────────────────┐
│  IntelligentCommunity - 张三(业主)          ┌──────────────┐│
│  ┌─────────────────────────────────────────┐ │ 自助缴费      ││
│  │  车位申请 │ 车位查看 │ 缴费查询 │ 自助缴费 │ 业主: 张三   ││
│  │  故障进度 │ 维修评价                  │ │ 类型: 物业费  ││
│  ├─────────────────────────────────────────┤ │ 金额: [___]  ││
│  │        主窗口                         │ │ [确认] [取消] ││
│  │        仍然可以操作                   │ └──────────────┘│
│  └─────────────────────────────────────────┘                  │
└─────────────────────────────────────────────────────────────────┘

阶段五:用户操作 - 维修进度 → 维修评价(联动流程)

cpp 复制代码
┌─────────────────────────────────────────────────────────────────┐
│  用户点击 "故障进度"                                            │
│                          ↓                                     │
│  on_issueProcessAct_triggered() 被调用                         │
│                          ↓                                     │
│  ownerState = 2(标记已查看进度)                               │
│                          ↓                                     │
│  切换到 errorinfo 表,显示报修记录                             │
│                          ↓                                     │
│  用户选择一行,点击 "维修评价"                                 │
│                          ↓                                     │
│  on_issueEvaluateAct_triggered() 被调用                        │
│                          ↓                                     │
│  检查 ownerState == 2(必须查看过进度)                        │
│                          ↓                                     │
│  获取当前选中的 errornum                                       │
│                          ↓                                     │
│  创建 issueAssessment 评价窗口                                 │
└─────────────────────────────────────────────────────────────────┘

阶段六:窗口关闭

cpp 复制代码
用户点击窗口右上角 "×"
    ↓
触发 QMainWindow 的关闭事件
    ↓
调用析构函数 ~OwnerManage()
    ↓
delete ui(释放 UI 对象)
    ↓
由于 Qt 对象树机制,所有子对象自动释放
    ↓
窗口关闭,返回登录对话框

完整数据流图

cpp 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                        用户交互                                 │
│                            ↓                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              工具栏按钮点击                             │    │
│  └─────────────────────┬───────────────────────────────────┘    │
│                        ↓                                       │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              槽函数被调用                               │    │
│  │  1. 切换表:setTable()                                 │    │
│  │  2. 设置过滤:setFilter()                              │    │
│  │  3. 执行查询:select()                                 │    │
│  │  4. 设置表头:setHeaderData()                          │    │
│  └─────────────────────┬───────────────────────────────────┘    │
│                        ↓                                       │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              QSqlTableModel                             │    │
│  │  1. 生成 SQL:SELECT * FROM carstation WHERE ...        │    │
│  │  2. 执行查询                                           │    │
│  │  3. 返回数据                                           │    │
│  └─────────────────────┬───────────────────────────────────┘    │
│                        ↓                                       │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │              QTableView(显示数据)                     │    │
│  │  1. 从 Model 获取数据                                  │    │
│  │  2. 按表头格式显示                                     │    │
│  │  3. 用户看到结果                                       │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

函数调用关系图

cpp 复制代码
用户点击工具栏按钮
    ↓
┌─────────────────────────────────────────────────────────────────┐
│                   槽函数被调用                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ① 车位申请 → on_applyCarStationAct_triggered()               │
│       ↓                                                         │
│       new ApplyCarStation → show()                             │
│                                                                 │
│  ② 车位查看 → on_showcCarStationAct_triggered()               │
│       ↓                                                         │
│       setTable("carstation") → setFilter() → select()          │
│       → setHeaderData() → setModel()                          │
│                                                                 │
│  ③ 缴费查询 → on_payShowAct_triggered()                       │
│       ↓                                                         │
│       setTable("priceRecord") → setFilter() → select()         │
│       → setHeaderData() → setModel()                          │
│                                                                 │
│  ④ 自助缴费 → on_payAct_triggered()                           │
│       ↓                                                         │
│       new ownerPaySelf() → setWindowTitle() → show()           │
│                                                                 │
│  ⑤ 故障报修 → on_issueReportAct_triggered()                   │
│       ↓                                                         │
│       new IssueInfo() → setUserName() → show()                 │
│                                                                 │
│  ⑥ 维修进度 → on_issueProcessAct_triggered()                 │
│       ↓                                                         │
│       ownerState = 2 → setTable("errorinfo") → setFilter()     │
│       → select() → setHeaderData() → setModel()               │
│                                                                 │
│  ⑦ 维修评价 → on_issueEvaluateAct_triggered()                 │
│       ↓                                                         │
│       if (ownerState == 2) → 获取选中行 → 获取 errornum        │
│       → new issueAssessment() → setMessageIndex() → exec()     │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

3.ownerinfo.h

原始版本一

cpp 复制代码
#ifndef OWNERINFO_H
#define OWNERINFO_H

#include <QWidget>
#include <QSqlTableModel>
#include <QMessageBox>
#include <QSqlRecord>
#include <QDebug>

namespace Ui {
class OwnerInfo;
}
//业主信息登记类,共有集成QWidget类。
class OwnerInfo : public QWidget
{
    Q_OBJECT

public:
    explicit OwnerInfo(QWidget *parent = 0);
    ~OwnerInfo();


private:
    Ui::OwnerInfo *ui;
    QSqlTableModel *model;  //SQL表格读写模型指针

    bool judgeEmpty();  //判断工作人员输入"姓名"和"密码"是否为空
    void clearAll();    //清除所有工作人员输入内容




signals:
    void EmitWorkerChanged();
private slots:
    void on_ownerInfoConfirmBtn_clicked();  //"确定"按键槽函数
    void on_ownerInfoReturnBtn_clicked();   //"返回"按键槽函数
};

#endif // OWNERINFO_H

修复版本二

无注释版
cpp 复制代码
class OwnerInfo : public QWidget
{
public:
    enum Mode { AddMode, EditMode };
    void setMode(Mode mode);
    void setOwnerId(int id);
private:
    Mode m_mode;
    int m_ownerId;
};
model->setFilter(QString("ownername = '%1'").arg(name));
model->select();
if (model->rowCount() > 0) { /* 已存在 */ }
if (!model->submitAll()) {
    QMessageBox::critical(this, "错误", "保存失败:" + model->lastError().text());
    model->revertAll();
}
有注释版
cpp 复制代码
// ============================================================
// 优化1:添加编辑模式
// ============================================================
class OwnerInfo : public QWidget
{
public:
    enum Mode { AddMode, EditMode };
    void setMode(Mode mode);
    void setOwnerId(int id);  // 编辑时设置要修改的业主ID

private:
    Mode m_mode;
    int m_ownerId;
};

// ============================================================
// 优化2:使用 setFilter 检查重复
// ============================================================
// ❌ 当前:加载所有数据
model->select();
for (int i = 0; i < model->rowCount(); i++) { ... }

// ✅ 优化:只查询特定姓名
model->setFilter(QString("ownername = '%1'").arg(name));
model->select();
if (model->rowCount() > 0) { /* 已存在 */ }

// ============================================================
// 优化3:添加错误处理
// ============================================================
if (!model->submitAll()) {
    QMessageBox::critical(this, "错误", 
                          "保存失败:" + model->lastError().text());
    model->revertAll();
}

3.ownerinfo.cpp

原始版本一

cpp 复制代码
#include "ownerinfo.h"
#include "ui_ownerinfo.h"
/********业主登记类OwnerInfo构造函数*******************************************/
OwnerInfo::OwnerInfo(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::OwnerInfo)
{
    ui->setupUi(this);
    //设置model实现与数据库交互
    model=new QSqlTableModel(this); //创建SQL连接
    model->setTable("houseowner");  //设置访问表为"houseowner"
    model->setEditStrategy(QSqlTableModel::OnManualSubmit); //设置数据库编辑模式
    model->removeColumns(5,5);      //移除当前列之后的5列数据

}
/********业主登记类OwnerInfo析构函数*******************************************/
OwnerInfo::~OwnerInfo()
{
    delete ui;
}
/********《槽函数》"确认"按键执行操作函数*************************************/
void OwnerInfo::on_ownerInfoConfirmBtn_clicked()
{
    if(!this->judgeEmpty()) //判断输入内容是否为空
        return;
    model->select();        //数据查询
    int i;
    for(i=0;i<model->rowCount();i++)    //循环检测所有行数据
    {
        //如果当前行的第一个数据与工作人员输入的新业主名字一致,则是重复登记,退出循环
        if(model->data(model->index(i,0)).toString()==ui->ownerNameLineEdit->text())
        {
            break;
        }
    }
    if(i!=model->rowCount())//如果检索到有重复的业主名,则退出本次操作,并警告
    {
        QMessageBox::information(this,"提示","该业主已经存在",QMessageBox::Yes);
        this->clearAll();   //清除所有输入内容
        return;
    }
    //如果没在数据库中检索到新的业主名,则可以进行添加操作
    QSqlRecord record=model->record();  //获取新行记录
    //将工作人员输入的名字写入数据库的"ownername"字段
    record.setValue("ownername",ui->ownerNameLineEdit->text());
    record.setValue("ownerpass",ui->ownerPassLineEdit->text());
    record.setValue("owneraddress",ui->ownerAddressLineEdit->text());
    record.setValue("ownerphone",ui->ownerPhoneLineEdit->text());

    model->insertRecord(-1,record); //向尾部添加新用户数据
    if(model->submitAll())          //提交修改
    {

        QMessageBox::information(this,"提示","业主添加成功",QMessageBox::Yes); //显示提示窗口
        this->clearAll();   //清除输入所有内容
    }
}
/********《槽函数》"返回"按键执行操作函数*************************************/
void OwnerInfo::on_ownerInfoReturnBtn_clicked()
{
    //如果窗口没有输入任何内容
    if(ui->ownerNameLineEdit->text().isEmpty()&&ui->ownerPhoneLineEdit->text().isEmpty()&&
            ui->ownerPassLineEdit->text().isEmpty()&&ui->ownerAddressLineEdit->text().isEmpty())
    {
        emit EmitWorkerChanged();//发送信号............................实际没用????
        this->hide();            //隐藏窗口
        qDebug("addworker");     //输出调试信息
        return;                  //返回
    }
    //如果窗口内有部分输入的内容,打开提示窗口
    if(QMessageBox::question(this,"提示","尚未保存,是否退出",
                             QMessageBox::Yes|QMessageBox::No)==QMessageBox::Yes)
    {
        //emit EmitToTeacherManage();
        this->hide();   //隐藏窗口
    }
}
/********判断工作人员输入"姓名"和"密码"是否为空函数**********************/
bool OwnerInfo::judgeEmpty()
{
    if(ui->ownerNameLineEdit->text().isEmpty()) //如果工作人员输入的"姓名"内容为空
    {
        //输出警告信息
        QMessageBox::warning(this,"警告","业主姓名不能为空",QMessageBox::Yes);
        return false;
    }
    else if(ui->ownerPassLineEdit->text().isEmpty())//如果工作人员输入的"密码"内容为空
    {
        //输出警告信息
        QMessageBox::warning(this,"警告","业主密码不能为空",QMessageBox::Yes);
        return false;
    }
    else
        return true;
}
/********清除工作人员输入函数************************************************/
void OwnerInfo::clearAll()
{
    ui->ownerNameLineEdit->clear();     //清除工作人员输入的"姓名"内容
    ui->ownerPassLineEdit->clear();     //                  "密码"
    ui->ownerPhoneLineEdit->clear();    //                  "电话"
    ui->ownerAddressLineEdit->clear();  //                  "住址"
}

修复版本二

无注释版
cpp 复制代码
#include "ownerinfo.h"
#include "ui_ownerinfo.h"

OwnerInfo::OwnerInfo(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::OwnerInfo)
{
    ui->setupUi(this);

    model = new QSqlTableModel(this);
    model->setTable("houseowner");
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->removeColumns(5, 5);
}

OwnerInfo::~OwnerInfo()
{
    delete ui;
}

void OwnerInfo::on_ownerInfoConfirmBtn_clicked()
{
    if (!this->judgeEmpty()) {
        return;
    }

    model->select();

    int i;
    for (i = 0; i < model->rowCount(); i++) {
        if (model->data(model->index(i, 0)).toString() == ui->ownerNameLineEdit->text()) {
            break;
        }
    }

    if (i != model->rowCount()) {
        QMessageBox::information(this, "提示", "该业主已经存在", QMessageBox::Yes);
        this->clearAll();
        return;
    }

    QSqlRecord record = model->record();
    record.setValue("ownername", ui->ownerNameLineEdit->text());
    record.setValue("ownerpass", ui->ownerPassLineEdit->text());
    record.setValue("owneraddress", ui->ownerAddressLineEdit->text());
    record.setValue("ownerphone", ui->ownerPhoneLineEdit->text());

    model->insertRecord(-1, record);

    if (model->submitAll()) {
        QMessageBox::information(this, "提示", "业主添加成功", QMessageBox::Yes);
        this->clearAll();
    }
}

void OwnerInfo::on_ownerInfoReturnBtn_clicked()
{
    if (ui->ownerNameLineEdit->text().isEmpty() &&
        ui->ownerPhoneLineEdit->text().isEmpty() &&
        ui->ownerPassLineEdit->text().isEmpty() &&
        ui->ownerAddressLineEdit->text().isEmpty()) {

        emit EmitWorkerChanged();
        this->hide();
        qDebug("addworker");
        return;
    }

    if (QMessageBox::question(this, "提示", "尚未保存,是否退出",
                              QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
        this->hide();
    }
}

bool OwnerInfo::judgeEmpty()
{
    if (ui->ownerNameLineEdit->text().isEmpty()) {
        QMessageBox::warning(this, "警告", "业主姓名不能为空", QMessageBox::Yes);
        return false;
    }

    if (ui->ownerPassLineEdit->text().isEmpty()) {
        QMessageBox::warning(this, "警告", "业主密码不能为空", QMessageBox::Yes);
        return false;
    }

    return true;
}

void OwnerInfo::clearAll()
{
    ui->ownerNameLineEdit->clear();
    ui->ownerPassLineEdit->clear();
    ui->ownerPhoneLineEdit->clear();
    ui->ownerAddressLineEdit->clear();
}
有注释版
cpp 复制代码
// ============================================================
// 文件:ownerinfo.cpp
// 功能:业主信息登记/编辑
// 说明:添加新业主或修改业主信息
// ============================================================

#include "ownerinfo.h"
// 包含自己的头文件声明

#include "ui_ownerinfo.h"
// 包含由 .ui 文件生成的 UI 类头文件

// ============================================================
// 构造函数 - 初始化业主信息界面
// ============================================================

OwnerInfo::OwnerInfo(QWidget *parent) :
    QWidget(parent),            // 调用父类 QWidget 构造函数
    ui(new Ui::OwnerInfo)       // 创建 UI 对象
{
    ui->setupUi(this);          // 加载 .ui 界面文件

    // ============================================================
    // 设置数据模型
    // ============================================================
    model = new QSqlTableModel(this);
    // 创建 SQL 表格模型,设置父对象为 this(自动内存管理)

    model->setTable("houseowner");
    // 设置要操作的数据表为 "houseowner"(业主表)

    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    // 设置编辑策略为"手动提交"
    // 修改后需要调用 submitAll() 才会保存到数据库

    model->removeColumns(5, 5);
    // 从第5列开始,移除5列(隐藏不需要显示的列)
    // ⚠️ 问题:注释不清晰,不确定移除了哪些列
}

// ============================================================
// 析构函数 - 释放资源
// ============================================================

OwnerInfo::~OwnerInfo()
{
    delete ui;
    // 删除 UI 对象,释放界面控件内存
    // model 不需要手动 delete,因为设置了父对象 this
}

// ============================================================
// "确认"按钮槽函数 - 添加业主
// ============================================================

void OwnerInfo::on_ownerInfoConfirmBtn_clicked()
{
    // --------------------------------------------------------
    // 1. 输入验证
    // --------------------------------------------------------
    if (!this->judgeEmpty()) {
        // 判断输入是否为空(姓名和密码不能为空)
        // 如果为空,judgeEmpty() 已弹出警告框,直接返回
        return;
    }

    // --------------------------------------------------------
    // 2. 查询数据库,检查业主是否已存在
    // --------------------------------------------------------
    model->select();
    // 执行查询,从 houseowner 表加载所有数据

    int i;
    for (i = 0; i < model->rowCount(); i++) {
        // 遍历所有行,检查姓名是否重复
        // model->index(i, 0) 获取第 i 行第 0 列(ownername 字段)
        // data() 获取单元格数据,toString() 转为字符串
        if (model->data(model->index(i, 0)).toString() == ui->ownerNameLineEdit->text()) {
            // 如果当前行的业主名与输入的一致,说明已存在
            break;  // 退出循环
        }
    }

    // --------------------------------------------------------
    // 3. 检查是否找到重复记录
    // --------------------------------------------------------
    if (i != model->rowCount()) {
        // 如果 i 不等于总行数,说明在循环中找到了重复记录(break 提前退出)
        QMessageBox::information(this, "提示", "该业主已经存在", QMessageBox::Yes);
        this->clearAll();   // 清除所有输入框
        return;  // 退出函数
    }

    // --------------------------------------------------------
    // 4. 添加新业主记录
    // --------------------------------------------------------
    QSqlRecord record = model->record();
    // 获取一个空记录结构(包含所有字段,但没有数据)

    // 将用户输入的值设置到记录中
    record.setValue("ownername", ui->ownerNameLineEdit->text());
    // 业主姓名

    record.setValue("ownerpass", ui->ownerPassLineEdit->text());
    // 业主密码

    record.setValue("owneraddress", ui->ownerAddressLineEdit->text());
    // 业主地址

    record.setValue("ownerphone", ui->ownerPhoneLineEdit->text());
    // 业主电话

    model->insertRecord(-1, record);
    // 插入记录到模型末尾(-1 表示追加到最后)

    // --------------------------------------------------------
    // 5. 提交数据到数据库
    // --------------------------------------------------------
    if (model->submitAll()) {
        // submitAll() 提交所有待处理的修改到数据库
        // 返回 true 表示提交成功

        QMessageBox::information(this, "提示", "业主添加成功", QMessageBox::Yes);
        this->clearAll();   // 清除输入框,准备添加下一个
    }
    // ⚠️ 问题:如果提交失败,没有错误提示
}

// ============================================================
// "返回"按钮槽函数 - 关闭窗口
// ============================================================

void OwnerInfo::on_ownerInfoReturnBtn_clicked()
{
    // --------------------------------------------------------
    // 1. 检查是否有输入内容
    // --------------------------------------------------------
    if (ui->ownerNameLineEdit->text().isEmpty() &&
        ui->ownerPhoneLineEdit->text().isEmpty() &&
        ui->ownerPassLineEdit->text().isEmpty() &&
        ui->ownerAddressLineEdit->text().isEmpty()) {
        // 所有输入框都为空 → 直接关闭

        emit EmitWorkerChanged();
        // 发射信号(通知其他模块数据已变更)
        // ⚠️ 问题:信号名拼写可能有问题,且未连接

        this->hide();  // 隐藏窗口(不是关闭)
        qDebug("addworker");  // 调试输出
        return;
    }

    // --------------------------------------------------------
    // 2. 有输入内容 → 询问是否保存
    // --------------------------------------------------------
    if (QMessageBox::question(this, "提示", "尚未保存,是否退出",
                              QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
        // 用户选择"是" → 放弃修改并退出
        // emit EmitToTeacherManage();  // 已注释
        this->hide();  // 隐藏窗口
    }
    // 用户选择"否" → 什么都不做,继续编辑
}

// ============================================================
// 判断输入是否为空
// ============================================================

bool OwnerInfo::judgeEmpty()
{
    // --------------------------------------------------------
    // 1. 检查业主姓名
    // --------------------------------------------------------
    if (ui->ownerNameLineEdit->text().isEmpty()) {
        QMessageBox::warning(this, "警告", "业主姓名不能为空", QMessageBox::Yes);
        return false;
    }

    // --------------------------------------------------------
    // 2. 检查业主密码
    // --------------------------------------------------------
    if (ui->ownerPassLineEdit->text().isEmpty()) {
        QMessageBox::warning(this, "警告", "业主密码不能为空", QMessageBox::Yes);
        return false;
    }

    // 姓名和密码都不为空 → 验证通过
    return true;
}

// ============================================================
// 清空所有输入框
// ============================================================

void OwnerInfo::clearAll()
{
    ui->ownerNameLineEdit->clear();     // 清空姓名
    ui->ownerPassLineEdit->clear();     // 清空密码
    ui->ownerPhoneLineEdit->clear();    // 清空电话
    ui->ownerAddressLineEdit->clear();  // 清空地址
}

核心功能:添加业主

cpp 复制代码
用户输入业主信息
    ↓
点击"确认"按钮
    ↓
┌─────────────────────────────────────────────────────────────────────┐
│  on_ownerInfoConfirmBtn_clicked()                                 │
├─────────────────────────────────────────────────────────────────────┤
│  1. judgeEmpty() → 检查姓名和密码是否为空                        │
│                    ↓                                              │
│  2. 查询数据库 → 检查业主是否已存在                              │
│                    ↓                                              │
│  3. 如果已存在 → 提示"该业主已经存在" → 清空输入 → 返回         │
│                    ↓                                              │
│  4. 如果不存在 → 创建记录 → insertRecord() → submitAll()         │
│                    ↓                                              │
│  5. 成功 → 提示"业主添加成功" → 清空输入                         │
│     失败 → ❌ 没有错误处理                                        │
└─────────────────────────────────────────────────────────────────────┘

ownerinfo.ui

在管理人员界面可以添加业主信息

4.ownerpayself.h

原始版本一

cpp 复制代码
#ifndef OWNERPAYSELF_H
#define OWNERPAYSELF_H

#include <QWidget>

namespace Ui {
class ownerPaySelf;
}

//缴费类,公有继承QWidget
//使用UI设计师完成界面开发
class ownerPaySelf : public QWidget
{
    Q_OBJECT

public:
    explicit ownerPaySelf(QWidget *parent = 0);
    ~ownerPaySelf();
    bool  updateState(int nType);


private slots:
    void on_pushButton_clicked();   //"确认"按键槽函数
    void on_pushButton_2_clicked(); //"返回"按键槽函数

private:
    Ui::ownerPaySelf *ui;

    double getOwnerArrears(const QString &ownerName);
    bool hasPaid(const QString &ownerName, const QString &type);
};

#endif // OWNERPAYSELF_H

修复版本二

无注释版
cpp 复制代码
#ifndef OWNERPAYSELF_H
#define OWNERPAYSELF_H

#include <QWidget>

namespace Ui {
class ownerPaySelf;
}

class ownerPaySelf : public QWidget
{
    Q_OBJECT

public:
    explicit ownerPaySelf(QWidget *parent = 0);
    ~ownerPaySelf();

    bool updateState(int nType);

private slots:
    void on_pushButton_clicked();
    void on_pushButton_2_clicked();

private:
    Ui::ownerPaySelf *ui;

    double getOwnerArrears(const QString &ownerName);
    bool hasPaid(const QString &ownerName, const QString &type);
};

#endif // OWNERPAYSELF_H
有注释版
cpp 复制代码
// ============================================================
// 文件:ownerpayself.h
// 功能:业主自助缴费界面的头文件声明
// 说明:业主可以在这里缴纳物业费、车位费等各项费用
// ============================================================

#ifndef OWNERPAYSELF_H
// 作用:防止头文件被多次包含(Include Guard)
// 如果 OWNERPAYSELF_H 未定义,则定义它并包含头文件内容
// 如果已定义,则跳过整个头文件内容

#define OWNERPAYSELF_H
// 定义宏 OWNERPAYSELF_H,标记这个头文件已经被包含

// ============================================================
// 头文件包含
// ============================================================

#include <QWidget>
// 包含 QWidget 基类
// QWidget 是所有 Qt 窗口控件的基类
// 本类继承 QWidget,作为一个独立的窗口部件

// ============================================================
// UI 命名空间声明
// ============================================================

namespace Ui {
class ownerPaySelf;
// 声明 UI 类
// 这个类由 Qt 的 uic 工具根据 ownerpayself.ui 文件自动生成
// 包含了界面上所有控件的指针(输入框、按钮、下拉框等)
}

// ============================================================
// ownerPaySelf 类定义
// 业主自助缴费窗口,继承自 QWidget
// ============================================================

class ownerPaySelf : public QWidget
// class ownerPaySelf : 定义一个名为 ownerPaySelf 的类
// public QWidget : 公有继承自 QWidget 基类
// 作为独立的窗口部件,可以嵌入到其他窗口或单独显示

{
    Q_OBJECT
    // Qt 元对象宏
    // 启用信号槽机制、运行时类型信息等 Qt 元对象功能
    // 因为类中使用了 private slots,必须包含此宏

public:
    // ============================================================
    // public 区域:对外公开的接口
    // ============================================================

    explicit ownerPaySelf(QWidget *parent = 0);
    // 构造函数
    // explicit: 防止隐式类型转换
    // QWidget *parent = 0: 父窗口指针,默认值为 nullptr

    ~ownerPaySelf();
    // 析构函数
    // 当对象被销毁时自动调用,释放资源

    bool updateState(int nType);
    // 更新缴费状态函数(公开接口)
    // 参数:nType - 缴费类型(0: 车位费, 1: 物业费)
    // 返回值:true - 更新成功,false - 更新失败
    // 在缴费成功后调用,更新对应表的缴费状态

private slots:
    // ============================================================
    // 私有槽函数区域
    // 响应按钮点击事件
    // ============================================================

    void on_pushButton_clicked();
    // "确认"按钮的槽函数
    // 当用户点击"确认"时被调用
    // 功能:验证输入 → 构建缴费记录 → 保存到数据库 → 更新状态

    void on_pushButton_2_clicked();
    // "返回"按钮的槽函数
    // 当用户点击"返回"时被调用
    // 功能:关闭当前缴费窗口

private:
    // ============================================================
    // private 区域:私有的成员变量和函数
    // 只能在类内部访问,外部不可见
    // ============================================================

    Ui::ownerPaySelf *ui;
    // UI 对象指针
    // 指向由 uic 工具生成的 UI 类对象
    // 通过这个指针可以访问界面上所有的控件
    // 例如:ui->lineEdit(金额输入框)
    //       ui->comboBox(缴费类型下拉框)
    //       ui->lineEdit_2(业主姓名输入框)
    //       ui->pushButton(确认按钮)
    //       ui->pushButton_2(返回按钮)

    // ============================================================
    // 私有辅助函数
    // ============================================================

    double getOwnerArrears(const QString &ownerName);
    // 获取业主欠费总额
    // 参数:ownerName - 业主姓名
    // 返回值:欠费总金额(double 类型)
    // 查询数据库中该业主所有未缴费的记录,汇总金额
    // ✅ 新增功能(扩展功能)

    bool hasPaid(const QString &ownerName, const QString &type);
    // 检查是否已缴费(防止重复缴费)
    // 参数:ownerName - 业主姓名,type - 缴费类型
    // 返回值:true - 已缴费,false - 未缴费
    // 用于防止业主对同一项目重复缴费
    // ✅ 新增功能(扩展功能)
};

#endif // OWNERPAYSELF_H
// 结束条件编译块
// 如果头文件被重复包含,从 #ifndef 到 #endif 之间的内容会被跳过

功能流程图

cpp 复制代码
业主打开自助缴费窗口
    ↓
输入缴费金额
    ↓
选择缴费类型(物业费/车位费/其他)
    ↓
点击"确认"按钮
    ↓
┌─────────────────────────────────────────────────────────────────────┐
│  on_pushButton_clicked()                                          │
├─────────────────────────────────────────────────────────────────────┤
│  1. 验证输入                                                      │
│     ↓ 金额为空 → 提示"请输入缴费金额"                            │
│     ↓ 业主名为空 → 提示"请输入业主姓名"                          │
│  2. 构建缴费记录                                                  │
│     → 业主姓名、缴费类型、缴费金额、缴费时间                     │
│  3. 插入到 priceRecord 表                                        │
│  4. 提交到数据库                                                  │
│  5. 更新状态(调用 updateState())                                │
│     ↓ 成功 → 提示"缴费成功!"                                    │
│     ↓ 失败 → 提示"缴费出错,请重新缴费"                          │
└─────────────────────────────────────────────────────────────────────┘

4.ownerpayself.cpp

原始版本一

cpp 复制代码
// ============================================================
// 文件:ownerpayself.cpp
// 功能:业主自助缴费模块
// ============================================================

#include "ownerpayself.h"
#include "ui_ownerpayself.h"

#include <QRegularExpression>          // Qt 6 推荐的正则表达式
#include <QRegularExpressionValidator> // Qt 6 推荐的验证器
#include <QSqlTableModel>
#include <QSqlRecord>
#include <QSqlQuery>
#include <QSqlError>
#include <QMessageBox>
#include <QDateTime>
#include <QDebug>

// ============================================================
// 构造函数 - 初始化界面和验证器
// ============================================================
ownerPaySelf::ownerPaySelf(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ownerPaySelf)
{
    ui->setupUi(this);

    // --------------------------------------------------------
    // 1. 设置输入验证器:只允许输入数字
    //    使用 QRegularExpressionValidator 替代 QRegExpValidator
    // --------------------------------------------------------
    QRegularExpression regx("[0-9]+$");
    QValidator* validator = new QRegularExpressionValidator(regx, this);
    ui->lineEdit->setValidator(validator);

    // --------------------------------------------------------
    // 2. 显示当前时间
    // --------------------------------------------------------
    QDateTime currentTime = QDateTime::currentDateTime();
    QString timeStr = currentTime.toString("yyyy-MM-dd hh:mm:ss");
    qDebug() << "缴费窗口初始化成功,当前时间:" << timeStr;
}

// ============================================================
// 析构函数 - 释放资源
// ============================================================
ownerPaySelf::~ownerPaySelf()
{
    delete ui;
}

// ============================================================
// "确认缴费"按钮槽函数
// ============================================================
void ownerPaySelf::on_pushButton_clicked()
{
    // --------------------------------------------------------
    // 1. 获取并验证用户输入
    // --------------------------------------------------------
    QString strValue = ui->lineEdit->text().trimmed();
    if (strValue.isEmpty()) {
        QMessageBox::warning(this, tr("提示"), tr("请输入缴费金额!"));
        ui->lineEdit->setFocus();
        return;
    }

    // 验证金额是否为有效数字
    bool ok;
    double amount = strValue.toDouble(&ok);
    if (!ok || amount <= 0) {
        QMessageBox::warning(this, tr("提示"), tr("请输入有效的金额!"));
        ui->lineEdit->clear();
        ui->lineEdit->setFocus();
        return;
    }

    QString strType = ui->comboBox->currentText();
    QString ownerName = ui->lineEdit_2->text().trimmed();

    // 检查业主姓名是否为空
    if (ownerName.isEmpty()) {
        QMessageBox::warning(this, tr("提示"), tr("请先输入业主姓名!"));
        ui->lineEdit_2->setFocus();
        return;
    }

    // --------------------------------------------------------
    // 2. 使用 QSqlTableModel 保存缴费记录
    // --------------------------------------------------------
    QSqlTableModel *tableModel = new QSqlTableModel(this);
    tableModel->setTable("priceRecord");

    if (!tableModel->select()) {
        QMessageBox::critical(this, tr("错误"),
                              tr("数据库查询失败:") + tableModel->lastError().text());
        delete tableModel;
        return;
    }

    // --------------------------------------------------------
    // 3. 构建缴费记录
    // --------------------------------------------------------
    QSqlRecord record = tableModel->record();
    record.setValue("ownername", ownerName);
    record.setValue("type", strType);
    record.setValue("price", strValue);

    QDateTime time = QDateTime::currentDateTime();
    QString strTime = time.toString("yyyy-MM-dd hh:mm:ss");
    record.setValue("time", strTime);

    // --------------------------------------------------------
    // 4. 插入记录到数据库
    // --------------------------------------------------------
    if (!tableModel->insertRecord(-1, record)) {
        QMessageBox::critical(this, tr("错误"),
                              tr("插入记录失败:") + tableModel->lastError().text());
        delete tableModel;
        return;
    }

    // --------------------------------------------------------
    // 5. 提交数据到数据库
    // --------------------------------------------------------
    bool submitSuccess = tableModel->submitAll();

    if (submitSuccess) {
        bool updateSuccess = updateState(ui->comboBox->currentIndex());

        if (updateSuccess) {
            QMessageBox::information(this, tr("提示"), tr("缴费成功!"));
            ui->lineEdit->clear();
            qDebug() << "缴费成功:" << ownerName << strType << strValue << strTime;
        } else {
            tableModel->revertAll();
            QMessageBox::warning(this, tr("提示"),
                                 tr("缴费记录已保存,但状态更新失败,请检查!"));
        }
    } else {
        tableModel->revertAll();
        QMessageBox::critical(this, tr("错误"),
                              tr("保存失败:") + tableModel->lastError().text());
    }

    delete tableModel;
}

// ============================================================
// "返回"按钮槽函数
// ============================================================
void ownerPaySelf::on_pushButton_2_clicked()
{
    this->close();
}

// ============================================================
// 更新缴费状态
// ============================================================
bool ownerPaySelf::updateState(int nType)
{
    QString ownerName = ui->lineEdit_2->text().trimmed();
    if (ownerName.isEmpty()) {
        qDebug() << "更新状态失败:业主姓名为空";
        return false;
    }

    if (0 == nType) {
        // 车位费缴费
        QSqlQuery query;
        query.prepare("UPDATE carstation SET paystate = '已缴费' WHERE ownername = :ownerName");
        query.bindValue(":ownerName", ownerName);

        if (!query.exec()) {
            qDebug() << "更新车位状态失败:" << query.lastError().text();
            QMessageBox::critical(this, tr("错误"),
                                  tr("更新车位状态失败:") + query.lastError().text());
            return false;
        }

        if (query.numRowsAffected() == 0) {
            qDebug() << "未找到对应的车位记录:" << ownerName;
            QMessageBox::warning(this, tr("提示"),
                                 tr("未找到业主 '%1' 的车位记录!").arg(ownerName));
            return false;
        }

        qDebug() << "车位缴费状态更新成功,业主:" << ownerName;
        return true;
    } else {
        qDebug() << "物业费缴费功能待实现";
        return false;
    }
}

// ============================================================
// 【扩展功能】获取当前业主的欠费信息
// ============================================================
double ownerPaySelf::getOwnerArrears(const QString &ownerName)
{
    QSqlQuery query;
    query.prepare("SELECT SUM(price) FROM priceRecord WHERE ownername = :ownerName AND status = '未缴费'");
    query.bindValue(":ownerName", ownerName);

    if (query.exec() && query.next()) {
        return query.value(0).toDouble();
    }
    return 0.0;
}

// ============================================================
// 【扩展功能】检查是否已缴费
// ============================================================
bool ownerPaySelf::hasPaid(const QString &ownerName, const QString &type)
{
    QSqlQuery query;
    query.prepare("SELECT COUNT(*) FROM priceRecord WHERE ownername = :ownerName AND type = :type AND time >= date('now', 'start of month')");
    query.bindValue(":ownerName", ownerName);
    query.bindValue(":type", type);

    if (query.exec() && query.next()) {
        return query.value(0).toInt() > 0;
    }
    return false;
}

修复版本二

无注释版
cpp 复制代码
#include "ownerpayself.h"
#include "ui_ownerpayself.h"

#include <QRegularExpression>
#include <QRegularExpressionValidator>
#include <QSqlTableModel>
#include <QSqlRecord>
#include <QSqlQuery>
#include <QSqlError>
#include <QMessageBox>
#include <QDateTime>
#include <QDebug>

ownerPaySelf::ownerPaySelf(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ownerPaySelf)
{
    ui->setupUi(this);

    QRegularExpression regx("[0-9]+$");
    QValidator* validator = new QRegularExpressionValidator(regx, this);
    ui->lineEdit->setValidator(validator);

    QDateTime currentTime = QDateTime::currentDateTime();
    QString timeStr = currentTime.toString("yyyy-MM-dd hh:mm:ss");
    qDebug() << "缴费窗口初始化成功,当前时间:" << timeStr;
}

ownerPaySelf::~ownerPaySelf()
{
    delete ui;
}

void ownerPaySelf::on_pushButton_clicked()
{
    QString strValue = ui->lineEdit->text().trimmed();
    if (strValue.isEmpty()) {
        QMessageBox::warning(this, tr("提示"), tr("请输入缴费金额!"));
        ui->lineEdit->setFocus();
        return;
    }

    bool ok;
    double amount = strValue.toDouble(&ok);
    if (!ok || amount <= 0) {
        QMessageBox::warning(this, tr("提示"), tr("请输入有效的金额!"));
        ui->lineEdit->clear();
        ui->lineEdit->setFocus();
        return;
    }

    QString strType = ui->comboBox->currentText();
    QString ownerName = ui->lineEdit_2->text().trimmed();

    if (ownerName.isEmpty()) {
        QMessageBox::warning(this, tr("提示"), tr("请先输入业主姓名!"));
        ui->lineEdit_2->setFocus();
        return;
    }

    QSqlTableModel *tableModel = new QSqlTableModel(this);
    tableModel->setTable("priceRecord");

    if (!tableModel->select()) {
        QMessageBox::critical(this, tr("错误"),
                              tr("数据库查询失败:") + tableModel->lastError().text());
        delete tableModel;
        return;
    }

    QSqlRecord record = tableModel->record();
    record.setValue("ownername", ownerName);
    record.setValue("type", strType);
    record.setValue("price", strValue);

    QDateTime time = QDateTime::currentDateTime();
    QString strTime = time.toString("yyyy-MM-dd hh:mm:ss");
    record.setValue("time", strTime);

    if (!tableModel->insertRecord(-1, record)) {
        QMessageBox::critical(this, tr("错误"),
                              tr("插入记录失败:") + tableModel->lastError().text());
        delete tableModel;
        return;
    }

    bool submitSuccess = tableModel->submitAll();

    if (submitSuccess) {
        bool updateSuccess = updateState(ui->comboBox->currentIndex());

        if (updateSuccess) {
            QMessageBox::information(this, tr("提示"), tr("缴费成功!"));
            ui->lineEdit->clear();
            qDebug() << "缴费成功:" << ownerName << strType << strValue << strTime;
        } else {
            tableModel->revertAll();
            QMessageBox::warning(this, tr("提示"),
                                 tr("缴费记录已保存,但状态更新失败,请检查!"));
        }
    } else {
        tableModel->revertAll();
        QMessageBox::critical(this, tr("错误"),
                              tr("保存失败:") + tableModel->lastError().text());
    }

    delete tableModel;
}

void ownerPaySelf::on_pushButton_2_clicked()
{
    this->close();
}

bool ownerPaySelf::updateState(int nType)
{
    QString ownerName = ui->lineEdit_2->text().trimmed();
    if (ownerName.isEmpty()) {
        qDebug() << "更新状态失败:业主姓名为空";
        return false;
    }

    if (0 == nType) {
        QSqlQuery query;
        query.prepare("UPDATE carstation SET paystate = '已缴费' WHERE ownername = :ownerName");
        query.bindValue(":ownerName", ownerName);

        if (!query.exec()) {
            qDebug() << "更新车位状态失败:" << query.lastError().text();
            QMessageBox::critical(this, tr("错误"),
                                  tr("更新车位状态失败:") + query.lastError().text());
            return false;
        }

        if (query.numRowsAffected() == 0) {
            qDebug() << "未找到对应的车位记录:" << ownerName;
            QMessageBox::warning(this, tr("提示"),
                                 tr("未找到业主 '%1' 的车位记录!").arg(ownerName));
            return false;
        }

        qDebug() << "车位缴费状态更新成功,业主:" << ownerName;
        return true;
    } else {
        qDebug() << "物业费缴费功能待实现";
        return false;
    }
}

double ownerPaySelf::getOwnerArrears(const QString &ownerName)
{
    QSqlQuery query;
    query.prepare("SELECT SUM(price) FROM priceRecord WHERE ownername = :ownerName AND status = '未缴费'");
    query.bindValue(":ownerName", ownerName);

    if (query.exec() && query.next()) {
        return query.value(0).toDouble();
    }
    return 0.0;
}

bool ownerPaySelf::hasPaid(const QString &ownerName, const QString &type)
{
    QSqlQuery query;
    query.prepare("SELECT COUNT(*) FROM priceRecord WHERE ownername = :ownerName AND type = :type AND time >= date('now', 'start of month')");
    query.bindValue(":ownerName", ownerName);
    query.bindValue(":type", type);

    if (query.exec() && query.next()) {
        return query.value(0).toInt() > 0;
    }
    return false;
}
有注释版
cpp 复制代码
// ============================================================
// 文件:ownerpayself.cpp
// 功能:业主自助缴费模块
// 说明:业主可以在此缴纳物业费、车位费等费用
// ============================================================

#include "ownerpayself.h"
// 包含自己的头文件声明
// 让编译器知道类 ownerPaySelf 的结构、成员函数和成员变量

#include "ui_ownerpayself.h"
// 包含由 .ui 文件生成的 UI 类头文件
// 包含了 Ui::ownerPaySelf 类的定义,其中有所有控件的指针

#include <QRegularExpression>
// 包含 Qt 6 的正则表达式类
// 用于验证用户输入的金额是否为纯数字

#include <QRegularExpressionValidator>
// 包含 Qt 6 的正则表达式验证器
// 用于限制用户输入只能匹配指定的正则表达式

#include <QSqlTableModel>
// 包含 SQL 表格模型类
// 用于与数据库表交互,执行增删改查操作

#include <QSqlRecord>
// 包含 SQL 记录类
// 用于表示数据库中的一条记录(一行数据)

#include <QSqlQuery>
// 包含 SQL 查询类
// 用于执行 SQL 语句和获取结果

#include <QSqlError>
// 包含 SQL 错误类
// 用于获取数据库操作失败时的错误信息

#include <QMessageBox>
// 包含消息框类
// 用于显示提示、警告、错误等信息

#include <QDateTime>
// 包含日期时间类
// 用于获取当前时间,记录缴费时间

#include <QDebug>
// 包含调试输出类
// 用于在控制台打印调试信息

// ============================================================
// 构造函数 - 初始化界面和验证器
// 参数:parent - 父窗口指针,默认 nullptr
// 当业主点击"自助缴费"时,此对象被创建
// ============================================================

ownerPaySelf::ownerPaySelf(QWidget *parent) :
    QWidget(parent),            // 调用父类 QWidget 的构造函数,传入父窗口指针
    ui(new Ui::ownerPaySelf)    // 创建 UI 对象(由 Qt Designer 生成的界面类)
{
    ui->setupUi(this);
    // setupUi() 加载 .ui 文件,创建所有控件并设置布局
    // 相当于把 UI 设计师设计的界面加载到当前窗口

    // --------------------------------------------------------
    // 1. 设置输入验证器:只允许输入数字
    //    使用 QRegularExpressionValidator 限制用户只能输入纯数字
    //    防止输入非数字字符导致程序异常
    // --------------------------------------------------------

    QRegularExpression regx("[0-9]+$");
    // 创建正则表达式对象
    // "[0-9]+$" 含义:
    //   [0-9] 匹配 0-9 之间的任意数字
    //   + 匹配一次或多次
    //   $ 匹配字符串结尾
    // 整体含义:整个字符串必须全部是数字

    QValidator* validator = new QRegularExpressionValidator(regx, this);
    // 创建正则表达式验证器
    // 参数1:正则表达式对象
    // 参数2:父对象 this(自动内存管理)
    // 验证器会检查用户输入是否符合正则表达式

    ui->lineEdit->setValidator(validator);
    // 将验证器设置到金额输入框
    // 用户只能输入数字,字母和符号会被自动过滤

    // --------------------------------------------------------
    // 2. 显示当前时间(用于调试)
    // --------------------------------------------------------

    QDateTime currentTime = QDateTime::currentDateTime();
    // 获取当前系统时间

    QString timeStr = currentTime.toString("yyyy-MM-dd hh:mm:ss");
    // 将时间格式化为字符串
    // 格式:年-月-日 时:分:秒
    // 例如:2026-08-22 14:30:00

    qDebug() << "缴费窗口初始化成功,当前时间:" << timeStr;
    // 输出调试信息到控制台
    // 方便开发者确认窗口已成功创建
}

// ============================================================
// 析构函数 - 释放资源
// 当窗口关闭时自动调用
// ============================================================

ownerPaySelf::~ownerPaySelf()
{
    delete ui;
    // 删除 UI 对象,释放界面上所有控件的内存
    // 这是必须的,因为 ui 是在构造函数中用 new 创建的
    // Qt 的对象树机制会自动释放子对象,但 ui 本身需要手动释放
}

// ============================================================
// "确认缴费"按钮槽函数
// 当用户点击"确认"按钮时被调用
// 功能:验证输入 → 构建记录 → 保存到数据库
// ============================================================

void ownerPaySelf::on_pushButton_clicked()
{
    // --------------------------------------------------------
    // 1. 获取并验证用户输入
    // --------------------------------------------------------

    QString strValue = ui->lineEdit->text().trimmed();
    // 获取金额输入框的文本,去除首尾空格

    if (strValue.isEmpty()) {
        // 如果金额为空
        QMessageBox::warning(this, tr("提示"), tr("请输入缴费金额!"));
        // 弹出警告框提示用户
        ui->lineEdit->setFocus();
        // 将焦点设置到金额输入框,让用户输入
        return;  // 退出函数
    }

    bool ok;
    double amount = strValue.toDouble(&ok);
    // 将字符串转换为 double 类型
    // ok 用于判断转换是否成功

    if (!ok || amount <= 0) {
        // 如果转换失败(不是数字)或金额小于等于 0
        QMessageBox::warning(this, tr("提示"), tr("请输入有效的金额!"));
        // 弹出警告框提示用户
        ui->lineEdit->clear();
        // 清空金额输入框
        ui->lineEdit->setFocus();
        // 将焦点设置到金额输入框
        return;  // 退出函数
    }

    QString strType = ui->comboBox->currentText();
    // 获取缴费类型下拉框的当前选中文本
    // 例如:"物业费"、"车位费"等

    QString ownerName = ui->lineEdit_2->text().trimmed();
    // 获取业主姓名输入框的文本,去除首尾空格

    if (ownerName.isEmpty()) {
        // 如果业主姓名为空
        QMessageBox::warning(this, tr("提示"), tr("请先输入业主姓名!"));
        // 弹出警告框提示用户
        ui->lineEdit_2->setFocus();
        // 将焦点设置到业主姓名输入框
        return;  // 退出函数
    }

    // --------------------------------------------------------
    // 2. 使用 QSqlTableModel 保存缴费记录
    //    ✅ 在堆上创建,避免栈上对象生命周期问题
    // --------------------------------------------------------

    QSqlTableModel *tableModel = new QSqlTableModel(this);
    // 创建 SQL 表格模型对象
    // 参数 this 表示父对象是当前窗口,由 Qt 自动管理内存

    tableModel->setTable("priceRecord");
    // 设置要操作的数据表为 "priceRecord"(缴费记录表)

    if (!tableModel->select()) {
        // 执行查询,如果失败则进入 if
        QMessageBox::critical(this, tr("错误"),
                              tr("数据库查询失败:") + tableModel->lastError().text());
        // 弹出错误对话框,显示具体错误信息
        delete tableModel;
        // 释放模型对象
        return;  // 退出函数
    }

    // --------------------------------------------------------
    // 3. 构建缴费记录
    //    使用 QSqlRecord 创建新记录
    // --------------------------------------------------------

    QSqlRecord record = tableModel->record();
    // 获取一个空记录结构(包含所有字段,但没有数据)
    // 用于构建要插入的新记录

    record.setValue("ownername", ownerName);
    // 设置 "ownername" 字段的值为业主姓名

    record.setValue("type", strType);
    // 设置 "type" 字段的值为缴费类型

    record.setValue("price", strValue);
    // 设置 "price" 字段的值为缴费金额

    QDateTime time = QDateTime::currentDateTime();
    // 获取当前系统时间

    QString strTime = time.toString("yyyy-MM-dd hh:mm:ss");
    // 将时间格式化为字符串

    record.setValue("time", strTime);
    // 设置 "time" 字段的值为当前时间

    // --------------------------------------------------------
    // 4. 插入记录到数据库
    //    insertRecord(-1) 表示在末尾追加
    // --------------------------------------------------------

    if (!tableModel->insertRecord(-1, record)) {
        // 插入记录到模型末尾,如果失败则进入 if
        QMessageBox::critical(this, tr("错误"),
                              tr("插入记录失败:") + tableModel->lastError().text());
        // 弹出错误对话框,显示具体错误信息
        delete tableModel;
        // 释放模型对象
        return;  // 退出函数
    }

    // --------------------------------------------------------
    // 5. 提交数据到数据库
    // --------------------------------------------------------

    bool submitSuccess = tableModel->submitAll();
    // 提交所有待处理的修改到数据库
    // 返回 true 表示提交成功,false 表示提交失败

    if (submitSuccess) {
        // 提交成功
        bool updateSuccess = updateState(ui->comboBox->currentIndex());
        // 调用 updateState() 更新缴费状态
        // 参数:当前选中的缴费类型索引(0: 车位费, 1: 物业费)

        if (updateSuccess) {
            // 状态更新成功
            QMessageBox::information(this, tr("提示"), tr("缴费成功!"));
            // 弹出提示框告知用户缴费成功

            ui->lineEdit->clear();
            // 清空金额输入框,方便下一次输入

            qDebug() << "缴费成功:" << ownerName << strType << strValue << strTime;
            // 输出调试信息,记录缴费详情
        } else {
            // 状态更新失败
            tableModel->revertAll();
            // 回滚数据(撤销插入操作)

            QMessageBox::warning(this, tr("提示"),
                                 tr("缴费记录已保存,但状态更新失败,请检查!"));
            // 弹出警告框提示用户
        }
    } else {
        // 提交失败
        tableModel->revertAll();
        // 回滚数据(撤销插入操作)

        QMessageBox::critical(this, tr("错误"),
                              tr("保存失败:") + tableModel->lastError().text());
        // 弹出错误对话框,显示具体错误信息
    }

    delete tableModel;
    // 释放模型对象
}

// ============================================================
// "返回"按钮槽函数 - 关闭当前窗口
// 当用户点击"返回"按钮时被调用
// ============================================================

void ownerPaySelf::on_pushButton_2_clicked()
{
    this->close();
    // close() 关闭当前缴费窗口
    // 窗口关闭后,返回到业主主界面
}

// ============================================================
// 更新缴费状态
// 参数:nType - 0:车位费  1:物业费
// 返回:true-更新成功  false-更新失败
// 缴费成功后调用,更新对应表的状态
// ============================================================

bool ownerPaySelf::updateState(int nType)
{
    // --------------------------------------------------------
    // 1. 获取当前业主姓名
    // --------------------------------------------------------

    QString ownerName = ui->lineEdit_2->text().trimmed();
    // 从输入框获取业主姓名,去除首尾空格

    if (ownerName.isEmpty()) {
        // 如果业主姓名为空
        qDebug() << "更新状态失败:业主姓名为空";
        // 输出调试信息
        return false;  // 返回 false 表示更新失败
    }

    // --------------------------------------------------------
    // 2. 根据缴费类型执行不同的更新逻辑
    // --------------------------------------------------------

    if (0 == nType) {
        // ========== 车位费缴费 ==========
        // 更新 carstation 表的 paystate 字段

        QSqlQuery query;
        // 创建 SQL 查询对象

        query.prepare("UPDATE carstation SET paystate = '已缴费' WHERE ownername = :ownerName");
        // 准备 SQL 更新语句
        // :ownerName 是命名占位符,后续用 bindValue() 绑定
        // 使用参数绑定防止 SQL 注入攻击

        query.bindValue(":ownerName", ownerName);
        // 将业主姓名绑定到占位符

        if (!query.exec()) {
            // 执行更新,如果失败则进入 if
            qDebug() << "更新车位状态失败:" << query.lastError().text();
            // 输出错误信息到控制台

            QMessageBox::critical(this, tr("错误"),
                                  tr("更新车位状态失败:") + query.lastError().text());
            // 弹出错误对话框
            return false;  // 返回 false 表示更新失败
        }

        if (query.numRowsAffected() == 0) {
            // numRowsAffected() 返回受影响的行数
            // 如果为 0,说明没有匹配到任何记录
            qDebug() << "未找到对应的车位记录:" << ownerName;
            // 输出调试信息

            QMessageBox::warning(this, tr("提示"),
                                 tr("未找到业主 '%1' 的车位记录!").arg(ownerName));
            // 弹出警告框,提示未找到车位记录
            return false;  // 返回 false 表示更新失败
        }

        qDebug() << "车位缴费状态更新成功,业主:" << ownerName;
        // 输出调试信息
        return true;  // 返回 true 表示更新成功

    } else {
        // ========== 物业费缴费 ==========
        // 物业费缴费功能待实现
        qDebug() << "物业费缴费功能待实现";
        // 输出调试信息
        return false;  // 返回 false 表示更新失败
    }
}

// ============================================================
// 【扩展功能】获取当前业主的欠费信息
// 参数:ownerName - 业主姓名
// 返回值:欠费总金额
// 查询数据库中该业主所有未缴费的记录,汇总金额
// ============================================================

double ownerPaySelf::getOwnerArrears(const QString &ownerName)
{
    QSqlQuery query;
    // 创建 SQL 查询对象

    query.prepare("SELECT SUM(price) FROM priceRecord WHERE ownername = :ownerName AND status = '未缴费'");
    // 准备 SQL 查询语句
    // SUM(price) 计算所有未缴费记录的总金额
    // status = '未缴费' 只查询未缴费的记录

    query.bindValue(":ownerName", ownerName);
    // 将业主姓名绑定到占位符

    if (query.exec() && query.next()) {
        // 执行查询,如果成功且有结果
        return query.value(0).toDouble();
        // 返回第一行第一列的值(总金额)
    }

    return 0.0;
    // 查询失败或没有记录,返回 0
}

// ============================================================
// 【扩展功能】检查是否已缴费(防止重复缴费)
// 参数:ownerName - 业主姓名,type - 缴费类型
// 返回值:true-已缴费,false-未缴费
// 用于防止业主对同一项目重复缴费
// ============================================================

bool ownerPaySelf::hasPaid(const QString &ownerName, const QString &type)
{
    QSqlQuery query;
    // 创建 SQL 查询对象

    query.prepare("SELECT COUNT(*) FROM priceRecord WHERE ownername = :ownerName AND type = :type AND time >= date('now', 'start of month')");
    // 准备 SQL 查询语句
    // COUNT(*) 统计符合条件的记录数量
    // time >= date('now', 'start of month') 查询当月开始的记录
    // 即只检查本月是否已缴费

    query.bindValue(":ownerName", ownerName);
    // 将业主姓名绑定到占位符

    query.bindValue(":type", type);
    // 将缴费类型绑定到占位符

    if (query.exec() && query.next()) {
        // 执行查询,如果成功且有结果
        return query.value(0).toInt() > 0;
        // 如果数量大于 0,说明已缴费
    }

    return false;
    // 查询失败或没有记录,返回 false(未缴费)
}

4.ownerpayself.ui

5.paymanage.h

原始版本一

cpp 复制代码
#ifndef PAYMANAGE_H
#define PAYMANAGE_H

#include <QWidget>
#include <QSqlTableModel>
#include <QButtonGroup>
#include <QMessageBox>
#include <QSqlError>

namespace Ui {
class PayManage;
}
//缴费管理类,公有继承QWidgets
//使用UI设计师设计界面
class PayManage : public QWidget
{
    Q_OBJECT

public:
    explicit PayManage(QWidget *parent = 0);
    ~PayManage();

private slots:
    void on_squreBtn_clicked();     //"查询"按钮槽函数
    void on_payConfirmBtn_clicked();//"确认支付"按钮槽函数
    void on_pushButton_clicked();   //"缴费"按钮槽函数

private:
    Ui::PayManage *ui;
    QSqlTableModel *payModel;    //创建SQL表格模型指针
    QButtonGroup *payStatusGroup;//单选按键组
};

#endif // PAYMANAGE_H

修复版本二

无注释版
cpp 复制代码
#ifndef PAYMANAGE_H
#define PAYMANAGE_H

#include <QWidget>
#include <QSqlTableModel>
#include <QButtonGroup>
#include <QMessageBox>
#include <QSqlError>

namespace Ui {
class PayManage;
}

class PayManage : public QWidget
{
    Q_OBJECT

public:
    explicit PayManage(QWidget *parent = 0);
    ~PayManage();

private slots:
    void on_squreBtn_clicked();
    void on_payConfirmBtn_clicked();
    void on_pushButton_clicked();

private:
    Ui::PayManage *ui;
    QSqlTableModel *payModel;
    QButtonGroup *payStatusGroup;
};

#endif // PAYMANAGE_H
有注释版
cpp 复制代码
// ============================================================
// 文件:paymanage.h
// 功能:缴费管理界面的头文件声明
// 说明:管理员在此进行收费管理、查询缴费记录、确认支付等操作
// ============================================================

#ifndef PAYMANAGE_H
// 作用:防止头文件被多次包含(Include Guard)
// 如果 PAYMANAGE_H 未定义,则定义它并包含头文件内容
// 如果已定义,则跳过整个头文件内容

#define PAYMANAGE_H
// 定义宏 PAYMANAGE_H,标记这个头文件已经被包含

// ============================================================
// 头文件包含
// ============================================================

#include <QWidget>
// 包含 QWidget 基类
// QWidget 是所有 Qt 窗口控件的基类
// 本类继承 QWidget,作为一个独立的窗口部件

#include <QSqlTableModel>
// 包含 QSqlTableModel 类
// 用于与数据库表交互,支持增删改查操作
// 本类用于操作缴费相关的数据表(如 priceRecord)

#include <QButtonGroup>
// 包含 QButtonGroup 类
// 用于管理一组按钮,实现单选互斥效果
// 本类用于管理缴费状态的单选按钮(已缴费/未缴费)

#include <QMessageBox>
// 包含 QMessageBox 类
// 用于显示提示、警告、错误等消息框

#include <QSqlError>
// 包含 QSqlError 类
// 用于获取数据库操作失败时的错误信息

// ============================================================
// UI 命名空间声明
// ============================================================

namespace Ui {
class PayManage;
// 声明 UI 类
// 这个类由 Qt 的 uic 工具根据 paymanage.ui 文件自动生成
// 包含了界面上所有控件的指针
}

// ============================================================
// PayManage 类定义
// 缴费管理窗口,继承自 QWidget
// 管理员在此进行缴费管理操作
// ============================================================

class PayManage : public QWidget
// class PayManage : 定义一个名为 PayManage 的类
// public QWidget : 公有继承自 QWidget 基类
// 作为独立的窗口部件,可以嵌入到其他窗口或单独显示

{
    Q_OBJECT
    // Qt 元对象宏
    // 启用信号槽机制、运行时类型信息等 Qt 元对象功能
    // 因为类中使用了 private slots,必须包含此宏

public:
    // ============================================================
    // public 区域:对外公开的接口
    // ============================================================

    explicit PayManage(QWidget *parent = 0);
    // 构造函数
    // explicit: 防止隐式类型转换
    // QWidget *parent = 0: 父窗口指针,默认值为 nullptr

    ~PayManage();
    // 析构函数
    // 当对象被销毁时自动调用,释放资源

private slots:
    // ============================================================
    // 私有槽函数区域
    // 响应按钮点击事件
    // ============================================================

    void on_squreBtn_clicked();
    // "查询"按钮的槽函数
    // 当用户点击"查询"时被调用
    // 功能:根据筛选条件查询缴费记录
    // 可能按业主姓名、缴费状态、时间范围等条件查询

    void on_payConfirmBtn_clicked();
    // "确认支付"按钮的槽函数
    // 当用户点击"确认支付"时被调用
    // 功能:确认选中记录的支付状态
    // 将选中的未缴费记录标记为已缴费

    void on_pushButton_clicked();
    // "缴费"按钮的槽函数
    // 当用户点击"缴费"时被调用
    // 功能:执行缴费操作
    // 可能用于手动录入缴费记录

private:
    // ============================================================
    // private 区域:私有的成员变量
    // 只能在类内部访问,外部不可见
    // ============================================================

    Ui::PayManage *ui;
    // UI 对象指针
    // 指向由 uic 工具生成的 UI 类对象
    // 通过这个指针可以访问界面上所有的控件
    // 例如:ui->tableView(缴费记录表格)
    //       ui->comboBox(搜索条件下拉框)
    //       ui->lineEdit(搜索关键字输入框)
    //       ui->squreBtn(查询按钮)
    //       ui->payConfirmBtn(确认支付按钮)
    //       ui->pushButton(缴费按钮)

    QSqlTableModel *payModel;
    // SQL 表格模型对象指针
    // 用于与缴费记录表(如 priceRecord)交互
    // 提供数据的查询、显示、更新等功能
    // 通过 setTable() 指定表名
    // 通过 setFilter() 设置筛选条件
    // 通过 select() 执行查询

    QButtonGroup *payStatusGroup;
    // 缴费状态按钮组
    // 管理多个单选按钮,实现互斥选择
    // 例如:全部 / 已缴费 / 未缴费
    // 用于筛选不同状态的缴费记录
};

#endif // PAYMANAGE_H
// 结束条件编译块
// 如果头文件被重复包含,从 #ifndef 到 #endif 之间的内容会被跳过

5.paymanage.cpp

原始版本一

cpp 复制代码
#include "paymanage.h"
#include "ui_paymanage.h"
#include "ownerpayself.h"
/*********PayManage缴费管理类构造函数********************************************************/
PayManage::PayManage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::PayManage)
{
    ui->setupUi(this);

    payModel = new QSqlTableModel(this);
    payModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
    payModel->setTable("priceRecord");  //创建数据库连接表"priceRecord"
    payModel->select();
    payModel->setHeaderData(0,Qt::Horizontal,tr("缴费人"));    //设置显示字段
    payModel->setHeaderData(1,Qt::Horizontal,tr("缴费类型"));
    payModel->setHeaderData(2,Qt::Horizontal,tr("缴费金额"));
    payModel->setHeaderData(3,Qt::Horizontal,tr("缴费时间"));
    ui->payTableView->setModel(payModel);   //送入表格显示

    payStatusGroup=new QButtonGroup(this);  //创建单选按键组
    payStatusGroup->addButton(ui->payedRadioButton,0);//添加单选案件
    payStatusGroup->addButton(ui->payRadioButton,1);
    ui->payRadioButton->setChecked(true);   //设置"物业费"按键默认选中
}
/*********PayManage缴费管理类析构函数********************************************************/
PayManage::~PayManage()
{
    delete ui;
}

/*********《槽函数》"查询"按键槽函数********************************************************/
void PayManage::on_squreBtn_clicked()
{
    if(ui->ownerNameLineEdit->text().isEmpty()) //判断"业主姓名"是否为空,为空进入
    {
        if(payStatusGroup->checkedId()== 0) //"车位租金"按键被选中,显示所有车位租金相关数据
        {
            payModel->setFilter("type='车位租金'"); //筛选数据
        }
        else
        {
             payModel->setFilter("type='物业费'");
        }
    }
    else    //判断"业主姓名"不为空
    {
        if(payStatusGroup->checkedId()==0)  //"车位租金"按键被选中
        {
            payModel->setFilter(QString("ownername= '%1'and type='车位租金'")
                                .arg(ui->ownerNameLineEdit->text()));
        }
        else
        {
             payModel->setFilter(QString("ownername= '%1'andtype='物业费'")
                                 .arg(ui->ownerNameLineEdit->text()));
        }
    }
    payModel->select(); //数据查询
    ui->payTableView->setModel(payModel);   //窗口显示

}
/*********《槽函数》"确认支付"按键槽函数********************************************************/
void PayManage::on_payConfirmBtn_clicked()
{

    payModel->database().transaction(); //判断并启动事件
    if(payModel->submitAll())   //提交缓存
    {
        payModel->database().commit();//提交数据库
    }
    else
    {
        payModel->database().rollback();//提交失败则回滚
        QMessageBox::warning(this,tr("tabalModel"),
                             tr("数据库错误:% 1").arg(payModel->lastError().text()));
    }
}
/*********《槽函数》"缴费"按键槽函数********************************************************/
void PayManage::on_pushButton_clicked()
{
    ownerPaySelf *p = new ownerPaySelf; //创建缴费川口对象
    p->show();  //显示窗口
}

修复版本二

无注释版
cpp 复制代码
#include "paymanage.h"
#include "ui_paymanage.h"
#include "ownerpayself.h"
#include <QSqlError>
#include <QDebug>

PayManage::PayManage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::PayManage)
{
    ui->setupUi(this);

    payModel = new QSqlTableModel(this);
    payModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
    payModel->setTable("priceRecord");
    payModel->select();

    payModel->setHeaderData(0, Qt::Horizontal, tr("缴费人"));
    payModel->setHeaderData(1, Qt::Horizontal, tr("缴费类型"));
    payModel->setHeaderData(2, Qt::Horizontal, tr("缴费金额"));
    payModel->setHeaderData(3, Qt::Horizontal, tr("缴费时间"));

    ui->payTableView->setModel(payModel);

    payStatusGroup = new QButtonGroup(this);
    payStatusGroup->addButton(ui->payedRadioButton, 0);
    payStatusGroup->addButton(ui->payRadioButton, 1);
    ui->payRadioButton->setChecked(true);
}

PayManage::~PayManage()
{
    delete ui;
}

void PayManage::on_squreBtn_clicked()
{
    QString ownerName = ui->ownerNameLineEdit->text().trimmed();
    int typeId = payStatusGroup->checkedId();
    QString typeName = (typeId == 0) ? "车位租金" : "物业费";

    QString filter;

    if (ownerName.isEmpty()) {
        filter = QString("type = '%1'").arg(typeName);
    } else {
        QString safeName = ownerName;
        safeName.replace("'", "''");
        filter = QString("ownername = '%1' AND type = '%2'")
                 .arg(safeName).arg(typeName);
    }

    payModel->setFilter(filter);
    payModel->select();

    qDebug() << "查询条件:" << filter;
}

void PayManage::on_payConfirmBtn_clicked()
{
    if (!payModel->isDirty()) {
        QMessageBox::information(this, tr("提示"), tr("没有需要保存的修改!"));
        return;
    }

    int ret = QMessageBox::question(this, tr("确认支付"),
                                    tr("确定要确认所有选中的缴费记录吗?"),
                                    QMessageBox::Yes | QMessageBox::No);

    if (ret != QMessageBox::Yes) {
        return;
    }

    payModel->database().transaction();

    if (payModel->submitAll()) {
        payModel->database().commit();
        QMessageBox::information(this, tr("提示"), tr("确认支付成功!"));
        qDebug() << "确认支付成功,提交了所有修改";
    } else {
        payModel->database().rollback();
        QString errorMsg = payModel->lastError().text();
        QMessageBox::critical(this, tr("错误"),
                              tr("确认支付失败:") + errorMsg);
        qDebug() << "确认支付失败:" << errorMsg;
    }
}

void PayManage::on_pushButton_clicked()
{
    ownerPaySelf *p = new ownerPaySelf(this);
    p->show();
}
有注释版
cpp 复制代码
// ============================================================
// 文件:paymanage.cpp
// 功能:缴费管理界面的实现
// 说明:管理员在此进行缴费记录的查询和确认支付
// ============================================================

#include "paymanage.h"
// 包含自己的头文件声明
// 让编译器知道类 PayManage 的结构、成员函数和成员变量

#include "ui_paymanage.h"
// 包含由 .ui 文件生成的 UI 类头文件
// 包含了 Ui::PayManage 类的定义,其中有所有控件的指针

#include "ownerpayself.h"
// 包含自助缴费模块的头文件
// 用于创建业主自助缴费窗口

#include <QSqlError>
// 包含 SQL 错误类
// 用于获取数据库操作失败时的错误信息

#include <QDebug>
// 包含调试输出类
// 用于在控制台打印调试信息

// ============================================================
// 构造函数 - 初始化缴费管理界面
// 参数:parent - 父窗口指针,默认 nullptr
// 当管理员点击"缴费管理"时,此对象被创建
// ============================================================

PayManage::PayManage(QWidget *parent) :
    QWidget(parent),            // 调用父类 QWidget 的构造函数,传入父窗口指针
    ui(new Ui::PayManage)       // 创建 UI 对象(由 Qt Designer 生成的界面类)
{
    ui->setupUi(this);
    // setupUi() 加载 .ui 文件,创建所有控件并设置布局

    // --------------------------------------------------------
    // 1. 创建数据模型
    // --------------------------------------------------------

    payModel = new QSqlTableModel(this);
    // 创建 SQL 表格模型,设置父对象为 this(自动内存管理)
    // 用于与缴费记录表交互

    payModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
    // 设置编辑策略为"手动提交"
    // 修改后需要调用 submitAll() 才会保存到数据库
    // 优点:可以批量修改,确认后再提交

    payModel->setTable("priceRecord");
    // 设置要操作的数据表为 "priceRecord"(缴费记录表)

    payModel->select();
    // 执行查询,从数据库加载所有缴费记录

    // --------------------------------------------------------
    // 2. 设置表头显示名称(用户看到的列名)
    // --------------------------------------------------------

    payModel->setHeaderData(0, Qt::Horizontal, tr("缴费人"));
    // 第0列显示为"缴费人"

    payModel->setHeaderData(1, Qt::Horizontal, tr("缴费类型"));
    // 第1列显示为"缴费类型"

    payModel->setHeaderData(2, Qt::Horizontal, tr("缴费金额"));
    // 第2列显示为"缴费金额"

    payModel->setHeaderData(3, Qt::Horizontal, tr("缴费时间"));
    // 第3列显示为"缴费时间"

    ui->payTableView->setModel(payModel);
    // 将数据模型设置到表格视图
    // 表格现在显示所有缴费记录

    // --------------------------------------------------------
    // 3. 创建缴费状态按钮组
    // --------------------------------------------------------

    payStatusGroup = new QButtonGroup(this);
    // 创建按钮组,父对象为 this(自动内存管理)
    // 用于实现单选互斥

    payStatusGroup->addButton(ui->payedRadioButton, 0);
    // 将"车位租金"单选按钮加入组,ID 为 0

    payStatusGroup->addButton(ui->payRadioButton, 1);
    // 将"物业费"单选按钮加入组,ID 为 1

    ui->payRadioButton->setChecked(true);
    // 默认选中"物业费"单选按钮
    // 用户打开窗口时,默认显示物业费缴费记录
}

// ============================================================
// 析构函数 - 释放资源
// 当窗口关闭时自动调用
// ============================================================

PayManage::~PayManage()
{
    delete ui;
    // 删除 UI 对象,释放界面上所有控件的内存
    // 这是必须的,因为 ui 是在构造函数中用 new 创建的
    // payModel 不需要手动 delete,因为设置了父对象 this
}

// ============================================================
// "查询"按钮槽函数 - 改进版
// 当用户点击"查询"按钮时被调用
// 功能:根据业主姓名和缴费类型筛选缴费记录
// 改进:使用参数绑定防止 SQL 注入,优化代码结构
// ============================================================

void PayManage::on_squreBtn_clicked()
{
    // --------------------------------------------------------
    // 1. 获取用户输入
    // --------------------------------------------------------

    QString ownerName = ui->ownerNameLineEdit->text().trimmed();
    // 获取业主姓名输入框的文本,去除首尾空格

    int typeId = payStatusGroup->checkedId();
    // 获取当前选中的缴费类型 ID
    // 0: 车位租金, 1: 物业费

    QString typeName = (typeId == 0) ? "车位租金" : "物业费";
    // 根据 ID 获取对应的类型名称字符串

    // --------------------------------------------------------
    // 2. 构建安全的过滤条件(防止 SQL 注入)
    // --------------------------------------------------------

    QString filter;
    // 声明过滤条件字符串

    if (ownerName.isEmpty()) {
        // 如果业主姓名为空,只按类型筛选
        filter = QString("type = '%1'").arg(typeName);
        // 筛选条件:缴费类型 = 选中的类型
        // ⚠️ typeName 是固定值("车位租金"或"物业费"),安全
    } else {
        // 如果业主姓名不为空,按姓名和类型筛选
        // 转义单引号防止 SQL 注入
        QString safeName = ownerName;
        safeName.replace("'", "''");
        // 将单引号替换为两个单引号(SQLite 转义方式)

        filter = QString("ownername = '%1' AND type = '%2'")
                 .arg(safeName).arg(typeName);
        // 筛选条件:业主姓名 = 输入值 AND 缴费类型 = 选中的类型
        // ✅ 使用转义后的名称,防止 SQL 注入
    }

    // --------------------------------------------------------
    // 3. 执行查询并刷新显示
    // --------------------------------------------------------

    payModel->setFilter(filter);
    // 设置过滤条件

    payModel->select();
    // 执行查询,从数据库获取筛选后的数据

    // payModel 中的数据已经更新,表格会自动刷新
    // 不需要再次调用 ui->payTableView->setModel(payModel)

    qDebug() << "查询条件:" << filter;
    // 输出调试信息,记录查询条件
}

// ============================================================
// "确认支付"按钮槽函数 - 改进版
// 当用户点击"确认支付"按钮时被调用
// 功能:确认当前显示的缴费记录,提交到数据库
// 改进:增加错误处理和用户反馈
// ============================================================

void PayManage::on_payConfirmBtn_clicked()
{
    // --------------------------------------------------------
    // 1. 检查是否有待提交的修改
    // --------------------------------------------------------

    if (!payModel->isDirty()) {
        // isDirty() 返回 true 表示有未保存的修改
        // 如果没有修改,直接返回
        QMessageBox::information(this, tr("提示"), tr("没有需要保存的修改!"));
        // 弹出提示框告知用户
        return;
        // 退出函数
    }

    // --------------------------------------------------------
    // 2. 确认提交
    // --------------------------------------------------------

    int ret = QMessageBox::question(this, tr("确认支付"),
                                    tr("确定要确认所有选中的缴费记录吗?"),
                                    QMessageBox::Yes | QMessageBox::No);
    // 弹出询问对话框,让用户确认是否提交
    // 返回用户点击的按钮(Yes 或 No)

    if (ret != QMessageBox::Yes) {
        // 如果用户点击"否",取消操作
        return;
        // 退出函数
    }

    // --------------------------------------------------------
    // 3. 使用事务确保数据一致性
    // --------------------------------------------------------

    payModel->database().transaction();
    // 开始数据库事务
    // 事务保证:要么全部成功,要么全部失败
    // 防止数据不一致

    if (payModel->submitAll()) {
        // submitAll() 提交所有待处理的修改到数据库
        // 返回 true 表示提交成功

        payModel->database().commit();
        // 提交事务,确认修改
        // 修改永久保存到数据库

        QMessageBox::information(this, tr("提示"), tr("确认支付成功!"));
        // 弹出提示框告知用户操作成功

        qDebug() << "确认支付成功,提交了所有修改";
        // 输出调试信息

    } else {
        // 提交失败

        payModel->database().rollback();
        // 回滚事务,撤销所有修改
        // 数据库恢复到事务开始前的状态

        QString errorMsg = payModel->lastError().text();
        // 获取错误信息

        QMessageBox::critical(this, tr("错误"),
                              tr("确认支付失败:") + errorMsg);
        // 弹出错误对话框,显示具体错误信息

        qDebug() << "确认支付失败:" << errorMsg;
        // 输出调试信息
    }
}

// ============================================================
// "缴费"按钮槽函数 - 改进版
// 当用户点击"缴费"按钮时被调用
// 功能:打开业主自助缴费窗口
// 改进:设置父对象防止内存泄漏
// ============================================================

void PayManage::on_pushButton_clicked()
{
    ownerPaySelf *p = new ownerPaySelf(this);
    // 创建自助缴费窗口对象
    // ✅ 设置父对象为 this,由 Qt 自动管理内存
    // 当 PayManage 窗口关闭时,缴费窗口也会被自动销毁

    p->show();
    // 显示缴费窗口(非模态)
    // 用户可以同时在两个窗口间切换操作
}

5.paymanage.ui

6.pricemanage.h

原始版本一

cpp 复制代码
#ifndef PRICEMANAGE_H
#define PRICEMANAGE_H

#include <QWidget>
#include <QSqlTableModel>
#include <QMessageBox>
#include <QSqlRecord>
#include <QDebug>

namespace Ui {
class PriceManage;
}
//价格维护窗口类,公有继承自QMainWindow类
//使用UI设计师完成设计
class PriceManage : public QWidget
{
    Q_OBJECT

public:
    explicit PriceManage(QWidget *parent = 0);
    ~PriceManage();

private slots:
    void on_priceConfirmBtn_clicked();  //"确认"按键槽函数
    void on_priceReturnBtn_clicked();   //"返回"按键槽函数

private:
    Ui::PriceManage *ui;
    QSqlTableModel *priceModel; //创建SQL表格模型指针

};

#endif // PRICEMANAGE_H

修复版本二

无注释版
cpp 复制代码
#ifndef PRICEMANAGE_H
#define PRICEMANAGE_H

#include <QWidget>
#include <QSqlTableModel>
#include <QMessageBox>
#include <QSqlRecord>
#include <QDebug>

namespace Ui {
class PriceManage;
}

class PriceManage : public QWidget
{
    Q_OBJECT

public:
    explicit PriceManage(QWidget *parent = 0);
    ~PriceManage();

private slots:
    void on_priceConfirmBtn_clicked();
    void on_priceReturnBtn_clicked();

private:
    Ui::PriceManage *ui;
    QSqlTableModel *priceModel;
};

#endif // PRICEMANAGE_H
有注释版
cpp 复制代码
// ============================================================
// 文件:pricemanage.h
// 功能:价格维护界面的头文件声明
// 说明:管理员在此设置和管理物业费、车位费等收费标准
// ============================================================

#ifndef PRICEMANAGE_H
// 作用:防止头文件被多次包含(Include Guard)
// 如果 PRICEMANAGE_H 未定义,则定义它并包含头文件内容
// 如果已定义,则跳过整个头文件内容

#define PRICEMANAGE_H
// 定义宏 PRICEMANAGE_H,标记这个头文件已经被包含

// ============================================================
// 头文件包含
// ============================================================

#include <QWidget>
// 包含 QWidget 基类
// QWidget 是所有 Qt 窗口控件的基类
// 本类继承 QWidget,作为一个独立的窗口部件

#include <QSqlTableModel>
// 包含 QSqlTableModel 类
// 用于与数据库表交互,支持增删改查操作
// 本类用于操作价格相关的数据表(如 price 表)

#include <QMessageBox>
// 包含 QMessageBox 类
// 用于显示提示、警告、错误等消息框

#include <QSqlRecord>
// 包含 QSqlRecord 类
// 用于表示数据库中的一条记录(一行数据)
// 在添加或修改价格时,用于构建记录

#include <QDebug>
// 包含 QDebug 类
// 用于输出调试信息到控制台

// ============================================================
// UI 命名空间声明
// ============================================================

namespace Ui {
class PriceManage;
// 声明 UI 类
// 这个类由 Qt 的 uic 工具根据 pricemanage.ui 文件自动生成
// 包含了界面上所有控件的指针
}

// ============================================================
// PriceManage 类定义
// 价格维护窗口,继承自 QWidget
// 管理员在此设置和管理收费标准
// ============================================================

class PriceManage : public QWidget
// class PriceManage : 定义一个名为 PriceManage 的类
// public QWidget : 公有继承自 QWidget 基类
// 作为独立的窗口部件,可以嵌入到其他窗口或单独显示

{
    Q_OBJECT
    // Qt 元对象宏
    // 启用信号槽机制、运行时类型信息等 Qt 元对象功能
    // 因为类中使用了 private slots,必须包含此宏

public:
    // ============================================================
    // public 区域:对外公开的接口
    // ============================================================

    explicit PriceManage(QWidget *parent = 0);
    // 构造函数
    // explicit: 防止隐式类型转换
    // QWidget *parent = 0: 父窗口指针,默认值为 nullptr

    ~PriceManage();
    // 析构函数
    // 当对象被销毁时自动调用,释放资源

private slots:
    // ============================================================
    // 私有槽函数区域
    // 响应按钮点击事件
    // ============================================================

    void on_priceConfirmBtn_clicked();
    // "确认"按钮的槽函数
    // 当用户点击"确认"时被调用
    // 功能:将当前输入的价格信息保存到数据库

    void on_priceReturnBtn_clicked();
    // "返回"按钮的槽函数
    // 当用户点击"返回"时被调用
    // 功能:关闭当前价格管理窗口

private:
    // ============================================================
    // private 区域:私有的成员变量
    // 只能在类内部访问,外部不可见
    // ============================================================

    Ui::PriceManage *ui;
    // UI 对象指针
    // 指向由 uic 工具生成的 UI 类对象
    // 通过这个指针可以访问界面上所有的控件
    // 例如:ui->typeComboBox(收费类型下拉框)
    //       ui->priceLineEdit(价格输入框)
    //       ui->unitComboBox(单位下拉框)
    //       ui->priceConfirmBtn(确认按钮)
    //       ui->priceReturnBtn(返回按钮)
    //       ui->tableView(价格列表表格)

    QSqlTableModel *priceModel;
    // SQL 表格模型对象指针
    // 用于与价格表(如 price)交互
    // 提供数据的查询、显示、更新等功能
    // 通过 setTable() 指定表名
    // 通过 select() 执行查询
    // 通过 submitAll() 提交修改
};

#endif // PRICEMANAGE_H
// 结束条件编译块
// 如果头文件被重复包含,从 #ifndef 到 #endif 之间的内容会被跳过

6.pricemanage.cpp

原始版本一

cpp 复制代码
#include "pricemanage.h"
#include "ui_pricemanage.h"

/*********PriceManage类构造函数***************************************************/
PriceManage::PriceManage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::PriceManage)
{
    ui->setupUi(this);

    priceModel=new QSqlTableModel(this);    //设置model实现与数据库交互
    priceModel->setTable("price");          //与数据库"price"表建立连接
    priceModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
}
/*********PriceManage类析构函数***************************************************/
PriceManage::~PriceManage()
{
    delete ui;
}
/********《槽函数》"确认"按键处理函数*******************************************/
void PriceManage::on_priceConfirmBtn_clicked()
{
    if(ui->pmFreeLineEdit->text().isEmpty()&&ui->carStationFreeLineEdit->text().isEmpty()
            &&ui->repareFreeLineEdit->text().isEmpty())
    {
        QMessageBox::warning(this,"警告","请填写完整信息",QMessageBox::Yes);
        return;
    }
    priceModel->select();

    QSqlRecord record=priceModel->record();
    record.setValue("pmfree",ui->pmFreeLineEdit->text());
    record.setValue("carstationfree",ui->carStationFreeLineEdit->text());
    record.setValue("reparifree",ui->repareFreeLineEdit->text());

    priceModel->insertRecord(-1,record);
    if(priceModel->submitAll())
    {
        QMessageBox::information(this,"提示","价格信息修改成功",QMessageBox::Yes);
        ui->carStationFreeLineEdit->clear();
        ui->pmFreeLineEdit->clear();
        ui->repareFreeLineEdit->clear();
    }
    else
    {
        QMessageBox::information(this,"提示","价格信息修改失败,请重新输入",QMessageBox::Yes);
    }
}
/********《槽函数》"返回"按键处理函数*******************************************/
void PriceManage::on_priceReturnBtn_clicked()
{
    this->hide();
}

修复版本二

无注释版
cpp 复制代码
#include "pricemanage.h"
#include "ui_pricemanage.h"

PriceManage::PriceManage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::PriceManage)
{
    ui->setupUi(this);

    priceModel = new QSqlTableModel(this);
    priceModel->setTable("price");
    priceModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
}

PriceManage::~PriceManage()
{
    delete ui;
}

void PriceManage::on_priceConfirmBtn_clicked()
{
    if (ui->pmFreeLineEdit->text().isEmpty() &&
        ui->carStationFreeLineEdit->text().isEmpty() &&
        ui->repareFreeLineEdit->text().isEmpty()) {

        QMessageBox::warning(this, "警告", "请填写完整信息", QMessageBox::Yes);
        return;
    }

    priceModel->select();

    QSqlRecord record = priceModel->record();
    record.setValue("pmfree", ui->pmFreeLineEdit->text());
    record.setValue("carstationfree", ui->carStationFreeLineEdit->text());
    record.setValue("reparifree", ui->repareFreeLineEdit->text());

    priceModel->insertRecord(-1, record);

    if (priceModel->submitAll()) {
        QMessageBox::information(this, "提示", "价格信息修改成功", QMessageBox::Yes);
        ui->carStationFreeLineEdit->clear();
        ui->pmFreeLineEdit->clear();
        ui->repareFreeLineEdit->clear();
    } else {
        QMessageBox::information(this, "提示", "价格信息修改失败,请重新输入", QMessageBox::Yes);
    }
}

void PriceManage::on_priceReturnBtn_clicked()
{
    this->hide();
}
有注释版
cpp 复制代码
// ============================================================
// 文件:pricemanage.cpp
// 功能:价格维护界面的实现
// 说明:管理员在此设置物业费、车位费、维修费等收费标准
// ============================================================

#include "pricemanage.h"
// 包含自己的头文件声明
// 让编译器知道类 PriceManage 的结构、成员函数和成员变量

#include "ui_pricemanage.h"
// 包含由 .ui 文件生成的 UI 类头文件
// 包含了 Ui::PriceManage 类的定义,其中有所有控件的指针

// ============================================================
// 构造函数 - 初始化价格管理界面
// 参数:parent - 父窗口指针,默认 nullptr
// 当管理员点击"价格管理"时,此对象被创建
// ============================================================

PriceManage::PriceManage(QWidget *parent) :
    QWidget(parent),            // 调用父类 QWidget 的构造函数,传入父窗口指针
    ui(new Ui::PriceManage)     // 创建 UI 对象(由 Qt Designer 生成的界面类)
{
    ui->setupUi(this);
    // setupUi() 加载 .ui 文件,创建所有控件并设置布局

    // --------------------------------------------------------
    // 创建数据模型
    // --------------------------------------------------------

    priceModel = new QSqlTableModel(this);
    // 创建 SQL 表格模型,设置父对象为 this(自动内存管理)
    // 用于与价格表交互

    priceModel->setTable("price");
    // 设置要操作的数据表为 "price"(价格表)
    // 该表存储各项收费标准

    priceModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
    // 设置编辑策略为"手动提交"
    // 修改后需要调用 submitAll() 才会保存到数据库
    // 优点:可以批量修改,确认后再提交
}

// ============================================================
// 析构函数 - 释放资源
// 当窗口关闭时自动调用
// ============================================================

PriceManage::~PriceManage()
{
    delete ui;
    // 删除 UI 对象,释放界面上所有控件的内存
    // 这是必须的,因为 ui 是在构造函数中用 new 创建的
    // priceModel 不需要手动 delete,因为设置了父对象 this
}

// ============================================================
// "确认"按钮槽函数
// 当用户点击"确认"按钮时被调用
// 功能:将输入的价格信息保存到数据库
// ============================================================

void PriceManage::on_priceConfirmBtn_clicked()
{
    // --------------------------------------------------------
    // 1. 验证输入是否完整
    // --------------------------------------------------------

    if (ui->pmFreeLineEdit->text().isEmpty() &&
        ui->carStationFreeLineEdit->text().isEmpty() &&
        ui->repareFreeLineEdit->text().isEmpty()) {
        // 检查三个价格输入框是否都为空
        // ⚠️ 问题:逻辑错误!要求三个都为空才提示,应该是"任何一个为空"就提示
        // 当前逻辑:只有三个都为空时才提示,如果只填了一个或两个,不会提示

        QMessageBox::warning(this, "警告", "请填写完整信息", QMessageBox::Yes);
        // 弹出警告框提示用户
        return;
        // 退出函数
    }

    // --------------------------------------------------------
    // 2. 查询数据库,准备插入新记录
    // --------------------------------------------------------

    priceModel->select();
    // 执行查询,从数据库加载所有价格记录

    // --------------------------------------------------------
    // 3. 构建价格记录
    // --------------------------------------------------------

    QSqlRecord record = priceModel->record();
    // 获取一个空记录结构(包含所有字段,但没有数据)

    record.setValue("pmfree", ui->pmFreeLineEdit->text());
    // 设置 "pmfree" 字段(物业费价格)
    // ⚠️ 问题:字段名 "pmfree" 可能是 "property management fee" 的缩写
    // 但命名不够清晰,可读性差

    record.setValue("carstationfree", ui->carStationFreeLineEdit->text());
    // 设置 "carstationfree" 字段(车位费价格)

    record.setValue("reparifree", ui->repareFreeLineEdit->text());
    // 设置 "reparifree" 字段(维修费价格)
    // ⚠️ 问题:字段名拼写错误,"reparifree" 应该是 "repairfree"

    // --------------------------------------------------------
    // 4. 插入记录到数据库
    // --------------------------------------------------------

    priceModel->insertRecord(-1, record);
    // 插入记录到模型末尾(-1 表示追加到最后)

    if (priceModel->submitAll()) {
        // submitAll() 提交所有待处理的修改到数据库
        // 返回 true 表示提交成功

        QMessageBox::information(this, "提示", "价格信息修改成功", QMessageBox::Yes);
        // 弹出提示框告知用户操作成功

        // 清空所有输入框
        ui->carStationFreeLineEdit->clear();
        // 清空车位费输入框

        ui->pmFreeLineEdit->clear();
        // 清空物业费输入框

        ui->repareFreeLineEdit->clear();
        // 清空维修费输入框

    } else {
        // 提交失败
        QMessageBox::information(this, "提示", "价格信息修改失败,请重新输入", QMessageBox::Yes);
        // 弹出提示框告知用户操作失败
        // ⚠️ 问题:应该用 critical() 而不是 information()
        // 且没有显示具体错误信息
    }
}

// ============================================================
// "返回"按钮槽函数
// 当用户点击"返回"按钮时被调用
// 功能:关闭当前价格管理窗口
// ============================================================

void PriceManage::on_priceReturnBtn_clicked()
{
    this->hide();
    // hide() 隐藏当前窗口
    // 与 close() 的区别:
    //   hide():隐藏窗口,对象仍然存在,可以再次显示
    //   close():关闭窗口,可能销毁对象
}

6.pricemanage.ui

7.setowner.h

原始版本一

cpp 复制代码
#ifndef SETOWNER_H
#define SETOWNER_H

#include <QWidget>
#include <QSqlTableModel>


namespace Ui {
class SetOwner;
}

class SetOwner : public QWidget
{
    Q_OBJECT

public:
    explicit SetOwner(QWidget *parent = 0);
    ~SetOwner();

private:
    Ui::SetOwner *ui;
    QSqlTableModel *showOwnerTalbe;
};

#endif // SETOWNER_H

修复版本二

无注释版
cpp 复制代码
#ifndef SETOWNER_H
#define SETOWNER_H

#include <QWidget>
#include <QSqlTableModel>

namespace Ui {
class SetOwner;
}

class SetOwner : public QWidget
{
    Q_OBJECT

public:
    explicit SetOwner(QWidget *parent = 0);
    ~SetOwner();

private:
    Ui::SetOwner *ui;
    QSqlTableModel *showOwnerTalbe;
};

#endif // SETOWNER_H
有注释版
cpp 复制代码
// ============================================================
// 文件:setowner.h
// 功能:设置业主界面的头文件声明
// 说明:管理员在此为业主分配房屋、设置业主信息等
// ============================================================

#ifndef SETOWNER_H
// 作用:防止头文件被多次包含(Include Guard)
// 如果 SETOWNER_H 未定义,则定义它并包含头文件内容
// 如果已定义,则跳过整个头文件内容

#define SETOWNER_H
// 定义宏 SETOWNER_H,标记这个头文件已经被包含

// ============================================================
// 头文件包含
// ============================================================

#include <QWidget>
// 包含 QWidget 基类
// QWidget 是所有 Qt 窗口控件的基类
// 本类继承 QWidget,作为一个独立的窗口部件

#include <QSqlTableModel>
// 包含 QSqlTableModel 类
// 用于与数据库表交互,支持增删改查操作
// 本类用于显示业主列表或房屋信息等

// ============================================================
// UI 命名空间声明
// ============================================================

namespace Ui {
class SetOwner;
// 声明 UI 类
// 这个类由 Qt 的 uic 工具根据 setowner.ui 文件自动生成
// 包含了界面上所有控件的指针
}

// ============================================================
// SetOwner 类定义
// 设置业主窗口,继承自 QWidget
// 管理员在此为业主分配房屋、设置相关信息
// ============================================================

class SetOwner : public QWidget
// class SetOwner : 定义一个名为 SetOwner 的类
// public QWidget : 公有继承自 QWidget 基类
// 作为独立的窗口部件,可以嵌入到其他窗口或单独显示

{
    Q_OBJECT
    // Qt 元对象宏
    // 启用信号槽机制、运行时类型信息等 Qt 元对象功能
    // 虽然当前没有使用信号槽,但这是一个良好习惯

public:
    // ============================================================
    // public 区域:对外公开的接口
    // ============================================================

    explicit SetOwner(QWidget *parent = 0);
    // 构造函数
    // explicit: 防止隐式类型转换
    // QWidget *parent = 0: 父窗口指针,默认值为 nullptr

    ~SetOwner();
    // 析构函数
    // 当对象被销毁时自动调用,释放资源

private:
    // ============================================================
    // private 区域:私有的成员变量
    // 只能在类内部访问,外部不可见
    // ============================================================

    Ui::SetOwner *ui;
    // UI 对象指针
    // 指向由 uic 工具生成的 UI 类对象
    // 通过这个指针可以访问界面上所有的控件

    QSqlTableModel *showOwnerTalbe;
    // SQL 表格模型对象指针
    // 用于显示业主或房屋相关数据
    // ⚠️ 注意:变量名拼写错误 "Talbe" 应该是 "Table"
    // 用于与数据库表交互,显示数据到 QTableView
};

#endif // SETOWNER_H
// 结束条件编译块
// 如果头文件被重复包含,从 #ifndef 到 #endif 之间的内容会被跳过

7.setowner.cpp

原始版本一

cpp 复制代码
#include "setowner.h"
#include "ui_setowner.h"

SetOwner::SetOwner(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::SetOwner)
{
    ui->setupUi(this);
    showOwnerTalbe = new QSqlTableModel(this);
    showOwnerTalbe->setEditStrategy(QSqlTableModel::OnManualSubmit);
    showOwnerTalbe->setTable("houseowner");
    showOwnerTalbe->select();
    ui->tableView->setModel(showOwnerTalbe);
}

SetOwner::~SetOwner()
{
    delete ui;
}

修复版本二

无注释版
cpp 复制代码
#include "setowner.h"
#include "ui_setowner.h"

SetOwner::SetOwner(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::SetOwner)
{
    ui->setupUi(this);

    showOwnerTalbe = new QSqlTableModel(this);
    showOwnerTalbe->setEditStrategy(QSqlTableModel::OnManualSubmit);
    showOwnerTalbe->setTable("houseowner");
    showOwnerTalbe->select();

    ui->tableView->setModel(showOwnerTalbe);
}

SetOwner::~SetOwner()
{
    delete ui;
}
有注释版
cpp 复制代码
// ============================================================
// 文件:setowner.cpp
// 功能:设置业主界面的实现
// 说明:管理员在此查看业主列表,为业主分配房屋等
// ============================================================

#include "setowner.h"
// 包含自己的头文件声明
// 让编译器知道类 SetOwner 的结构、成员函数和成员变量

#include "ui_setowner.h"
// 包含由 .ui 文件生成的 UI 类头文件
// 包含了 Ui::SetOwner 类的定义,其中有所有控件的指针

// ============================================================
// 构造函数 - 初始化设置业主界面
// 参数:parent - 父窗口指针,默认 nullptr
// 当管理员点击"设置业主"时,此对象被创建
// ============================================================

SetOwner::SetOwner(QWidget *parent) :
    QWidget(parent),            // 调用父类 QWidget 的构造函数,传入父窗口指针
    ui(new Ui::SetOwner)        // 创建 UI 对象(由 Qt Designer 生成的界面类)
{
    ui->setupUi(this);
    // setupUi() 加载 .ui 文件,创建所有控件并设置布局

    // --------------------------------------------------------
    // 创建数据模型,显示业主列表
    // --------------------------------------------------------

    showOwnerTalbe = new QSqlTableModel(this);
    // 创建 SQL 表格模型,设置父对象为 this(自动内存管理)
    // ⚠️ 问题:变量名拼写错误 "Talbe" 应该是 "Table"

    showOwnerTalbe->setEditStrategy(QSqlTableModel::OnManualSubmit);
    // 设置编辑策略为"手动提交"
    // 修改后需要调用 submitAll() 才会保存到数据库

    showOwnerTalbe->setTable("houseowner");
    // 设置要操作的数据表为 "houseowner"(业主表)
    // 显示所有业主信息

    showOwnerTalbe->select();
    // 执行查询,从数据库加载所有业主记录

    ui->tableView->setModel(showOwnerTalbe);
    // 将数据模型设置到表格视图
    // 表格显示所有业主信息
}

// ============================================================
// 析构函数 - 释放资源
// 当窗口关闭时自动调用
// ============================================================

SetOwner::~SetOwner()
{
    delete ui;
    // 删除 UI 对象,释放界面上所有控件的内存
    // 这是必须的,因为 ui 是在构造函数中用 new 创建的
    // showOwnerTalbe 不需要手动 delete,因为设置了父对象 this
}

7.setowner.ui

8.workerfree.h

原始版本一

cpp 复制代码
#ifndef WORKERFREE_H
#define WORKERFREE_H

#include <QWidget>
#include <QSqlQueryModel>
#include <QSqlTableModel>
#include <QMessageBox>
#include <QSqlRecord>
#include <QDebug>
#include <QDateTime>
#include <QString>
#include <QButtonGroup>

namespace Ui {
class WorkerFree;
}
//员工请假类,公有继承自QWidget
//界面由UI设计师完成设计
class WorkerFree : public QWidget
{
    Q_OBJECT

public:
    explicit WorkerFree(QWidget *parent = 0);
    ~WorkerFree();

private slots:
    void on_workerFreeBtn_clicked();        //"提交"按钮槽函数
    void on_workerFreeReturnBtn_clicked();  //"返回"按钮槽函数
    void on_freeRadioButton_clicked();      //"请假"按钮槽函数
    void on_attendRadioButton_clicked();    //"出勤"按钮槽函数

private:
    Ui::WorkerFree *ui;

    QSqlTableModel *workerFreeModel;    //创建SQL表格查询模型
    QButtonGroup *freeInfoRadioGroup;   //创建组合按键对象指针

    bool judgeEmpty();  //判断员工输入是否为空
    void clearAll();    //清除员工所有输入内容
};

#endif // WORKERFREE_H

修复版本二

无注释版
cpp 复制代码
#ifndef WORKERFREE_H
#define WORKERFREE_H

#include <QWidget>
#include <QSqlQueryModel>
#include <QSqlTableModel>
#include <QMessageBox>
#include <QSqlRecord>
#include <QDebug>
#include <QDateTime>
#include <QString>
#include <QButtonGroup>

namespace Ui {
class WorkerFree;
}

class WorkerFree : public QWidget
{
    Q_OBJECT

public:
    explicit WorkerFree(QWidget *parent = 0);
    ~WorkerFree();

private slots:
    void on_workerFreeBtn_clicked();
    void on_workerFreeReturnBtn_clicked();
    void on_freeRadioButton_clicked();
    void on_attendRadioButton_clicked();

private:
    Ui::WorkerFree *ui;
    QSqlTableModel *workerFreeModel;
    QButtonGroup *freeInfoRadioGroup;

    bool judgeEmpty();
    void clearAll();
};

#endif // WORKERFREE_H
有注释版
cpp 复制代码
// ============================================================
// 文件:workerfree.h
// 功能:员工请假/考勤管理界面的头文件声明
// 说明:工作人员在此提交请假申请,管理员管理出勤状态
// ============================================================

#ifndef WORKERFREE_H
// 作用:防止头文件被多次包含(Include Guard)
// 如果 WORKERFREE_H 未定义,则定义它并包含头文件内容
// 如果已定义,则跳过整个头文件内容

#define WORKERFREE_H
// 定义宏 WORKERFREE_H,标记这个头文件已经被包含

// ============================================================
// 头文件包含
// ============================================================

#include <QWidget>
// 包含 QWidget 基类
// QWidget 是所有 Qt 窗口控件的基类
// 本类继承 QWidget,作为一个独立的窗口部件

#include <QSqlQueryModel>
// 包含 QSqlQueryModel 类(只读查询模型)
// 用于执行自定义 SQL 查询,显示结果
// 适用于不需要编辑数据的场景

#include <QSqlTableModel>
// 包含 QSqlTableModel 类(可读写表格模型)
// 用于与数据库表交互,支持增删改查操作
// 本类用于操作员工考勤相关数据表

#include <QMessageBox>
// 包含 QMessageBox 类
// 用于显示提示、警告、错误等消息框

#include <QSqlRecord>
// 包含 QSqlRecord 类
// 用于表示数据库中的一条记录(一行数据)
// 在添加或修改考勤记录时使用

#include <QDebug>
// 包含 QDebug 类
// 用于输出调试信息到控制台

#include <QDateTime>
// 包含 QDateTime 类
// 用于获取当前时间,记录请假/考勤时间

#include <QString>
// 包含 QString 类
// Qt 的字符串类,用于处理文本数据

#include <QButtonGroup>
// 包含 QButtonGroup 类
// 用于管理一组按钮,实现单选互斥效果
// 本类用于管理"请假"和"出勤"两个单选按钮

// ============================================================
// UI 命名空间声明
// ============================================================

namespace Ui {
class WorkerFree;
// 声明 UI 类
// 这个类由 Qt 的 uic 工具根据 workerfree.ui 文件自动生成
// 包含了界面上所有控件的指针
}

// ============================================================
// WorkerFree 类定义
// 员工请假/考勤管理窗口,继承自 QWidget
// 工作人员提交请假申请,管理员管理出勤状态
// ============================================================

class WorkerFree : public QWidget
// class WorkerFree : 定义一个名为 WorkerFree 的类
// public QWidget : 公有继承自 QWidget 基类
// 作为独立的窗口部件,可以嵌入到其他窗口或单独显示

{
    Q_OBJECT
    // Qt 元对象宏
    // 启用信号槽机制、运行时类型信息等 Qt 元对象功能
    // 因为类中使用了 private slots,必须包含此宏

public:
    // ============================================================
    // public 区域:对外公开的接口
    // ============================================================

    explicit WorkerFree(QWidget *parent = 0);
    // 构造函数
    // explicit: 防止隐式类型转换
    // QWidget *parent = 0: 父窗口指针,默认值为 nullptr

    ~WorkerFree();
    // 析构函数
    // 当对象被销毁时自动调用,释放资源

private slots:
    // ============================================================
    // 私有槽函数区域
    // 响应按钮点击事件
    // ============================================================

    void on_workerFreeBtn_clicked();
    // "提交"按钮的槽函数
    // 当用户点击"提交"时被调用
    // 功能:提交请假申请或出勤记录到数据库

    void on_workerFreeReturnBtn_clicked();
    // "返回"按钮的槽函数
    // 当用户点击"返回"时被调用
    // 功能:关闭当前窗口

    void on_freeRadioButton_clicked();
    // "请假"按钮的槽函数
    // 当用户点击"请假"单选按钮时被调用
    // 功能:切换到请假模式,显示请假相关选项

    void on_attendRadioButton_clicked();
    // "出勤"按钮的槽函数
    // 当用户点击"出勤"单选按钮时被调用
    // 功能:切换到出勤模式,显示出勤相关选项

private:
    // ============================================================
    // private 区域:私有的成员变量
    // 只能在类内部访问,外部不可见
    // ============================================================

    Ui::WorkerFree *ui;
    // UI 对象指针
    // 指向由 uic 工具生成的 UI 类对象
    // 通过这个指针可以访问界面上所有的控件

    QSqlTableModel *workerFreeModel;
    // SQL 表格模型对象指针
    // 用于与考勤数据表交互(如 worker_attendance 或 workerfree 表)
    // 提供数据的查询、显示、插入等功能

    QButtonGroup *freeInfoRadioGroup;
    // 状态按钮组
    // 管理"请假"和"出勤"两个单选按钮
    // 实现互斥选择,只能选一个

    // ============================================================
    // 私有辅助函数
    // ============================================================

    bool judgeEmpty();
    // 判断员工输入是否为空
    // 返回值:true - 不为空,false - 为空
    // 在提交前调用,验证输入完整性

    void clearAll();
    // 清除员工所有输入内容
    // 清空所有输入框,重置界面状态
    // 在提交成功或取消时调用
};

#endif // WORKERFREE_H
// 结束条件编译块
// 如果头文件被重复包含,从 #ifndef 到 #endif 之间的内容会被跳过

8.workerfree.cpp

原始版本一

cpp 复制代码
#include "workerfree.h"
#include "ui_workerfree.h"

/*********员工请假类WorkerFree构造函数*******************************************************/
WorkerFree::WorkerFree(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::WorkerFree)
{
    ui->setupUi(this);

    workerFreeModel=new QSqlTableModel(this);               //创建SQL表格模型对象
    workerFreeModel->setEditStrategy(QSqlTableModel::OnManualSubmit);//设置编辑模式

    freeInfoRadioGroup=new QButtonGroup(this);              //创建按键组对象
    freeInfoRadioGroup->addButton(ui->attendRadioButton,0); //添加单选按钮"出勤",序号为0
    freeInfoRadioGroup->addButton(ui->freeRadioButton,1);   //添加单选按钮"请假",序号为1
    ui->attendRadioButton->setChecked(true);                //设置默认单选按键为"出勤"

    QDateTime time = QDateTime::currentDateTime();          //获取当前系统时间
    QString str = time.toString("yyyy-MM-dd hh:mm:ss");     //格式化
    ui->freeTimeLineEdit->setText(str);                     //设置界面中"当前时间"默认内容为系统时间

    ui->freeTextLineEdit->hide();   //默认隐藏"请假事由"文本编辑行
    ui->label_3->hide();            //默认隐藏标签

}
/*********员工请假类WorkerFree析构函数*******************************************************/
WorkerFree::~WorkerFree()
{
    delete ui;
}
/*********《槽函数》"提交"按键函数*******************************************************/
void WorkerFree::on_workerFreeBtn_clicked()
{
    if(!this->judgeEmpty())             //判断员工输入是否为空
        return;
    workerFreeModel->setTable("worker");//设置连接的数据库表为"worker"
    workerFreeModel->select();          //启动查询
    int i,j=0;      //i用于设置for循环变量,j=1表示检索到员工,j=0表示为检索到员工
    for(i=0;i<workerFreeModel->rowCount();i++)
    {
        if(workerFreeModel->data(workerFreeModel->index(i,0)).toString()==  //查询表中所有行
                ui->workerNameLineEdit->text())
        {
           j=1;     //表中发现对应员工
           break;   //退出for循环
        }
        else        //表中未发现员工
            j=0;
    }
    qDebug()<<i<<workerFreeModel->rowCount();   //输出表中行数

    if(j==0)    //如果未发现员工,输出警告信息
    {
        QMessageBox::information(this,"提示","不存在此员工信息",QMessageBox::Yes);
        this->clearAll();
        return;
    }

    workerFreeModel->setTable("workerattend");  //设置连接表为"workerattend"
    QSqlRecord record=workerFreeModel->record();//获取一个空记录
    record.setValue("workernum",ui->workerNameLineEdit->text());    //workernum填充数据
    if(freeInfoRadioGroup->checkedId()==0)      //判断单选按键为"出勤"
    {
        record.setValue("workfree","出勤");     //workfree填充数据
        record.setValue("freetime",ui->freeTimeLineEdit->text());
    }
    else                                        //判断单选按键为"请假"
    {
        record.setValue("workfree","请假");     //workfree填充数据
        record.setValue("freetime",ui->freeTimeLineEdit->text());   //freetime填充数据
        record.setValue("freetext",ui->freeTextLineEdit->text());   //freetext填充数据
        record.setValue("freestatus","未批准");
    }

    workerFreeModel->insertRecord(-1,record);   //首行添加数据
    if(workerFreeModel->submitAll())            //提交数据
    {
        QMessageBox::information(this,"提示","提交成功",QMessageBox::Yes);
        this->clearAll();   //提交成功,清除所有
    }
    else
    {
        QMessageBox::information(this,"提示","提交失败",QMessageBox::Yes);
        this->clearAll();   //提交失败,清除所有
    }

}
/*********《槽函数》"返回"按键函数*******************************************************/
void WorkerFree::on_workerFreeReturnBtn_clicked()
{
    if(ui->workerNameLineEdit->text().isEmpty()&&ui->freeTimeLineEdit->text().isEmpty())
    {
        this->hide();   //判断员工输入内容为空,则直接隐藏推出
        return;
    }
    else if(QMessageBox::question(this,"提示","是否取消提交",QMessageBox::Yes|QMessageBox::No)
            ==QMessageBox::Yes)
    {
        this->hide();   //员工输入了部分内容,提示是否取消,确认之后隐藏
    }
}
/*********《槽函数》"请假"单选按键函数*******************************************************/
void WorkerFree::on_freeRadioButton_clicked()
{
    ui->freeTextLineEdit->show();   //显示请假理由行编辑器
    ui->label_3->show();            //显示提示标签
}
/*********《槽函数》"出勤"单选按键函数*******************************************************/
void WorkerFree::on_attendRadioButton_clicked()
{
    ui->freeTextLineEdit->hide();   //隐藏请假理由行编辑器
    ui->label_3->hide();            //隐藏提示标签
}
/*********判断员工输入的内容是否为空函数*************************************************/
bool WorkerFree::judgeEmpty()
{
    if(ui->workerNameLineEdit->text().isEmpty())
    {
        QMessageBox::warning(this,"警告","请填写请假人员姓名",QMessageBox::Yes);
        return false;
    }
    else
        return true;
}
/*********清除员工输入的内容函数*******************************************************/
void WorkerFree::clearAll()
{
    ui->workerNameLineEdit->clear();
    ui->freeTextLineEdit->clear();
}

修复版本二

无注释版
cpp 复制代码
#include "workerfree.h"
#include "ui_workerfree.h"

WorkerFree::WorkerFree(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::WorkerFree)
{
    ui->setupUi(this);

    workerFreeModel = new QSqlTableModel(this);
    workerFreeModel->setEditStrategy(QSqlTableModel::OnManualSubmit);

    freeInfoRadioGroup = new QButtonGroup(this);
    freeInfoRadioGroup->addButton(ui->attendRadioButton, 0);
    freeInfoRadioGroup->addButton(ui->freeRadioButton, 1);
    ui->attendRadioButton->setChecked(true);

    QDateTime time = QDateTime::currentDateTime();
    QString str = time.toString("yyyy-MM-dd hh:mm:ss");
    ui->freeTimeLineEdit->setText(str);

    ui->freeTextLineEdit->hide();
    ui->label_3->hide();
}

WorkerFree::~WorkerFree()
{
    delete ui;
}

void WorkerFree::on_workerFreeBtn_clicked()
{
    if (!this->judgeEmpty()) {
        return;
    }

    workerFreeModel->setTable("worker");
    workerFreeModel->select();

    int i, j = 0;

    for (i = 0; i < workerFreeModel->rowCount(); i++) {
        if (workerFreeModel->data(workerFreeModel->index(i, 0)).toString() ==
            ui->workerNameLineEdit->text()) {
            j = 1;
            break;
        } else {
            j = 0;
        }
    }

    qDebug() << i << workerFreeModel->rowCount();

    if (j == 0) {
        QMessageBox::information(this, "提示", "不存在此员工信息", QMessageBox::Yes);
        this->clearAll();
        return;
    }

    workerFreeModel->setTable("workerattend");

    QSqlRecord record = workerFreeModel->record();

    record.setValue("workernum", ui->workerNameLineEdit->text());

    if (freeInfoRadioGroup->checkedId() == 0) {
        record.setValue("workfree", "出勤");
        record.setValue("freetime", ui->freeTimeLineEdit->text());
    } else {
        record.setValue("workfree", "请假");
        record.setValue("freetime", ui->freeTimeLineEdit->text());
        record.setValue("freetext", ui->freeTextLineEdit->text());
        record.setValue("freestatus", "未批准");
    }

    workerFreeModel->insertRecord(-1, record);

    if (workerFreeModel->submitAll()) {
        QMessageBox::information(this, "提示", "提交成功", QMessageBox::Yes);
        this->clearAll();
    } else {
        QMessageBox::information(this, "提示", "提交失败", QMessageBox::Yes);
        this->clearAll();
    }
}

void WorkerFree::on_workerFreeReturnBtn_clicked()
{
    if (ui->workerNameLineEdit->text().isEmpty() &&
        ui->freeTimeLineEdit->text().isEmpty()) {
        this->hide();
        return;
    } else if (QMessageBox::question(this, "提示", "是否取消提交",
                                      QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
        this->hide();
    }
}

void WorkerFree::on_freeRadioButton_clicked()
{
    ui->freeTextLineEdit->show();
    ui->label_3->show();
}

void WorkerFree::on_attendRadioButton_clicked()
{
    ui->freeTextLineEdit->hide();
    ui->label_3->hide();
}

bool WorkerFree::judgeEmpty()
{
    if (ui->workerNameLineEdit->text().isEmpty()) {
        QMessageBox::warning(this, "警告", "请填写请假人员姓名", QMessageBox::Yes);
        return false;
    }
    return true;
}

void WorkerFree::clearAll()
{
    ui->workerNameLineEdit->clear();
    ui->freeTextLineEdit->clear();
}
有注释版
cpp 复制代码
// ============================================================
// 文件:workerfree.cpp
// 功能:员工请假/考勤管理界面的实现
// 说明:工作人员提交请假申请,管理员管理出勤状态
// ============================================================

#include "workerfree.h"
// 包含自己的头文件声明
// 让编译器知道类 WorkerFree 的结构、成员函数和成员变量

#include "ui_workerfree.h"
// 包含由 .ui 文件生成的 UI 类头文件
// 包含了 Ui::WorkerFree 类的定义,其中有所有控件的指针

// ============================================================
// 构造函数 - 初始化考勤管理界面
// 参数:parent - 父窗口指针,默认 nullptr
// 当用户打开考勤管理窗口时,此对象被创建
// ============================================================

WorkerFree::WorkerFree(QWidget *parent) :
    QWidget(parent),            // 调用父类 QWidget 的构造函数,传入父窗口指针
    ui(new Ui::WorkerFree)      // 创建 UI 对象(由 Qt Designer 生成的界面类)
{
    ui->setupUi(this);
    // setupUi() 加载 .ui 文件,创建所有控件并设置布局

    // --------------------------------------------------------
    // 1. 创建数据模型
    // --------------------------------------------------------

    workerFreeModel = new QSqlTableModel(this);
    // 创建 SQL 表格模型,设置父对象为 this(自动内存管理)
    // 用于与考勤数据表交互

    workerFreeModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
    // 设置编辑策略为"手动提交"
    // 修改后需要调用 submitAll() 才会保存到数据库

    // --------------------------------------------------------
    // 2. 创建按钮组(出勤/请假)
    // --------------------------------------------------------

    freeInfoRadioGroup = new QButtonGroup(this);
    // 创建按钮组,父对象为 this(自动内存管理)
    // 用于实现单选互斥

    freeInfoRadioGroup->addButton(ui->attendRadioButton, 0);
    // 将"出勤"单选按钮加入组,ID 为 0

    freeInfoRadioGroup->addButton(ui->freeRadioButton, 1);
    // 将"请假"单选按钮加入组,ID 为 1

    ui->attendRadioButton->setChecked(true);
    // 默认选中"出勤"单选按钮
    // 用户打开窗口时,默认显示出勤模式

    // --------------------------------------------------------
    // 3. 设置当前时间
    // --------------------------------------------------------

    QDateTime time = QDateTime::currentDateTime();
    // 获取当前系统时间

    QString str = time.toString("yyyy-MM-dd hh:mm:ss");
    // 将时间格式化为字符串

    ui->freeTimeLineEdit->setText(str);
    // 将当前时间显示在时间输入框中

    // --------------------------------------------------------
    // 4. 默认隐藏"请假事由"相关控件
    // --------------------------------------------------------

    ui->freeTextLineEdit->hide();
    // 默认隐藏"请假事由"文本输入框
    // 只有选择"请假"时才显示

    ui->label_3->hide();
    // 默认隐藏"事由"标签
    // 只有选择"请假"时才显示
}

// ============================================================
// 析构函数 - 释放资源
// 当窗口关闭时自动调用
// ============================================================

WorkerFree::~WorkerFree()
{
    delete ui;
    // 删除 UI 对象,释放界面上所有控件的内存
    // workerFreeModel 不需要手动 delete,因为设置了父对象 this
}

// ============================================================
// "提交"按钮槽函数
// 当用户点击"提交"按钮时被调用
// 功能:提交请假或出勤记录到数据库
// ============================================================

void WorkerFree::on_workerFreeBtn_clicked()
{
    // --------------------------------------------------------
    // 1. 验证输入
    // --------------------------------------------------------

    if (!this->judgeEmpty()) {
        // 判断员工姓名是否为空
        // 如果为空,judgeEmpty() 已弹出警告框,直接返回
        return;
    }

    // --------------------------------------------------------
    // 2. 检查员工是否存在
    // --------------------------------------------------------

    workerFreeModel->setTable("worker");
    // 切换到 "worker" 表(员工信息表)

    workerFreeModel->select();
    // 执行查询,加载所有员工数据

    int i, j = 0;
    // i:循环变量
    // j:标志位,1 表示找到员工,0 表示未找到

    for (i = 0; i < workerFreeModel->rowCount(); i++) {
        // 遍历所有行,检查员工是否存在

        if (workerFreeModel->data(workerFreeModel->index(i, 0)).toString() ==
            ui->workerNameLineEdit->text()) {
            // 如果当前行的第0列(员工姓名)与输入匹配
            j = 1;      // 找到员工
            break;      // 退出循环
        } else {
            j = 0;      // 未找到员工
        }
    }

    qDebug() << i << workerFreeModel->rowCount();
    // 输出调试信息:当前索引和总行数

    if (j == 0) {
        // 如果未找到员工
        QMessageBox::information(this, "提示", "不存在此员工信息", QMessageBox::Yes);
        // 弹出提示框
        this->clearAll();
        // 清空所有输入框
        return;
        // 退出函数
    }

    // --------------------------------------------------------
    // 3. 构建考勤记录
    // --------------------------------------------------------

    workerFreeModel->setTable("workerattend");
    // 切换到 "workerattend" 表(考勤记录表)

    QSqlRecord record = workerFreeModel->record();
    // 获取一个空记录结构

    record.setValue("workernum", ui->workerNameLineEdit->text());
    // 设置 "workernum" 字段(员工姓名)

    if (freeInfoRadioGroup->checkedId() == 0) {
        // 如果"出勤"按钮被选中

        record.setValue("workfree", "出勤");
        // 设置 "workfree" 字段为"出勤"

        record.setValue("freetime", ui->freeTimeLineEdit->text());
        // 设置 "freetime" 字段为当前时间

    } else {
        // 如果"请假"按钮被选中

        record.setValue("workfree", "请假");
        // 设置 "workfree" 字段为"请假"

        record.setValue("freetime", ui->freeTimeLineEdit->text());
        // 设置 "freetime" 字段为当前时间

        record.setValue("freetext", ui->freeTextLineEdit->text());
        // 设置 "freetext" 字段为请假事由

        record.setValue("freestatus", "未批准");
        // 设置 "freestatus" 字段为"未批准"
        // 请假需要管理员审批
    }

    // --------------------------------------------------------
    // 4. 插入记录并提交
    // --------------------------------------------------------

    workerFreeModel->insertRecord(-1, record);
    // 插入记录到模型末尾(-1 表示追加到最后)

    if (workerFreeModel->submitAll()) {
        // 提交成功
        QMessageBox::information(this, "提示", "提交成功", QMessageBox::Yes);
        // 弹出提示框
        this->clearAll();
        // 清空所有输入框
    } else {
        // 提交失败
        QMessageBox::information(this, "提示", "提交失败", QMessageBox::Yes);
        // ⚠️ 问题:应该用 critical() 而不是 information()
        // 且没有显示具体错误信息
        this->clearAll();
        // 清空所有输入框
    }
}

// ============================================================
// "返回"按钮槽函数
// 当用户点击"返回"按钮时被调用
// 功能:关闭当前窗口
// ============================================================

void WorkerFree::on_workerFreeReturnBtn_clicked()
{
    if (ui->workerNameLineEdit->text().isEmpty() &&
        ui->freeTimeLineEdit->text().isEmpty()) {
        // 如果所有输入框都为空
        this->hide();
        // 直接隐藏窗口
        return;
    } else if (QMessageBox::question(this, "提示", "是否取消提交",
                                      QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
        // 如果有输入内容,询问是否取消
        // 用户点击"是",隐藏窗口
        this->hide();
    }
    // 用户点击"否",继续编辑
}

// ============================================================
// "请假"单选按钮槽函数
// 当用户点击"请假"单选按钮时被调用
// 功能:显示请假事由输入框
// ============================================================

void WorkerFree::on_freeRadioButton_clicked()
{
    ui->freeTextLineEdit->show();
    // 显示请假事由输入框

    ui->label_3->show();
    // 显示"事由"标签
}

// ============================================================
// "出勤"单选按钮槽函数
// 当用户点击"出勤"单选按钮时被调用
// 功能:隐藏请假事由输入框
// ============================================================

void WorkerFree::on_attendRadioButton_clicked()
{
    ui->freeTextLineEdit->hide();
    // 隐藏请假事由输入框

    ui->label_3->hide();
    // 隐藏"事由"标签
}

// ============================================================
// 判断输入是否为空
// 返回值:true - 不为空,false - 为空
// ============================================================

bool WorkerFree::judgeEmpty()
{
    if (ui->workerNameLineEdit->text().isEmpty()) {
        // 如果员工姓名为空
        QMessageBox::warning(this, "警告", "请填写请假人员姓名", QMessageBox::Yes);
        // 弹出警告框
        return false;
        // 返回 false
    }
    return true;
    // 返回 true
}

// ============================================================
// 清空所有输入框
// ============================================================

void WorkerFree::clearAll()
{
    ui->workerNameLineEdit->clear();
    // 清空员工姓名输入框

    ui->freeTextLineEdit->clear();
    // 清空请假事由输入框
}

8.workerfree.ui

9.workerinfo.h

原始版本一

cpp 复制代码
#ifndef WORKERINFO_H
#define WORKERINFO_H

#include <QWidget>
#include <QDebug>
#include <QMessageBox>
#include <QSqlTableModel>
#include <QSqlRecord>
#include <QButtonGroup>
//#include "managermanage.h"

namespace Ui {
class WorkerInfo;
}
//工作人员信息添加窗口类,公有继承自QWidget类
//该添加窗口,使用UI编辑器,构建整个UI界面。
class WorkerInfo : public QWidget
{
    Q_OBJECT

public:
    explicit WorkerInfo(QWidget *parent = 0);
    ~WorkerInfo();


private slots:
    void on_AddActBtn_clicked();    //添加按键槽函数
    void on_ReturnBtn_clicked();    //返回按键槽函数

signals:
    void EmitWorkerChanged();

private:
    Ui::WorkerInfo *ui;
    QSqlTableModel *model;  //使用SQL表格模型操作数据库
    QButtonGroup *isManagerRadioGroup;//创建按键组指针

    bool judgeEmpty();  //判断用户输入的账号、密码是否为空
    void clearAll();    //清除界面用户输入的账号、密码和电话内容
};

#endif // WORKERINFO_H

修复版本二

无注释版
cpp 复制代码
#ifndef WORKERINFO_H
#define WORKERINFO_H

#include <QWidget>
#include <QDebug>
#include <QMessageBox>
#include <QSqlTableModel>
#include <QSqlRecord>
#include <QButtonGroup>

namespace Ui {
class WorkerInfo;
}

class WorkerInfo : public QWidget
{
    Q_OBJECT

public:
    explicit WorkerInfo(QWidget *parent = 0);
    ~WorkerInfo();

private slots:
    void on_AddActBtn_clicked();
    void on_ReturnBtn_clicked();

signals:
    void EmitWorkerChanged();

private:
    Ui::WorkerInfo *ui;
    QSqlTableModel *model;
    QButtonGroup *isManagerRadioGroup;

    bool judgeEmpty();
    void clearAll();
};

#endif // WORKERINFO_H
有注释版
cpp 复制代码
// ============================================================
// 文件:workerinfo.h
// 功能:工作人员信息添加界面的头文件声明
// 说明:管理员在此添加新的工作人员账号
// ============================================================

#ifndef WORKERINFO_H
// 作用:防止头文件被多次包含(Include Guard)
// 如果 WORKERINFO_H 未定义,则定义它并包含头文件内容
// 如果已定义,则跳过整个头文件内容

#define WORKERINFO_H
// 定义宏 WORKERINFO_H,标记这个头文件已经被包含

// ============================================================
// 头文件包含
// ============================================================

#include <QWidget>
// 包含 QWidget 基类
// QWidget 是所有 Qt 窗口控件的基类
// 本类继承 QWidget,作为一个独立的窗口部件

#include <QDebug>
// 包含 QDebug 类
// 用于输出调试信息到控制台

#include <QMessageBox>
// 包含 QMessageBox 类
// 用于显示提示、警告、错误等消息框

#include <QSqlTableModel>
// 包含 QSqlTableModel 类(可读写表格模型)
// 用于与数据库表交互,支持增删改查操作
// 本类用于操作工作人员数据表

#include <QSqlRecord>
// 包含 QSqlRecord 类
// 用于表示数据库中的一条记录(一行数据)
// 在添加工作人员时,用于构建新记录

#include <QButtonGroup>
// 包含 QButtonGroup 类
// 用于管理一组按钮,实现单选互斥效果
// 本类用于管理"是/否管理员"两个单选按钮

//#include "managermanage.h"
// 已注释:原本可能需要管理员管理界面的头文件
// 但当前不需要

// ============================================================
// UI 命名空间声明
// ============================================================

namespace Ui {
class WorkerInfo;
// 声明 UI 类
// 这个类由 Qt 的 uic 工具根据 workerinfo.ui 文件自动生成
// 包含了界面上所有控件的指针
}

// ============================================================
// WorkerInfo 类定义
// 工作人员信息添加窗口,继承自 QWidget
// 管理员在此添加新的工作人员账号
// ============================================================

class WorkerInfo : public QWidget
// class WorkerInfo : 定义一个名为 WorkerInfo 的类
// public QWidget : 公有继承自 QWidget 基类
// 作为独立的窗口部件,可以嵌入到其他窗口或单独显示

{
    Q_OBJECT
    // Qt 元对象宏
    // 启用信号槽机制、运行时类型信息等 Qt 元对象功能
    // 因为类中使用了 signals 和 private slots,必须包含此宏

public:
    // ============================================================
    // public 区域:对外公开的接口
    // ============================================================

    explicit WorkerInfo(QWidget *parent = 0);
    // 构造函数
    // explicit: 防止隐式类型转换
    // QWidget *parent = 0: 父窗口指针,默认值为 nullptr

    ~WorkerInfo();
    // 析构函数
    // 当对象被销毁时自动调用,释放资源

private slots:
    // ============================================================
    // 私有槽函数区域
    // 响应按钮点击事件
    // ============================================================

    void on_AddActBtn_clicked();
    // "添加"按钮的槽函数
    // 当用户点击"添加"时被调用
    // 功能:验证输入 → 检查重复 → 添加工作人员到数据库

    void on_ReturnBtn_clicked();
    // "返回"按钮的槽函数
    // 当用户点击"返回"时被调用
    // 功能:关闭当前添加窗口

signals:
    // ============================================================
    // 信号区域
    // ============================================================

    void EmitWorkerChanged();
    // 工作人员信息变更信号
    // 当工作人员信息被添加或修改时发射此信号
    // 用于通知其他模块(如工作人员管理界面)刷新数据

private:
    // ============================================================
    // private 区域:私有的成员变量
    // 只能在类内部访问,外部不可见
    // ============================================================

    Ui::WorkerInfo *ui;
    // UI 对象指针
    // 指向由 uic 工具生成的 UI 类对象
    // 通过这个指针可以访问界面上所有的控件

    QSqlTableModel *model;
    // SQL 表格模型对象指针
    // 用于与工作人员表(如 worker)交互
    // 提供数据的插入、查询等功能

    QButtonGroup *isManagerRadioGroup;
    // 管理员权限按钮组
    // 管理"是管理员"和"否管理员"两个单选按钮
    // 实现互斥选择,决定新用户是否为管理员

    // ============================================================
    // 私有辅助函数
    // ============================================================

    bool judgeEmpty();
    // 判断用户输入的账号、密码是否为空
    // 返回值:true - 都不为空,false - 至少有一个为空
    // 在添加前调用,验证输入完整性

    void clearAll();
    // 清除界面用户输入的账号、密码和电话内容
    // 清空所有输入框,重置界面状态
    // 在添加成功或取消时调用
};

#endif // WORKERINFO_H
// 结束条件编译块
// 如果头文件被重复包含,从 #ifndef 到 #endif 之间的内容会被跳过

9.workerinfo.cpp

原始版本一

cpp 复制代码
#include "workerinfo.h"
#include "ui_workerinfo.h"
/*********WorkerInfo类构造函数***********************************/
WorkerInfo::WorkerInfo(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::WorkerInfo)
{
    ui->setupUi(this);

    isManagerRadioGroup=new QButtonGroup;   //创建按键组,实现单选功能
    isManagerRadioGroup->addButton(ui->yesradioButton,0);//添加"是"按键,编号为0
    isManagerRadioGroup->addButton(ui->noradioButton,1); //添加"否"按键,编号为1
    ui->noradioButton->setChecked(true);    //设置"否"按键默认选中

    //设使用表格模型tablemodel实现与数据库交互
    model=new QSqlTableModel(this);
    //设置数据表名称为为"worker"
    model->setTable("worker");
    //设置编辑策略:数据改变先缓存,直到调用提交函数。
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    //从"第5列"开始的"5列"数据
    model->removeColumns(5,5);/*?*/
}
/*********WorkerInfo类析构造函数***********************************/
WorkerInfo::~WorkerInfo()
{
    delete ui;
}
/*********"添加"按键实现函数*************************************/
void WorkerInfo::on_AddActBtn_clicked()
{
    if(!this->judgeEmpty()) //如果账号和密码有一个为空,则直接退出。
        return;
    model->select();    //数据库查询
    int i;  //用于for循环中,测试用户输入账户与数据表中账户是否一致。
    for(i=0;i<model->rowCount();i++)
    {
        //不断查询数据库中数据,调取表中第一列账户名,与用户输入账户名进行比较
        if(model->data(model->index(i,0)).toString()==ui->worknumlineEdit->text())
        {
            break;  //发现相同账户名,结束for循环
        }
    }
    //如果发现循环次数i小于数据表中总的数据条数,说明数据表中本来就有该账户
    if(i!=model->rowCount())
    {
        //弹出提示人员存在信息窗口
        QMessageBox::information(this,"提示","该人员已经存在",QMessageBox::Yes);
        this->clearAll();   //清除窗口内容
        return; //函数返回
    }
    QSqlRecord record=model->record();  //生成一个空的字段(空数据行)
    //将ui界面用户输入的"账号"、"密码"、"电话"内容,放到该空行的
    //workernum、workerpass、workerphone里面
    record.setValue("workernum",ui->worknumlineEdit->text());
    record.setValue("workerpass",ui->workpasslineEdit->text());
    record.setValue("workerphone",ui->workphonelineEdit->text());
    if(isManagerRadioGroup->checkedId()==0) //判断单选窗口选中的按键
    {
        //判断按键编号为0,表示按下"是"按键,则设置表中workertype字段
        //内容为"是"
        record.setValue("workertype","是");
    }
    else
    {
        record.setValue("workertype","否");
    }
    model->insertRecord(-1,record); //将新行数据插入到表的第一行
    if(model->submitAll())  //提交修改数据
    {
        //创建信息窗口,显示添加成功
        QMessageBox::information(this,"提示","工作人员添加成功",QMessageBox::Yes);
        this->clearAll();   //清除用户如输入的内容,准备添加新用户
    }
}
/*********"返回"按键实现函数*************************************/
void WorkerInfo::on_ReturnBtn_clicked()
{
    //如果"账户""密码""电话"都为空,关闭时就只退出收尾即可
    if(ui->worknumlineEdit->text().isEmpty()&&ui->workpasslineEdit->text().isEmpty()&&
       ui->workphonelineEdit->text().isEmpty())
    {
        emit EmitWorkerChanged();   //发送数据改变信号。---------------实际没有使用槽函数,改进????
        this->hide();               //隐藏该窗口(关闭)
         qDebug("addworker");       //输出调试信息
        return;                     //程序返回
    }
    //如果还有用户输入的内容,创建询问窗口,让用户确认是否退出
    if(QMessageBox::question(this,"提示","尚未保存,是否退出",QMessageBox::Yes|QMessageBox::No)==QMessageBox::Yes)
    {
        //emit EmitToTeacherManage();
        this->hide();   //窗口隐藏(关闭)
    }
}
/*********判断用户输入内容是否为空函数******************************/
bool WorkerInfo::judgeEmpty()
{
    if(ui->worknumlineEdit->text().isEmpty())   //判断用户输入的"账号"内容是否为空
    {
        //内容为空,创建警告窗口,提示错误信息
        QMessageBox::warning(this,"警告","人员编号不能为空",QMessageBox::Yes);
        return false;
    }
    else if(ui->workpasslineEdit->text().isEmpty())//判断用户输入的"密码"是否为空
    {
        //内容为空,创建警告窗口,提示错误信息
        QMessageBox::warning(this,"警告","密码不能为空",QMessageBox::Yes);
        return false;
    }
    else//用户输入的"账号"和"密码"都有内容,则直接返回true
        return true;
}
/*********清除用户输入内容函数*************************************/
void WorkerInfo::clearAll()
{
    ui->worknumlineEdit->clear();   //清空用户输入的 用户名
    ui->workpasslineEdit->clear();  //清空用户输入的 登陆密码
    ui->workphonelineEdit->clear(); //清除用户输入的 电话
}

修复版本二

无注释版
cpp 复制代码
#include "workerinfo.h"
#include "ui_workerinfo.h"

WorkerInfo::WorkerInfo(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::WorkerInfo)
{
    ui->setupUi(this);

    isManagerRadioGroup = new QButtonGroup;
    isManagerRadioGroup->addButton(ui->yesradioButton, 0);
    isManagerRadioGroup->addButton(ui->noradioButton, 1);
    ui->noradioButton->setChecked(true);

    model = new QSqlTableModel(this);
    model->setTable("worker");
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->removeColumns(5, 5);
}

WorkerInfo::~WorkerInfo()
{
    delete ui;
}

void WorkerInfo::on_AddActBtn_clicked()
{
    if (!this->judgeEmpty()) {
        return;
    }

    model->select();

    int i;

    for (i = 0; i < model->rowCount(); i++) {
        if (model->data(model->index(i, 0)).toString() == ui->worknumlineEdit->text()) {
            break;
        }
    }

    if (i != model->rowCount()) {
        QMessageBox::information(this, "提示", "该人员已经存在", QMessageBox::Yes);
        this->clearAll();
        return;
    }

    QSqlRecord record = model->record();

    record.setValue("workernum", ui->worknumlineEdit->text());
    record.setValue("workerpass", ui->workpasslineEdit->text());
    record.setValue("workerphone", ui->workphonelineEdit->text());

    if (isManagerRadioGroup->checkedId() == 0) {
        record.setValue("workertype", "是");
    } else {
        record.setValue("workertype", "否");
    }

    model->insertRecord(-1, record);

    if (model->submitAll()) {
        QMessageBox::information(this, "提示", "工作人员添加成功", QMessageBox::Yes);
        this->clearAll();
    }
}

void WorkerInfo::on_ReturnBtn_clicked()
{
    if (ui->worknumlineEdit->text().isEmpty() &&
        ui->workpasslineEdit->text().isEmpty() &&
        ui->workphonelineEdit->text().isEmpty()) {

        emit EmitWorkerChanged();
        this->hide();
        qDebug("addworker");
        return;
    }

    if (QMessageBox::question(this, "提示", "尚未保存,是否退出",
                              QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
        this->hide();
    }
}

bool WorkerInfo::judgeEmpty()
{
    if (ui->worknumlineEdit->text().isEmpty()) {
        QMessageBox::warning(this, "警告", "人员编号不能为空", QMessageBox::Yes);
        return false;
    } else if (ui->workpasslineEdit->text().isEmpty()) {
        QMessageBox::warning(this, "警告", "密码不能为空", QMessageBox::Yes);
        return false;
    } else {
        return true;
    }
}

void WorkerInfo::clearAll()
{
    ui->worknumlineEdit->clear();
    ui->workpasslineEdit->clear();
    ui->workphonelineEdit->clear();
}
有注释版
cpp 复制代码
// ============================================================
// 文件:workerinfo.cpp
// 功能:工作人员信息添加界面的实现
// 说明:管理员在此添加新的工作人员账号
// ============================================================

#include "workerinfo.h"
// 包含自己的头文件声明
// 让编译器知道类 WorkerInfo 的结构、成员函数和成员变量

#include "ui_workerinfo.h"
// 包含由 .ui 文件生成的 UI 类头文件
// 包含了 Ui::WorkerInfo 类的定义,其中有所有控件的指针

// ============================================================
// 构造函数 - 初始化添加工作人员界面
// 参数:parent - 父窗口指针,默认 nullptr
// 当管理员点击"添加工作人员"时,此对象被创建
// ============================================================

WorkerInfo::WorkerInfo(QWidget *parent) :
    QWidget(parent),            // 调用父类 QWidget 的构造函数,传入父窗口指针
    ui(new Ui::WorkerInfo)      // 创建 UI 对象(由 Qt Designer 生成的界面类)
{
    ui->setupUi(this);
    // setupUi() 加载 .ui 文件,创建所有控件并设置布局

    // --------------------------------------------------------
    // 1. 创建管理员权限按钮组
    // --------------------------------------------------------

    isManagerRadioGroup = new QButtonGroup;
    // 创建按钮组对象
    // ⚠️ 问题:没有设置父对象 this,可能导致内存泄漏
    // 建议:new QButtonGroup(this)

    isManagerRadioGroup->addButton(ui->yesradioButton, 0);
    // 将"是"单选按钮加入组,ID 为 0

    isManagerRadioGroup->addButton(ui->noradioButton, 1);
    // 将"否"单选按钮加入组,ID 为 1

    ui->noradioButton->setChecked(true);
    // 默认选中"否"(普通工作人员)
    // 用户打开窗口时,默认添加普通工作人员

    // --------------------------------------------------------
    // 2. 创建数据模型
    // --------------------------------------------------------

    model = new QSqlTableModel(this);
    // 创建 SQL 表格模型,设置父对象为 this(自动内存管理)

    model->setTable("worker");
    // 设置要操作的数据表为 "worker"(工作人员表)

    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    // 设置编辑策略为"手动提交"
    // 修改后需要调用 submitAll() 才会保存到数据库

    model->removeColumns(5, 5);
    // 从第5列开始,移除5列(隐藏不需要显示的列)
    // ⚠️ 问题:注释不清晰,不确定移除了哪些列
}

// ============================================================
// 析构函数 - 释放资源
// 当窗口关闭时自动调用
// ============================================================

WorkerInfo::~WorkerInfo()
{
    delete ui;
    // 删除 UI 对象,释放界面上所有控件的内存
    // model 不需要手动 delete,因为设置了父对象 this
    // ⚠️ 问题:isManagerRadioGroup 没有父对象,可能内存泄漏
}

// ============================================================
// "添加"按钮槽函数
// 当用户点击"添加"按钮时被调用
// 功能:验证输入 → 检查重复 → 添加工作人员到数据库
// ============================================================

void WorkerInfo::on_AddActBtn_clicked()
{
    // --------------------------------------------------------
    // 1. 输入验证
    // --------------------------------------------------------

    if (!this->judgeEmpty()) {
        // 判断账号和密码是否为空
        // 如果为空,judgeEmpty() 已弹出警告框,直接返回
        return;
    }

    // --------------------------------------------------------
    // 2. 检查账号是否已存在
    // --------------------------------------------------------

    model->select();
    // 执行查询,从数据库加载所有工作人员数据

    int i;
    // 用于循环遍历,检查账号是否已存在

    for (i = 0; i < model->rowCount(); i++) {
        // 遍历所有行,检查账号是否重复

        if (model->data(model->index(i, 0)).toString() == ui->worknumlineEdit->text()) {
            // 如果当前行的第0列(账号)与输入匹配
            break;
            // 找到重复,退出循环
        }
    }

    if (i != model->rowCount()) {
        // 如果 i 不等于总行数,说明在循环中找到了重复账号(break 提前退出)
        QMessageBox::information(this, "提示", "该人员已经存在", QMessageBox::Yes);
        // 弹出提示框
        this->clearAll();
        // 清空所有输入框
        return;
        // 退出函数
    }

    // --------------------------------------------------------
    // 3. 构建工作人员记录
    // --------------------------------------------------------

    QSqlRecord record = model->record();
    // 获取一个空记录结构(包含所有字段,但没有数据)

    record.setValue("workernum", ui->worknumlineEdit->text());
    // 设置 "workernum" 字段(账号)

    record.setValue("workerpass", ui->workpasslineEdit->text());
    // 设置 "workerpass" 字段(密码)

    record.setValue("workerphone", ui->workphonelineEdit->text());
    // 设置 "workerphone" 字段(电话)

    if (isManagerRadioGroup->checkedId() == 0) {
        // 如果"是管理员"按钮被选中(ID 为 0)
        record.setValue("workertype", "是");
        // 设置 "workertype" 字段为"是"(管理员)
    } else {
        // 如果"否管理员"按钮被选中(ID 为 1)
        record.setValue("workertype", "否");
        // 设置 "workertype" 字段为"否"(普通工作人员)
    }

    // --------------------------------------------------------
    // 4. 插入记录并提交
    // --------------------------------------------------------

    model->insertRecord(-1, record);
    // 插入记录到模型末尾(-1 表示追加到最后)

    if (model->submitAll()) {
        // 提交成功
        QMessageBox::information(this, "提示", "工作人员添加成功", QMessageBox::Yes);
        // 弹出提示框
        this->clearAll();
        // 清空所有输入框,准备添加下一个
    }
    // ⚠️ 问题:提交失败时没有错误提示
}

// ============================================================
// "返回"按钮槽函数
// 当用户点击"返回"按钮时被调用
// 功能:关闭当前添加窗口
// ============================================================

void WorkerInfo::on_ReturnBtn_clicked()
{
    // --------------------------------------------------------
    // 1. 检查是否有输入内容
    // --------------------------------------------------------

    if (ui->worknumlineEdit->text().isEmpty() &&
        ui->workpasslineEdit->text().isEmpty() &&
        ui->workphonelineEdit->text().isEmpty()) {
        // 所有输入框都为空 → 直接关闭

        emit EmitWorkerChanged();
        // 发射信号(通知其他模块数据已变更)
        // ⚠️ 问题:信号可能未被连接

        this->hide();
        // 隐藏窗口

        qDebug("addworker");
        // 输出调试信息

        return;
        // 退出函数
    }

    // --------------------------------------------------------
    // 2. 有输入内容 → 询问是否保存
    // --------------------------------------------------------

    if (QMessageBox::question(this, "提示", "尚未保存,是否退出",
                              QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
        // 用户选择"是" → 放弃修改并退出
        // emit EmitToTeacherManage();  // 已注释
        this->hide();
        // 隐藏窗口
    }
    // 用户选择"否" → 什么都不做,继续编辑
}

// ============================================================
// 判断输入是否为空
// 返回值:true - 都不为空,false - 至少有一个为空
// ============================================================

bool WorkerInfo::judgeEmpty()
{
    if (ui->worknumlineEdit->text().isEmpty()) {
        // 如果账号为空
        QMessageBox::warning(this, "警告", "人员编号不能为空", QMessageBox::Yes);
        // 弹出警告框
        return false;
        // 返回 false
    } else if (ui->workpasslineEdit->text().isEmpty()) {
        // 如果密码为空
        QMessageBox::warning(this, "警告", "密码不能为空", QMessageBox::Yes);
        // 弹出警告框
        return false;
        // 返回 false
    } else {
        // 账号和密码都不为空
        return true;
        // 返回 true
    }
}

// ============================================================
// 清空所有输入框
// ============================================================

void WorkerInfo::clearAll()
{
    ui->worknumlineEdit->clear();
    // 清空账号输入框

    ui->workpasslineEdit->clear();
    // 清空密码输入框

    ui->workphonelineEdit->clear();
    // 清空电话输入框
}

9.workerinfo.ui

10.workermanage.h

原始版本一

cpp 复制代码
#ifndef WORKERMANAGE_H
#define WORKERMANAGE_H

#include <QMainWindow>
#include <QTableView>
#include <QSqlTableModel>
#include <QLabel>
#include <QDebug>
#include <QSqlError>
#include <QString>
#include "ownerinfo.h"
#include "houseinfo.h"
#include "carstationinfo.h"
#include "workerfree.h"
#include "setowner.h"
#include "pricemanage.h"
#include "paymanage.h"

namespace Ui {
class WorkerManage;
}
//工作人员工作窗口类,公有继承自QMainWindow类
//工作加窗口,使用UI编辑器,构建整个UI界面。
class WorkerManage : public QMainWindow
{
    Q_OBJECT

public:
    explicit WorkerManage(QWidget *parent = 0);
    ~WorkerManage();

private:
    Ui::WorkerManage *ui;

    QLabel *lable;              //创建标签对象的一个指针
    QTableView *workerTableView;//创建表格试图对象的一个指针
    QSqlTableModel *workerModel;//创建SQL表格模型的一个指针

    /********以下指针均为各种界面对象的指针,用于打开一个界面************/
     OwnerInfo *ownerInfo;          //创建业主登记对象的一个指针
     HouseInfo *houseInfo;          //创建房产登记对象的一个指针
     CarStationInfo *carStationInfo;//创建录入车位信息对象的一个指针
     PriceManage *pricemanage;      //创建价格维护对象的一个指针
     PayManage *paymanage;          //创建缴费对象的一个指针象指针

     WorkerFree *workFree;          //创建请假对象的一个指针
     SetOwner *owner;
     /*******************************************************************/

    /****指示用户进行的操作,不同取值含义不同,如下:*******************
     -------------------------------------------------------
     |  workerManageStatus   |          含义               |
     -------------------------------------------------------
     |         0             |        系统初次进入         |
     |         1             |     已经查询过业主信息      |
     |         2             |     已经查询过车位信息      |
     |         3             |     已经查询过故障信息      |
     |         4             |     已经创建了请假          |
     |         5             |     已经查询月度出勤信息    |
     -------------------------------------------------------
     * ****************************************************************/

    int workerManageStatus;


    void delCurRow();   //删除当前行
    void alterCurRow(); //修改当前行
    void setTableHead();//设置当前行


signals:
    //void EmitToManagerManage();
    void EmitOwnerChanged();

private slots:

    void showOwnerSlot();   //业主查询槽函数
    void addOwnerSlot();    //成员登记槽函数
    void alterOwnerSlot();  //业主修改槽函数
    void delOwnerSlot();    //删除业主槽函数
    void addHouseSlot();    //房产登记槽函数

    void showCarStationSlot();      //查看车位信息槽函数
    void addCarStationSlot();       //录入车位信息槽函数
    void alterCarStationSlot();     //修改车位信息槽函数
    void delCarStationSlot();       //删除车位信息槽函数
    void carStationRentActSlot();   //车位出租槽函数
    //void houseInfoSlot();

    void priceManageSlot(); //价格维护槽函数
    void payInfoSlot();     //缴费查询槽函数
    void paySlot();         //缴费槽函数

    void issueShowSlot();   //故障查询槽函数
    void issueRepairSlot(); //故障维修槽函数

    void freeSlot();        //请假槽函数
    void freeConfirmSlot(); //销假槽函数
    void attendSlot();      //月度出勤槽函数



    //void attendWorkerSlot();
    void refreshTableViewSlot();    //定义为空
};

#endif // WORKERMANAGE_H

修复版本二

无注释版
cpp 复制代码
#ifndef WORKERMANAGE_H
#define WORKERMANAGE_H

#include <QMainWindow>
#include <QTableView>
#include <QSqlTableModel>
#include <QLabel>
#include <QDebug>
#include <QSqlError>
#include <QString>

#include "ownerinfo.h"
#include "houseinfo.h"
#include "carstationinfo.h"
#include "workerfree.h"
#include "setowner.h"
#include "pricemanage.h"
#include "paymanage.h"

namespace Ui {
class WorkerManage;
}

class WorkerManage : public QMainWindow
{
    Q_OBJECT

public:
    explicit WorkerManage(QWidget *parent = 0);
    ~WorkerManage();

private:
    Ui::WorkerManage *ui;

    QLabel *lable;
    QTableView *workerTableView;
    QSqlTableModel *workerModel;

    OwnerInfo *ownerInfo;
    HouseInfo *houseInfo;
    CarStationInfo *carStationInfo;
    PriceManage *pricemanage;
    PayManage *paymanage;
    WorkerFree *workFree;
    SetOwner *owner;

    int workerManageStatus;

    void delCurRow();
    void alterCurRow();
    void setTableHead();

signals:
    void EmitOwnerChanged();

private slots:
    void showOwnerSlot();
    void addOwnerSlot();
    void alterOwnerSlot();
    void delOwnerSlot();
    void addHouseSlot();

    void showCarStationSlot();
    void addCarStationSlot();
    void alterCarStationSlot();
    void delCarStationSlot();
    void carStationRentActSlot();

    void priceManageSlot();
    void payInfoSlot();
    void paySlot();

    void issueShowSlot();
    void issueRepairSlot();

    void freeSlot();
    void freeConfirmSlot();
    void attendSlot();

    void refreshTableViewSlot();
};

#endif // WORKERMANAGE_H
有注释版
cpp 复制代码
// ============================================================
// 文件:workermanage.h
// 功能:工作人员管理界面的头文件声明
// 说明:工作人员登录后的主界面,包含业主管理、房产管理、
//       车位管理、缴费管理、请假管理等功能
// ============================================================

#ifndef WORKERMANAGE_H
// 作用:防止头文件被多次包含(Include Guard)

#define WORKERMANAGE_H
// 定义宏 WORKERMANAGE_H

// ============================================================
// 头文件包含
// ============================================================

#include <QMainWindow>
// 包含 QMainWindow 基类
// 提供菜单栏、工具栏、状态栏等主窗口功能

#include <QTableView>
// 包含 QTableView 类
// 用于以表格形式显示数据

#include <QSqlTableModel>
// 包含 QSqlTableModel 类
// 用于与数据库表交互,支持增删改查操作

#include <QLabel>
// 包含 QLabel 类
// 用于显示文本标签

#include <QDebug>
// 包含 QDebug 类
// 用于输出调试信息到控制台

#include <QSqlError>
// 包含 QSqlError 类
// 用于获取数据库操作失败时的错误信息

#include <QString>
// 包含 QString 类
// Qt 的字符串类

// ============================================================
// 包含其他功能模块的头文件
// ============================================================

#include "ownerinfo.h"
// 业主信息登记模块

#include "houseinfo.h"
// 房产信息登记模块

#include "carstationinfo.h"
// 车位信息录入模块

#include "workerfree.h"
// 员工请假模块

#include "setowner.h"
// 设置业主模块

#include "pricemanage.h"
// 价格维护模块

#include "paymanage.h"
// 缴费管理模块

// ============================================================
// UI 命名空间声明
// ============================================================

namespace Ui {
class WorkerManage;
// 声明 UI 类
// 这个类由 Qt 的 uic 工具根据 workermanage.ui 文件自动生成
}

// ============================================================
// WorkerManage 类定义
// 工作人员管理主窗口,继承自 QMainWindow
// 工作人员登录后的主界面
// ============================================================

class WorkerManage : public QMainWindow
// class WorkerManage : 定义一个名为 WorkerManage 的类
// public QMainWindow : 公有继承自 QMainWindow 基类

{
    Q_OBJECT
    // Qt 元对象宏
    // 启用信号槽机制、运行时类型信息等

public:
    // ============================================================
    // public 区域:对外公开的接口
    // ============================================================

    explicit WorkerManage(QWidget *parent = 0);
    // 构造函数
    // explicit: 防止隐式类型转换

    ~WorkerManage();
    // 析构函数

private:
    // ============================================================
    // private 区域:私有的成员变量
    // ============================================================

    Ui::WorkerManage *ui;
    // UI 对象指针
    // 指向由 uic 工具生成的 UI 类对象

    // ============================================================
    // 界面核心组件
    // ============================================================

    QLabel *lable;
    // 标签对象指针
    // 用于显示提示信息或状态信息

    QTableView *workerTableView;
    // 表格视图对象指针
    // 用于以表格形式显示各种数据

    QSqlTableModel *workerModel;
    // SQL 表格模型对象指针
    // 用于与数据库表交互

    // ============================================================
    // 功能模块窗口指针
    // ============================================================

    OwnerInfo *ownerInfo;
    // 业主登记窗口指针
    // 用于添加或编辑业主信息

    HouseInfo *houseInfo;
    // 房产登记窗口指针
    // 用于添加或编辑房屋信息

    CarStationInfo *carStationInfo;
    // 录入车位信息窗口指针
    // 用于添加或编辑车位信息

    PriceManage *pricemanage;
    // 价格维护窗口指针
    // 用于设置各项收费标准

    PayManage *paymanage;
    // 缴费管理窗口指针
    // 用于管理缴费记录

    WorkerFree *workFree;
    // 请假管理窗口指针
    // 用于提交请假申请

    SetOwner *owner;
    // 设置业主窗口指针
    // 用于为业主分配房屋

    // ============================================================
    // 状态标志
    // ============================================================

    int workerManageStatus;
    // 工作人员管理状态标志
    // 用于指示用户当前进行的操作
    // 
    // 取值含义:
    // 0: 系统初次进入
    // 1: 已查询过业主信息
    // 2: 已查询过车位信息
    // 3: 已查询过故障信息
    // 4: 已创建请假记录
    // 5: 已查询月度出勤信息

    // ============================================================
    // 私有辅助函数
    // ============================================================

    void delCurRow();
    // 删除当前选中的行
    // 从表格中删除当前选中的记录

    void alterCurRow();
    // 修改当前选中的行
    // 编辑当前选中的记录

    void setTableHead();
    // 设置表头
    // 设置当前表格的列标题

signals:
    // ============================================================
    // 信号区域
    // ============================================================

    //void EmitToManagerManage();
    // 已注释:原本可能用于向管理员界面发送信号

    void EmitOwnerChanged();
    // 业主信息变更信号
    // 当业主信息发生变化时发射此信号

private slots:
    // ============================================================
    // 私有槽函数区域
    // 响应菜单/按钮点击事件
    // ============================================================

    // ---------- 业主管理 ----------
    void showOwnerSlot();
    // 业主查询槽函数
    // 显示所有业主信息

    void addOwnerSlot();
    // 业主登记槽函数
    // 打开业主登记窗口

    void alterOwnerSlot();
    // 业主修改槽函数
    // 修改当前选中的业主信息

    void delOwnerSlot();
    // 删除业主槽函数
    // 删除当前选中的业主

    // ---------- 房产管理 ----------
    void addHouseSlot();
    // 房产登记槽函数
    // 打开房产登记窗口

    // ---------- 车位管理 ----------
    void showCarStationSlot();
    // 查看车位信息槽函数
    // 显示所有车位信息

    void addCarStationSlot();
    // 录入车位信息槽函数
    // 打开录入车位信息窗口

    void alterCarStationSlot();
    // 修改车位信息槽函数
    // 修改当前选中的车位信息

    void delCarStationSlot();
    // 删除车位信息槽函数
    // 删除当前选中的车位

    void carStationRentActSlot();
    // 车位出租槽函数
    // 将车位出租给业主

    // ---------- 缴费管理 ----------
    void priceManageSlot();
    // 价格维护槽函数
    // 打开价格维护窗口

    void payInfoSlot();
    // 缴费查询槽函数
    // 显示所有缴费记录

    void paySlot();
    // 缴费槽函数
    // 执行缴费操作

    // ---------- 故障管理 ----------
    void issueShowSlot();
    // 故障查询槽函数
    // 显示所有故障报修记录

    void issueRepairSlot();
    // 故障维修槽函数
    // 处理故障维修

    // ---------- 考勤管理 ----------
    void freeSlot();
    // 请假槽函数
    // 打开请假申请窗口

    void freeConfirmSlot();
    // 销假槽函数
    // 确认请假结束

    void attendSlot();
    // 月度出勤槽函数
    // 查看月度出勤统计

    // ---------- 其他 ----------
    void refreshTableViewSlot();
    // 刷新表格视图槽函数
    // 定义为空,待实现
};

#endif // WORKERMANAGE_H
// 结束条件编译块

10.workermanage.cpp

原始版本一

cpp 复制代码
#include "workermanage.h"
#include "ui_workermanage.h"

/*********:WorkerManage类构造函数***********************************/
WorkerManage::WorkerManage(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::WorkerManage)
{
    ui->setupUi(this);
    ui->toolBar->setIconSize(QSize(50,50)); //设置工具栏图标的大小


    lable=new QLabel;           //新建标签对象赋值给指针
    setCentralWidget(lable);    //设置该指针为窗口中心部件

    //该标签用于在主窗口显示一个图片,但实际运行不起来....................................................问题是??
    QImage *img=new QImage;                     //创建图像编辑对象的一个指针
    img->load("/image/show.png");               //载入本地图像文件
    lable->clear();                             //清空标签
    lable->setPixmap(QPixmap::fromImage(*img)); //先转换图片为像素图,然后加载图像到Label标签
    lable->show();                              //显示标签


    workerTableView=new QTableView;     //新建表格视图对象赋值给指针
    setCentralWidget(workerTableView);  //设置表格视图为中心部件

    workerModel=new QSqlTableModel(this);                           //创建表格模型对象的一个指针,指向默认数据库
    workerModel->setEditStrategy(QSqlTableModel::OnManualSubmit);   //设置SQL表格模型编辑策略:数据改变先缓存,直到调用提交

    //owner=new SetOwner;
    //setCentralWidget(owner);

    workerManageStatus=0;   //标定1,表示第一次进入系统
    connect(ui->showOwnerAct, SIGNAL(triggered()), this, SLOT(showOwnerSlot()));    //"业主查询"按键的"点击信号"与业主查询槽函数连接
    connect(ui->addOwnerAct, SIGNAL(triggered()), this, SLOT(addOwnerSlot()));      //"成员登记"按键的"点击信号"与成员登记槽函数连接
    connect(ui->alterOwnerAct,SIGNAL(triggered(bool)),this,SLOT(alterOwnerSlot())); //"业主修改"按键的"点击信号"与业主修改槽函数连接
    connect(ui->delOwnerAct, SIGNAL(triggered()), this, SLOT(delOwnerSlot()));      //"删除业主"按键的"点击信号"与删除业主槽函数连接
    connect(ui->addHouseAct, SIGNAL(triggered()), this, SLOT(addHouseSlot()));      //"房产登记"按键的"点击信号"与房产等级槽函数连接

    connect(ui->showCarStationAct, SIGNAL(triggered()), this, SLOT(showCarStationSlot()));  //"查看车位信息"按键的"点击信息"与查看车位信息槽函数连接
    connect(ui->addCarStationAct,SIGNAL(triggered()),this,SLOT(addCarStationSlot()));       //"录入车位信息"按键的"点击信息"与录入车位信息槽函数连接
    connect(ui->alterCarStationAct,SIGNAL(triggered()),this,SLOT(alterCarStationSlot()));   //"修改车位信息"按键的"点击信息"与修改车位信息槽函数连接
    connect(ui->delCarStationAct,SIGNAL(triggered()),this,SLOT(delCarStationSlot()));       //"删除车位信息"按键的"点击信息"与删除车位信息槽函数连接
    connect(ui->carStationRenAct, SIGNAL(triggered()), this, SLOT(carStationRentActSlot()));
    //connect(ui->houseInfoAct, SIGNAL(triggered()), this, SLOT(houseInfoSlot()));

    connect(ui->priceManageAct, SIGNAL(triggered()), this, SLOT(priceManageSlot()));//"价格维护"按键的"点击信息"与价格维护槽函数连接
    connect(ui->payInfoAct, SIGNAL(triggered()), this, SLOT(payInfoSlot()));        //"缴费查询"按键的"点击信息"与缴费查询槽函数连接
    connect(ui->payAct, SIGNAL(triggered()), this, SLOT(paySlot()));                //"缴费"按键的"点击信息"与缴费槽函数连接

    connect(ui->issueShowAct,SIGNAL(triggered(bool)),this,SLOT(issueShowSlot()));    //"故障查询"按键的"点击信息"与故障查询槽函数连接
    connect(ui->issueRepairAct,SIGNAL(triggered(bool)),this,SLOT(issueRepairSlot()));//"故障维修"按键的"点击信息"与故障维修槽函数连接


    connect(ui->freeAct, SIGNAL(triggered()), this, SLOT(freeSlot()));              //"请假"按键的"点击信息"与请假槽函数连接
    connect(ui->freeConfirmAct, SIGNAL(triggered()), this, SLOT(freeConfirmSlot()));//"销假"按键的"点击信息"与销假槽函数连接
    connect(ui->attendAct, SIGNAL(triggered()), this, SLOT(attendSlot()));          //"月度出勤"按键的"点击信息"与月度出勤槽函数连接

    //connect(this,SIGNAL(EmitWorkerChanged()),this,SLOT(refreshTableViewSlot()));
    //connect(workerInfo,SIGNAL(EmitWorkerChanged()),this,SLOT(refreshTableViewSlot()));


}

WorkerManage::~WorkerManage()
{
    delete ui;
}
/*********《槽函数》业主查询函数***********************************/
void WorkerManage::showOwnerSlot()
{
    workerManageStatus=1;   //标定1,业主查询动作已经完成
    workerModel->setTable("houseowner");                        //设置查询的表格为"houseowner"

    workerModel->setHeaderData(0,Qt::Horizontal,tr("业主姓名"));//设置显示的0号字段,最左边位置
    workerModel->setHeaderData(1,Qt::Horizontal,tr("业主密码"));
    workerModel->setHeaderData(2,Qt::Horizontal,tr("地址"));
    workerModel->setHeaderData(3,Qt::Horizontal,tr("电话"));
    workerModel->select();                                      //进行数据查询
    workerTableView->setModel(workerModel);                     //数据显示
}
/*********《槽函数》业主信息登记函数***********************************/
void WorkerManage::addOwnerSlot()
{
    if(workerManageStatus==1)   //如果已经查询过业主信息,则允许登记成员
    {
        ownerInfo=new OwnerInfo;//创建业主信息登记对象
        ownerInfo->show();      //显示登记界面
    }
}
/*********《槽函数》业主修改函数***********************************/
void WorkerManage::alterOwnerSlot()
{
    if(workerManageStatus==1)//如果已经查询过业主信息,则允许修改成员
    {
        alterCurRow();       //修改当前行数据
    }
}
/*********《槽函数》删除业主函数***********************************/
void WorkerManage::delOwnerSlot()
{
    if(workerManageStatus==1)//如果已经查询过业主信息,则允许删除成员
    {
        delCurRow();         //删除当前行数据
    }
}
/*********《槽函数》房产登记函数***********************************/
void WorkerManage::addHouseSlot()
{
    houseInfo=new HouseInfo;    //创建房产信息对象
    houseInfo->show();          //显示房产登记界面
}
/*********《槽函数》查看车位信息函数***********************************/
void WorkerManage::showCarStationSlot()
{
    workerManageStatus=2;   //标定2,表示已经查询过车位信息

    workerModel->setTable("carstation");                        //设置查询的表格为"carstation"
    workerModel->select();                                      //进行数据查询
    workerModel->setHeaderData(0,Qt::Horizontal,tr("车位号"));  //设置显示的0号字段,最左边位置
    workerModel->setHeaderData(1,Qt::Horizontal,tr("地上/地下"));
    workerModel->setHeaderData(2,Qt::Horizontal,tr("大/小"));
    workerModel->setHeaderData(3,Qt::Horizontal,tr("能否充电"));
    workerModel->setHeaderData(4,Qt::Horizontal,tr("所属业主"));
    workerModel->setHeaderData(5,Qt::Horizontal,tr("缴费状态"));
    workerTableView->setModel(workerModel);
}

/*********《槽函数》录入车位信息********************************/
void WorkerManage::addCarStationSlot()
{
    if(workerManageStatus==2)   //如果已经查看过车位信息
    {
        carStationInfo=new CarStationInfo;  //创建添加车位信息对象
        carStationInfo->show(); //显示窗口
    }
}
/*********《槽函数》删除车位信息********************************/
void WorkerManage::delCarStationSlot()
{
    if(workerManageStatus==2)   //如果已经查看过车位信息
    {
        delCurRow();    //删除当前行车位信息
    }
}
/*********《槽函数》修改车位信息********************************/
void WorkerManage::alterCarStationSlot()
{
    if(workerManageStatus==2)   //如果已经查看过车位信息
    {
         alterCurRow();//修改当前行
    }
}
/*********《槽函数》车位出租信息函数***********************************/
void WorkerManage::carStationRentActSlot()
{
    if(workerManageStatus == 2) //如果车位信息已经查询显示过了
    {
        workerModel->setTable("carstation");         //设置查询的表格为"carstation"
        workerModel->setFilter("ownername is null ");//设置过滤器,如果"ownername"字段为空,说明没人租,则显示
        workerModel->select();                       //数据查询
        workerTableView->setModel(workerModel);      //显示出局
    }
}

/*********《槽函数》价格维护函数***********************************/
void WorkerManage::priceManageSlot()
{
    pricemanage=new PriceManage;    //创建价格维护对象
    pricemanage->show();            //显示
}
/*********《槽函数》缴费查询函数***********************************/
void WorkerManage::payInfoSlot()
{
    workerModel->setTable("priceRecord");   //设置查询的表格为"priceRecord"
    workerModel->select();
    workerModel->setHeaderData(0,Qt::Horizontal,tr("缴费人"));
    workerModel->setHeaderData(1,Qt::Horizontal,tr("缴费类型"));
    workerModel->setHeaderData(2,Qt::Horizontal,tr("缴费金额"));
    workerModel->setHeaderData(3,Qt::Horizontal,tr("缴费时间"));
    workerTableView->setModel(workerModel);
}
/*********《槽函数》缴费函数***********************************/
void WorkerManage::paySlot()
{
    paymanage=new PayManage;
    paymanage->show();
}
/*********《槽函数》故障查询函数********************************/
void WorkerManage::issueShowSlot()
{
    workerManageStatus=3;   //标记3,表示已查询过故障信息
    workerModel->setTable("errorinfo"); //设置查询的表格为"errorinfo"
    workerModel->select();
    workerModel->setHeaderData(0,Qt::Horizontal,tr("故障编号"));
    workerModel->setHeaderData(1,Qt::Horizontal,tr("报修人"));
    workerModel->setHeaderData(2,Qt::Horizontal,tr("故障信息"));
    workerModel->setHeaderData(3,Qt::Horizontal,tr("报修时间"));
    workerModel->setHeaderData(4,Qt::Horizontal,tr("报修状态"));
    workerModel->setHeaderData(5,Qt::Horizontal,tr("处理时间"));
    workerTableView->setModel(workerModel);
}
/*********《槽函数》故障维修函数********************************/
void WorkerManage::issueRepairSlot()
{
    if(workerManageStatus==3)//如果已经查询了故障信息
    {
        alterCurRow();  //修改当前行
    }
}
/*********《槽函数》请假函数********************************/
void WorkerManage::freeSlot()
{
    workerManageStatus=4;   //标记4,表示已经创建请假
    workFree=new WorkerFree;//创建请假对象
    workFree->show();       //显示
}
/*********《槽函数》请假审批函数********************************/
void WorkerManage::freeConfirmSlot()
{
    if(workerManageStatus==4)   //如果已创建请假
    {
        QString name = this->windowTitle();
        workerModel->setTable("workerattend");
        workerModel->setFilter(QString("worknum= '%1'and freeact ='未销假'").arg(name));
        setTableHead(); //设置SQL表格模型字段并显示
    }
}
/*********《槽函数》月度出勤函数********************************/
void WorkerManage::attendSlot()
{
    workerManageStatus=5;//标记5,表示已查看月度出勤
    QString name = this->windowTitle();

    workerModel->setTable("workerattend");
    workerModel->setFilter(QString("workernum= '%1'").arg(name));
    setTableHead(); //设置SQL表格模型字段并显示
}
/*********《槽函数》刷新视图函数,未使用************************/
void WorkerManage::refreshTableViewSlot()
{

}

/*********删除当前行数据函数***********************************/
void WorkerManage::delCurRow()
{  
    int curRow=workerTableView->currentIndex().row();   //获取当前鼠标行
    workerModel->removeRow(curRow);                     //删除当前行
    int ok=QMessageBox::warning(this,tr("删除当前信息") //显示警告信息窗口
                                ,tr("你确定删除此信息吗?"),QMessageBox::Yes,QMessageBox::No);
    if(ok==QMessageBox::No)       //如果点击"No"按键
    {
        workerModel->revertAll(); //恢复数据
    }
    else                          //如果点击"Yes"按键
    {
        workerModel->submitAll(); //提交数据
    }
}
/*********修改当前行数据函数***********************************/
void WorkerManage::alterCurRow()
{
    workerModel->database().transaction();  //启动并判断是否支持事务
    if(workerModel->submitAll())            //提交所有数据到缓存
    {
        workerModel->database().commit();   //正式提交数据到数据库
    }
    else    //提交失败
    {
        workerModel->database().rollback();//数据回滚
        //创建警告信息窗口,并输出信息
        QMessageBox::warning(this,tr("tabalModel"),
                             tr("数据库错误:% 1").arg(workerModel->lastError().text()));
    }
}
/*********设置表格模型的字段函数***********************************/
void WorkerManage::setTableHead()
{
    workerModel->setHeaderData(0,Qt::Horizontal,tr("员工账号"));
    workerModel->setHeaderData(1,Qt::Horizontal,tr("请假/出勤"));
    workerModel->setHeaderData(2,Qt::Horizontal,tr("请假/出勤时间"));
    workerModel->setHeaderData(3,Qt::Horizontal,tr("请假理由"));
    workerModel->setHeaderData(4,Qt::Horizontal,tr("是否销假"));
    workerModel->setHeaderData(5,Qt::Horizontal,tr("销假时间"));
    workerModel->setHeaderData(6,Qt::Horizontal,tr("是否批准"));
    workerModel->select();
    workerTableView->setModel(workerModel);
}

修复版本二

无注释版
cpp 复制代码
#include "workermanage.h"
#include "ui_workermanage.h"

WorkerManage::WorkerManage(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::WorkerManage)
{
    ui->setupUi(this);
    ui->toolBar->setIconSize(QSize(50, 50));

    lable = new QLabel;
    setCentralWidget(lable);

    QImage *img = new QImage;
    img->load("/image/show.png");
    lable->clear();
    lable->setPixmap(QPixmap::fromImage(*img));
    lable->show();

    workerTableView = new QTableView;
    setCentralWidget(workerTableView);

    workerModel = new QSqlTableModel(this);
    workerModel->setEditStrategy(QSqlTableModel::OnManualSubmit);

    workerManageStatus = 0;

    connect(ui->showOwnerAct, SIGNAL(triggered()), this, SLOT(showOwnerSlot()));
    connect(ui->addOwnerAct, SIGNAL(triggered()), this, SLOT(addOwnerSlot()));
    connect(ui->alterOwnerAct, SIGNAL(triggered(bool)), this, SLOT(alterOwnerSlot()));
    connect(ui->delOwnerAct, SIGNAL(triggered()), this, SLOT(delOwnerSlot()));
    connect(ui->addHouseAct, SIGNAL(triggered()), this, SLOT(addHouseSlot()));

    connect(ui->showCarStationAct, SIGNAL(triggered()), this, SLOT(showCarStationSlot()));
    connect(ui->addCarStationAct, SIGNAL(triggered()), this, SLOT(addCarStationSlot()));
    connect(ui->alterCarStationAct, SIGNAL(triggered()), this, SLOT(alterCarStationSlot()));
    connect(ui->delCarStationAct, SIGNAL(triggered()), this, SLOT(delCarStationSlot()));
    connect(ui->carStationRenAct, SIGNAL(triggered()), this, SLOT(carStationRentActSlot()));

    connect(ui->priceManageAct, SIGNAL(triggered()), this, SLOT(priceManageSlot()));
    connect(ui->payInfoAct, SIGNAL(triggered()), this, SLOT(payInfoSlot()));
    connect(ui->payAct, SIGNAL(triggered()), this, SLOT(paySlot()));

    connect(ui->issueShowAct, SIGNAL(triggered(bool)), this, SLOT(issueShowSlot()));
    connect(ui->issueRepairAct, SIGNAL(triggered(bool)), this, SLOT(issueRepairSlot()));

    connect(ui->freeAct, SIGNAL(triggered()), this, SLOT(freeSlot()));
    connect(ui->freeConfirmAct, SIGNAL(triggered()), this, SLOT(freeConfirmSlot()));
    connect(ui->attendAct, SIGNAL(triggered()), this, SLOT(attendSlot()));
}

WorkerManage::~WorkerManage()
{
    delete ui;
}

void WorkerManage::showOwnerSlot()
{
    workerManageStatus = 1;

    workerModel->setTable("houseowner");
    workerModel->setHeaderData(0, Qt::Horizontal, tr("业主姓名"));
    workerModel->setHeaderData(1, Qt::Horizontal, tr("业主密码"));
    workerModel->setHeaderData(2, Qt::Horizontal, tr("地址"));
    workerModel->setHeaderData(3, Qt::Horizontal, tr("电话"));
    workerModel->select();
    workerTableView->setModel(workerModel);
}

void WorkerManage::addOwnerSlot()
{
    if (workerManageStatus == 1) {
        ownerInfo = new OwnerInfo;
        ownerInfo->show();
    }
}

void WorkerManage::alterOwnerSlot()
{
    if (workerManageStatus == 1) {
        alterCurRow();
    }
}

void WorkerManage::delOwnerSlot()
{
    if (workerManageStatus == 1) {
        delCurRow();
    }
}

void WorkerManage::addHouseSlot()
{
    houseInfo = new HouseInfo;
    houseInfo->show();
}

void WorkerManage::showCarStationSlot()
{
    workerManageStatus = 2;

    workerModel->setTable("carstation");
    workerModel->select();
    workerModel->setHeaderData(0, Qt::Horizontal, tr("车位号"));
    workerModel->setHeaderData(1, Qt::Horizontal, tr("地上/地下"));
    workerModel->setHeaderData(2, Qt::Horizontal, tr("大/小"));
    workerModel->setHeaderData(3, Qt::Horizontal, tr("能否充电"));
    workerModel->setHeaderData(4, Qt::Horizontal, tr("所属业主"));
    workerModel->setHeaderData(5, Qt::Horizontal, tr("缴费状态"));

    workerTableView->setModel(workerModel);
}

void WorkerManage::addCarStationSlot()
{
    if (workerManageStatus == 2) {
        carStationInfo = new CarStationInfo;
        carStationInfo->show();
    }
}

void WorkerManage::delCarStationSlot()
{
    if (workerManageStatus == 2) {
        delCurRow();
    }
}

void WorkerManage::alterCarStationSlot()
{
    if (workerManageStatus == 2) {
        alterCurRow();
    }
}

void WorkerManage::carStationRentActSlot()
{
    if (workerManageStatus == 2) {
        workerModel->setTable("carstation");
        workerModel->setFilter("ownername is null");
        workerModel->select();
        workerTableView->setModel(workerModel);
    }
}

void WorkerManage::priceManageSlot()
{
    pricemanage = new PriceManage;
    pricemanage->show();
}

void WorkerManage::payInfoSlot()
{
    workerModel->setTable("priceRecord");
    workerModel->select();
    workerModel->setHeaderData(0, Qt::Horizontal, tr("缴费人"));
    workerModel->setHeaderData(1, Qt::Horizontal, tr("缴费类型"));
    workerModel->setHeaderData(2, Qt::Horizontal, tr("缴费金额"));
    workerModel->setHeaderData(3, Qt::Horizontal, tr("缴费时间"));
    workerTableView->setModel(workerModel);
}

void WorkerManage::paySlot()
{
    paymanage = new PayManage;
    paymanage->show();
}

void WorkerManage::issueShowSlot()
{
    workerManageStatus = 3;

    workerModel->setTable("errorinfo");
    workerModel->select();
    workerModel->setHeaderData(0, Qt::Horizontal, tr("故障编号"));
    workerModel->setHeaderData(1, Qt::Horizontal, tr("报修人"));
    workerModel->setHeaderData(2, Qt::Horizontal, tr("故障信息"));
    workerModel->setHeaderData(3, Qt::Horizontal, tr("报修时间"));
    workerModel->setHeaderData(4, Qt::Horizontal, tr("报修状态"));
    workerModel->setHeaderData(5, Qt::Horizontal, tr("处理时间"));
    workerTableView->setModel(workerModel);
}

void WorkerManage::issueRepairSlot()
{
    if (workerManageStatus == 3) {
        alterCurRow();
    }
}

void WorkerManage::freeSlot()
{
    workerManageStatus = 4;

    workFree = new WorkerFree;
    workFree->show();
}

void WorkerManage::freeConfirmSlot()
{
    if (workerManageStatus == 4) {
        QString name = this->windowTitle();
        workerModel->setTable("workerattend");
        workerModel->setFilter(QString("worknum= '%1' and freeact ='未销假'").arg(name));
        setTableHead();
    }
}

void WorkerManage::attendSlot()
{
    workerManageStatus = 5;

    QString name = this->windowTitle();
    workerModel->setTable("workerattend");
    workerModel->setFilter(QString("workernum= '%1'").arg(name));
    setTableHead();
}

void WorkerManage::refreshTableViewSlot()
{

}

void WorkerManage::delCurRow()
{
    int curRow = workerTableView->currentIndex().row();
    workerModel->removeRow(curRow);

    int ok = QMessageBox::warning(this, tr("删除当前信息"),
                                  tr("你确定删除此信息吗?"),
                                  QMessageBox::Yes, QMessageBox::No);

    if (ok == QMessageBox::No) {
        workerModel->revertAll();
    } else {
        workerModel->submitAll();
    }
}

void WorkerManage::alterCurRow()
{
    workerModel->database().transaction();

    if (workerModel->submitAll()) {
        workerModel->database().commit();
    } else {
        workerModel->database().rollback();
        QMessageBox::warning(this, tr("tabalModel"),
                             tr("数据库错误:% 1").arg(workerModel->lastError().text()));
    }
}

void WorkerManage::setTableHead()
{
    workerModel->setHeaderData(0, Qt::Horizontal, tr("员工账号"));
    workerModel->setHeaderData(1, Qt::Horizontal, tr("请假/出勤"));
    workerModel->setHeaderData(2, Qt::Horizontal, tr("请假/出勤时间"));
    workerModel->setHeaderData(3, Qt::Horizontal, tr("请假理由"));
    workerModel->setHeaderData(4, Qt::Horizontal, tr("是否销假"));
    workerModel->setHeaderData(5, Qt::Horizontal, tr("销假时间"));
    workerModel->setHeaderData(6, Qt::Horizontal, tr("是否批准"));

    workerModel->select();
    workerTableView->setModel(workerModel);
}
有注释版
cpp 复制代码
// ============================================================
// 文件:workermanage.cpp
// 功能:工作人员管理界面的实现
// 说明:工作人员登录后的主界面,包含业主管理、房产管理、
//       车位管理、缴费管理、故障管理、考勤管理等功能
// ============================================================

#include "workermanage.h"
// 包含自己的头文件声明
// 让编译器知道类 WorkerManage 的结构、成员函数和成员变量

#include "ui_workermanage.h"
// 包含由 .ui 文件生成的 UI 类头文件
// 包含了 Ui::WorkerManage 类的定义,其中有所有控件的指针

// ============================================================
// 构造函数 - 初始化工作人员管理界面
// 参数:parent - 父窗口指针,默认 nullptr
// 当工作人员登录成功后,此对象被创建
// ============================================================

WorkerManage::WorkerManage(QWidget *parent) :
    QMainWindow(parent),            // 调用父类 QMainWindow 的构造函数,传入父窗口指针
    ui(new Ui::WorkerManage)        // 创建 UI 对象(由 Qt Designer 生成的界面类)
{
    ui->setupUi(this);
    // setupUi() 加载 .ui 文件,创建所有控件并设置布局

    ui->toolBar->setIconSize(QSize(50, 50));
    // 设置工具栏中图标的大小为 50x50 像素

    // --------------------------------------------------------
    // 尝试在标签中显示图片(但实际运行不起来)
    // --------------------------------------------------------

    lable = new QLabel;
    // 创建标签对象

    setCentralWidget(lable);
    // 设置标签为中心部件(临时)

    // 该标签用于在主窗口显示一个图片,但实际运行不起来
    QImage *img = new QImage;
    // 创建图像对象
    // ⚠️ 问题:没有设置父对象,可能导致内存泄漏

    img->load("/image/show.png");
    // 载入本地图像文件
    // ⚠️ 问题:路径错误,应该是相对路径或资源路径

    lable->clear();
    // 清空标签

    lable->setPixmap(QPixmap::fromImage(*img));
    // 将图像转换为像素图并设置到标签

    lable->show();
    // 显示标签

    // --------------------------------------------------------
    // 创建表格视图作为中央部件
    // --------------------------------------------------------

    workerTableView = new QTableView;
    // 创建表格视图对象

    setCentralWidget(workerTableView);
    // 设置表格视图为中心部件(覆盖了之前的标签)

    // --------------------------------------------------------
    // 创建数据模型
    // --------------------------------------------------------

    workerModel = new QSqlTableModel(this);
    // 创建 SQL 表格模型,设置父对象为 this(自动内存管理)

    workerModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
    // 设置编辑策略为"手动提交"
    // 修改后需要调用 submitAll() 才会保存到数据库

    // owner = new SetOwner;
    // setCentralWidget(owner);
    // 已注释:原本可能显示设置业主窗口

    workerManageStatus = 0;
    // 标定1,表示第一次进入系统

    // --------------------------------------------------------
    // 信号槽连接(Qt 4 旧语法)
    // 连接菜单/工具栏按钮的 triggered 信号到对应的槽函数
    // ⚠️ 问题:使用 Qt 4 旧语法,建议升级到 Qt 5 新语法
    // --------------------------------------------------------

    // ---------- 业主管理 ----------
    connect(ui->showOwnerAct, SIGNAL(triggered()), this, SLOT(showOwnerSlot()));
    // "业主查询"按键 → 业主查询槽函数

    connect(ui->addOwnerAct, SIGNAL(triggered()), this, SLOT(addOwnerSlot()));
    // "成员登记"按键 → 成员登记槽函数

    connect(ui->alterOwnerAct, SIGNAL(triggered(bool)), this, SLOT(alterOwnerSlot()));
    // "业主修改"按键 → 业主修改槽函数

    connect(ui->delOwnerAct, SIGNAL(triggered()), this, SLOT(delOwnerSlot()));
    // "删除业主"按键 → 删除业主槽函数

    connect(ui->addHouseAct, SIGNAL(triggered()), this, SLOT(addHouseSlot()));
    // "房产登记"按键 → 房产登记槽函数

    // ---------- 车位管理 ----------
    connect(ui->showCarStationAct, SIGNAL(triggered()), this, SLOT(showCarStationSlot()));
    // "查看车位信息"按键 → 查看车位信息槽函数

    connect(ui->addCarStationAct, SIGNAL(triggered()), this, SLOT(addCarStationSlot()));
    // "录入车位信息"按键 → 录入车位信息槽函数

    connect(ui->alterCarStationAct, SIGNAL(triggered()), this, SLOT(alterCarStationSlot()));
    // "修改车位信息"按键 → 修改车位信息槽函数

    connect(ui->delCarStationAct, SIGNAL(triggered()), this, SLOT(delCarStationSlot()));
    // "删除车位信息"按键 → 删除车位信息槽函数

    connect(ui->carStationRenAct, SIGNAL(triggered()), this, SLOT(carStationRentActSlot()));
    // "车位出租"按键 → 车位出租槽函数

    // ---------- 缴费管理 ----------
    connect(ui->priceManageAct, SIGNAL(triggered()), this, SLOT(priceManageSlot()));
    // "价格维护"按键 → 价格维护槽函数

    connect(ui->payInfoAct, SIGNAL(triggered()), this, SLOT(payInfoSlot()));
    // "缴费查询"按键 → 缴费查询槽函数

    connect(ui->payAct, SIGNAL(triggered()), this, SLOT(paySlot()));
    // "缴费"按键 → 缴费槽函数

    // ---------- 故障管理 ----------
    connect(ui->issueShowAct, SIGNAL(triggered(bool)), this, SLOT(issueShowSlot()));
    // "故障查询"按键 → 故障查询槽函数

    connect(ui->issueRepairAct, SIGNAL(triggered(bool)), this, SLOT(issueRepairSlot()));
    // "故障维修"按键 → 故障维修槽函数

    // ---------- 考勤管理 ----------
    connect(ui->freeAct, SIGNAL(triggered()), this, SLOT(freeSlot()));
    // "请假"按键 → 请假槽函数

    connect(ui->freeConfirmAct, SIGNAL(triggered()), this, SLOT(freeConfirmSlot()));
    // "销假"按键 → 销假槽函数

    connect(ui->attendAct, SIGNAL(triggered()), this, SLOT(attendSlot()));
    // "月度出勤"按键 → 月度出勤槽函数

    // 已注释的信号连接
    // connect(this,SIGNAL(EmitWorkerChanged()),this,SLOT(refreshTableViewSlot()));
    // connect(workerInfo,SIGNAL(EmitWorkerChanged()),this,SLOT(refreshTableViewSlot()));
}

// ============================================================
// 析构函数 - 释放资源
// ============================================================

WorkerManage::~WorkerManage()
{
    delete ui;
    // 删除 UI 对象,释放界面上所有控件的内存
    // workerModel、workerTableView 等不需要手动 delete
    // 因为设置了父对象 this 或由 Qt 对象树管理
}

// ============================================================
// 《槽函数》业主查询函数
// 功能:查询并显示所有业主信息
// ============================================================

void WorkerManage::showOwnerSlot()
{
    workerManageStatus = 1;
    // 标定1,业主查询动作已经完成

    workerModel->setTable("houseowner");
    // 设置查询的表格为 "houseowner"(业主表)

    // 设置表头显示名称
    workerModel->setHeaderData(0, Qt::Horizontal, tr("业主姓名"));
    // 第0列显示为"业主姓名"

    workerModel->setHeaderData(1, Qt::Horizontal, tr("业主密码"));
    // 第1列显示为"业主密码"

    workerModel->setHeaderData(2, Qt::Horizontal, tr("地址"));
    // 第2列显示为"地址"

    workerModel->setHeaderData(3, Qt::Horizontal, tr("电话"));
    // 第3列显示为"电话"

    workerModel->select();
    // 执行查询

    workerTableView->setModel(workerModel);
    // 将数据模型设置到表格视图
}

// ============================================================
// 《槽函数》业主信息登记函数
// 功能:打开业主信息登记窗口
// ============================================================

void WorkerManage::addOwnerSlot()
{
    if (workerManageStatus == 1) {
        // 如果已经查询过业主信息,则允许登记成员
        ownerInfo = new OwnerInfo;
        // 创建业主信息登记对象
        // ⚠️ 问题:没有设置父对象,可能导致内存泄漏

        ownerInfo->show();
        // 显示登记界面
    }
}

// ============================================================
// 《槽函数》业主修改函数
// 功能:修改当前选中的业主信息
// ============================================================

void WorkerManage::alterOwnerSlot()
{
    if (workerManageStatus == 1) {
        // 如果已经查询过业主信息,则允许修改成员
        alterCurRow();
        // 修改当前行数据
    }
}

// ============================================================
// 《槽函数》删除业主函数
// 功能:删除当前选中的业主
// ============================================================

void WorkerManage::delOwnerSlot()
{
    if (workerManageStatus == 1) {
        // 如果已经查询过业主信息,则允许删除成员
        delCurRow();
        // 删除当前行数据
    }
}

// ============================================================
// 《槽函数》房产登记函数
// 功能:打开房产信息登记窗口
// ============================================================

void WorkerManage::addHouseSlot()
{
    houseInfo = new HouseInfo;
    // 创建房产信息对象
    // ⚠️ 问题:没有设置父对象,可能导致内存泄漏

    houseInfo->show();
    // 显示房产登记界面
}

// ============================================================
// 《槽函数》查看车位信息函数
// 功能:查询并显示所有车位信息
// ============================================================

void WorkerManage::showCarStationSlot()
{
    workerManageStatus = 2;
    // 标定2,表示已经查询过车位信息

    workerModel->setTable("carstation");
    // 设置查询的表格为 "carstation"(车位表)

    workerModel->select();
    // 执行查询

    // 设置表头
    workerModel->setHeaderData(0, Qt::Horizontal, tr("车位号"));
    workerModel->setHeaderData(1, Qt::Horizontal, tr("地上/地下"));
    workerModel->setHeaderData(2, Qt::Horizontal, tr("大/小"));
    workerModel->setHeaderData(3, Qt::Horizontal, tr("能否充电"));
    workerModel->setHeaderData(4, Qt::Horizontal, tr("所属业主"));
    workerModel->setHeaderData(5, Qt::Horizontal, tr("缴费状态"));

    workerTableView->setModel(workerModel);
    // 将数据模型设置到表格视图
}

// ============================================================
// 《槽函数》录入车位信息
// 功能:打开录入车位信息窗口
// ============================================================

void WorkerManage::addCarStationSlot()
{
    if (workerManageStatus == 2) {
        // 如果已经查看过车位信息
        carStationInfo = new CarStationInfo;
        // 创建添加车位信息对象

        carStationInfo->show();
        // 显示窗口
    }
}

// ============================================================
// 《槽函数》删除车位信息
// 功能:删除当前选中的车位
// ============================================================

void WorkerManage::delCarStationSlot()
{
    if (workerManageStatus == 2) {
        // 如果已经查看过车位信息
        delCurRow();
        // 删除当前行车位信息
    }
}

// ============================================================
// 《槽函数》修改车位信息
// 功能:修改当前选中的车位信息
// ============================================================

void WorkerManage::alterCarStationSlot()
{
    if (workerManageStatus == 2) {
        // 如果已经查看过车位信息
        alterCurRow();
        // 修改当前行
    }
}

// ============================================================
// 《槽函数》车位出租信息函数
// 功能:显示空闲车位列表,用于出租
// ============================================================

void WorkerManage::carStationRentActSlot()
{
    if (workerManageStatus == 2) {
        // 如果车位信息已经查询显示过了

        workerModel->setTable("carstation");
        // 设置查询的表格为 "carstation"

        workerModel->setFilter("ownername is null");
        // 设置过滤器:只显示 "ownername" 字段为空的车位(无人租用)

        workerModel->select();
        // 执行查询

        workerTableView->setModel(workerModel);
        // 显示数据
    }
}

// ============================================================
// 《槽函数》价格维护函数
// 功能:打开价格维护窗口
// ============================================================

void WorkerManage::priceManageSlot()
{
    pricemanage = new PriceManage;
    // 创建价格维护对象
    // ⚠️ 问题:没有设置父对象,可能导致内存泄漏

    pricemanage->show();
    // 显示
}

// ============================================================
// 《槽函数》缴费查询函数
// 功能:查询并显示所有缴费记录
// ============================================================

void WorkerManage::payInfoSlot()
{
    workerModel->setTable("priceRecord");
    // 设置查询的表格为 "priceRecord"(缴费记录表)

    workerModel->select();
    // 执行查询

    // 设置表头
    workerModel->setHeaderData(0, Qt::Horizontal, tr("缴费人"));
    workerModel->setHeaderData(1, Qt::Horizontal, tr("缴费类型"));
    workerModel->setHeaderData(2, Qt::Horizontal, tr("缴费金额"));
    workerModel->setHeaderData(3, Qt::Horizontal, tr("缴费时间"));

    workerTableView->setModel(workerModel);
    // 将数据模型设置到表格视图
}

// ============================================================
// 《槽函数》缴费函数
// 功能:打开缴费管理窗口
// ============================================================

void WorkerManage::paySlot()
{
    paymanage = new PayManage;
    // 创建缴费管理对象
    // ⚠️ 问题:没有设置父对象,可能导致内存泄漏

    paymanage->show();
    // 显示
}

// ============================================================
// 《槽函数》故障查询函数
// 功能:查询并显示所有故障报修记录
// ============================================================

void WorkerManage::issueShowSlot()
{
    workerManageStatus = 3;
    // 标记3,表示已查询过故障信息

    workerModel->setTable("errorinfo");
    // 设置查询的表格为 "errorinfo"(故障信息表)

    workerModel->select();
    // 执行查询

    // 设置表头
    workerModel->setHeaderData(0, Qt::Horizontal, tr("故障编号"));
    workerModel->setHeaderData(1, Qt::Horizontal, tr("报修人"));
    workerModel->setHeaderData(2, Qt::Horizontal, tr("故障信息"));
    workerModel->setHeaderData(3, Qt::Horizontal, tr("报修时间"));
    workerModel->setHeaderData(4, Qt::Horizontal, tr("报修状态"));
    workerModel->setHeaderData(5, Qt::Horizontal, tr("处理时间"));

    workerTableView->setModel(workerModel);
    // 将数据模型设置到表格视图
}

// ============================================================
// 《槽函数》故障维修函数
// 功能:修改当前选中的故障记录(更新维修状态)
// ============================================================

void WorkerManage::issueRepairSlot()
{
    if (workerManageStatus == 3) {
        // 如果已经查询了故障信息
        alterCurRow();
        // 修改当前行
    }
}

// ============================================================
// 《槽函数》请假函数
// 功能:打开请假申请窗口
// ============================================================

void WorkerManage::freeSlot()
{
    workerManageStatus = 4;
    // 标记4,表示已经创建请假

    workFree = new WorkerFree;
    // 创建请假对象
    // ⚠️ 问题:没有设置父对象,可能导致内存泄漏

    workFree->show();
    // 显示
}

// ============================================================
// 《槽函数》请假审批函数(销假)
// 功能:查询并显示未销假的请假记录
// ============================================================

void WorkerManage::freeConfirmSlot()
{
    if (workerManageStatus == 4) {
        // 如果已创建请假

        QString name = this->windowTitle();
        // 获取当前工作人员姓名

        workerModel->setTable("workerattend");
        // 设置查询的表格为 "workerattend"(考勤表)

        workerModel->setFilter(QString("worknum= '%1' and freeact ='未销假'").arg(name));
        // 过滤条件:当前员工 + 未销假
        // ⚠️ SQL 注入风险

        setTableHead();
        // 设置表头并显示
    }
}

// ============================================================
// 《槽函数》月度出勤函数
// 功能:查询并显示当前员工的月度出勤记录
// ============================================================

void WorkerManage::attendSlot()
{
    workerManageStatus = 5;
    // 标记5,表示已查看月度出勤

    QString name = this->windowTitle();
    // 获取当前工作人员姓名

    workerModel->setTable("workerattend");
    // 设置查询的表格为 "workerattend"

    workerModel->setFilter(QString("workernum= '%1'").arg(name));
    // 过滤条件:当前员工
    // ⚠️ SQL 注入风险

    setTableHead();
    // 设置表头并显示
}

// ============================================================
// 《槽函数》刷新视图函数(未使用)
// ============================================================

void WorkerManage::refreshTableViewSlot()
{
    // 空函数,待实现
}

// ============================================================
// 删除当前行数据函数
// 功能:删除表格中当前选中的行
// ============================================================

void WorkerManage::delCurRow()
{
    int curRow = workerTableView->currentIndex().row();
    // 获取当前选中的行索引

    workerModel->removeRow(curRow);
    // 从模型中移除该行(内存操作)

    int ok = QMessageBox::warning(this, tr("删除当前信息"),
                                  tr("你确定删除此信息吗?"),
                                  QMessageBox::Yes, QMessageBox::No);
    // 弹出确认对话框

    if (ok == QMessageBox::No) {
        // 如果用户点击"否"
        workerModel->revertAll();
        // 恢复数据(撤销删除)
    } else {
        // 如果用户点击"是"
        workerModel->submitAll();
        // 提交数据到数据库(确认删除)
    }
}

// ============================================================
// 修改当前行数据函数
// 功能:提交当前表格的修改到数据库
// ============================================================

void WorkerManage::alterCurRow()
{
    workerModel->database().transaction();
    // 启动事务

    if (workerModel->submitAll()) {
        // 提交所有数据到缓存
        workerModel->database().commit();
        // 正式提交数据到数据库
    } else {
        // 提交失败
        workerModel->database().rollback();
        // 数据回滚

        QMessageBox::warning(this, tr("tabalModel"),
                             tr("数据库错误:% 1").arg(workerModel->lastError().text()));
        // 显示错误信息
        // ⚠️ 问题:标题 "tabalModel" 拼写错误,应为 "TableModel"
    }
}

// ============================================================
// 设置表格模型的字段函数
// 功能:设置考勤表的表头并显示数据
// ============================================================

void WorkerManage::setTableHead()
{
    workerModel->setHeaderData(0, Qt::Horizontal, tr("员工账号"));
    workerModel->setHeaderData(1, Qt::Horizontal, tr("请假/出勤"));
    workerModel->setHeaderData(2, Qt::Horizontal, tr("请假/出勤时间"));
    workerModel->setHeaderData(3, Qt::Horizontal, tr("请假理由"));
    workerModel->setHeaderData(4, Qt::Horizontal, tr("是否销假"));
    workerModel->setHeaderData(5, Qt::Horizontal, tr("销假时间"));
    workerModel->setHeaderData(6, Qt::Horizontal, tr("是否批准"));

    workerModel->select();
    // 执行查询

    workerTableView->setModel(workerModel);
    // 将数据模型设置到表格视图
}

10.workermanage.ui

连接数据库

在vscode里打开.dbSQLite 数据库文件

下载安装扩展

选择打开编辑器的方式为SQLite Viewer

找到数据库后还要连接数据库,即把数据库配置到正确位置

我的数据库原来在这个路径下

cpp 复制代码
D:\重要文件\资料\技术\c++\IntelligentCommunity-2

但是程序找的数据库在这个路径下

cpp 复制代码
D:\重要文件\资料\技术\c++\IntelligentCommunity-2\build\Desktop_Qt_6_10_3_MinGW_64_bit_Debug\debug\IntelligentCommunity.db

因此需要把数据库复制到该路径下

然后就有记录了

项目整体架构图

cpp 复制代码
┌─────────────────────────────────────────────────────────────────────┐
│                    IntelligentCommunity 智慧社区管理系统            │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐    │
│  │                   登录界面 (LoginDialog)                    │    │
│  │             用户名 + 密码 + 角色选择                        │    │
│  └──────────────────────┬──────────────────────────────────────┘    │
│                         │ 登录成功                                 │
│         ┌───────────────┼───────────────┐                        │
│         ▼               ▼               ▼                        │
│  ┌───────────┐  ┌───────────┐  ┌───────────┐                    │
│  │ 管理员界面 │  │ 工作人员  │  │ 业主界面  │                    │
│  │Manager    │  │ 界面      │  │Owner      │                    │
│  │Manage     │  │Worker     │  │Manage     │                    │
│  │           │  │Manage     │  │           │                    │
│  └───────────┘  └───────────┘  └───────────┘                    │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

登录界面 (LoginDialog)

运行效果图

交互流程

cpp 复制代码
用户操作:
1. 输入用户名 "123456"
2. 输入密码 "123456"
3. 选择角色 "管理员"
5. 点击 "登录"

系统响应:
- 验证用户名密码
- 检查角色权限
- 跳转到对应主界面

此为管理员界面

点击第一个图标业主管理

人事管理菜单栏可以查看/管理所有物业工作人员的账号信息

系统参数

功能 说明
系统设置 修改系统配置(如公司名称、缴费标准等)
权限管理 设置不同角色的操作权限
数据备份 备份数据库文件

下为工作人员的界面图

下位业主界面图

管理员 vs 工作人员

总结

角色 核心区别
管理员 管理整个系统,拥有所有权限
工作人员 执行具体任务,权限受限

详细对比表

对比项 管理员 工作人员
数据库标记 workertype = "是" workertype = "否"
登录角色选择 选择 "管理员" 选择 "工作人员"
看到的主界面 管理员主界面 (ManagerManage) 工作人员主界面 (WorkerManage)
可查看业主信息 ✅ 是 ⚠️ 受限
可管理工作人员 ✅ 是 ❌ 否
可添加/删除业主 ✅ 是 ❌ 否
可处理缴费 ✅ 是 ⚠️ 只能查看/收取
可分配工单 ✅ 是 ❌ 否
可查看系统参数 ✅ 是 ❌ 否
可修改权限 ✅ 是 ❌ 否
可查看所有数据 ✅ 是 ⚠️ 仅部分数据
相关推荐
夜不会漫长1 小时前
C++入门(1)
开发语言·c++·算法
Niuguangshuo2 小时前
silero-vad:超轻量级开源 VAD 实践指南
开发语言·python
哭哭啼2 小时前
JAVA服务问题诊断
java·开发语言·jvm
..Dauntless..3 小时前
【C++】继承——基类和派生类的配合
开发语言·c++·算法
程与留4 小时前
05_Qt 核心模块概览——Qt Core、Gui、Widgets、Quick 的职责划分
c++·qt
CRMEB定制开发4 小时前
2026年最值得推荐的10大开源商城系统盘点
开发语言·人工智能·开源·商城系统·小程序商城
buhuizhiyuci4 小时前
【QT-百日筑基篇】修真世界摸爬滚打多年,终于黄天不负有心人,突破炼器中期——常用控件QWight的属性
开发语言·c++·qt·gui·图形化
Littlehero_1216 小时前
QT自定义控件之热换站系统(源码开源)
开发语言·qt
meilindehuzi_a6 小时前
Python 基础语法(1):常量、变量、类型、输入输出与运算符
开发语言·python