ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

QT CS架构汽车维修系统:状态机驱动的工单生命周期管理

2026/9/10 11:48:19 拓冰建站 浏览量
QT CS架构汽车维修系统:状态机驱动的工单生命周期管理 简介本资源是一套面向计算机专业本科生的毕业设计实战项目——基于C与Qt开发的汽车4S店维修系统采用经典的Client-Server架构聚焦汽车售后服务场景中的订单管理、车辆档案、配件库存、客户关系及财务统计等核心业务流程兼顾功能性与工程规范性。压缩包共30个文件含5个cpp源码、4个h头文件、4个ui界面设计文件、4个jpg/bmp图片资源、1个SQL数据库脚本、1个Visual Studio解决方案.sln及配套工程配置文件完整呈现CS架构下客户端界面与服务端逻辑的协同实现包体仅187KB轻量易部署。已有110人学习下载资源提供可直接编译运行的完整代码工程包含登录注册、维修工单流转、车辆信息维护等六大模块目录结构清晰Qt信号槽机制与数据库交互逻辑均有良好实践是C GUI开发与毕业设计落地的典型参考范例。1. 这不是个“画界面连数据库”的毕设——QT CS架构汽车4S店维修系统本质是解决多角色协同、状态强约束与本地响应优先的业务闭环很多同学拿到“基于QT的汽车4S店维修系统”毕设题目第一反应是拖几个按钮、连个SQLite、写几条SQL再套个登录框就完事。但真实4S店维修场景远比这复杂服务顾问在前台接单时需实时查看车间工位占用状态技师在工位终端离线或弱网操作工单必须能本地缓存未同步数据财务结算前要校验配件库存、工时定价策略、保修条款三重规则所有操作还需留痕、可追溯、防误删。QT作为跨平台C框架其信号槽机制、QThread线程模型、QSqlDatabase事务控制能力恰恰能支撑这种本地强交互服务端强校验状态机驱动的CS架构落地。本系统不追求炫酷UI而聚焦于用QT原生能力实现「工单生命周期管理」——从客户进店登记、故障诊断、派工、维修执行、质检、结算到回访跟踪每个环节都对应明确的状态跃迁与权限边界。适合已掌握C基础、了解SQL语法、希望用真实业务逻辑体现工程能力的本科毕设者。2. 用QT构建CS架构核心客户端本地状态管理 服务端API契约设计CS架构在此类系统中并非简单“客户端发请求、服务端回JSON”而是要求客户端承担大量业务逻辑与状态缓存服务端专注数据一致性与规则校验。QT的QObject树、QStateMachine、QSqlRelationalTableModel等组件天然适配这一分层。2.1 客户端本地状态机建模用QStateMachine管理工单全生命周期工单状态如“待接车”→“已预检”→“待派工”→“维修中”→“待质检”→“已结算”不是字符串枚举而是有严格跃迁规则的状态节点。QT的QStateMachine提供可视化状态图定义能力避免硬编码if-else判断。// state_machine.h class RepairOrderStateMachine : public QStateMachine { Q_OBJECT public: explicit RepairOrderStateMachine(QObject *parent nullptr); enum StateType { StatePending, // 待接车 StatePreInspected, // 已预检 StateAssigned, // 待派工 StateRepairing, // 维修中 StateQualityCheck, // 待质检 StateSettled // 已结算 }; private: QState *m_statePending; QState *m_statePreInspected; QState *m_stateAssigned; QState *m_stateRepairing; QState *m_stateQualityCheck; QState *m_stateSettled; };提示状态机初始化时需调用addDefaultAnimation()并绑定QSignalTransition例如从StatePending到StatePreInspected的跃迁应监听preInspectCompleted()信号而非按钮点击事件——这确保业务逻辑与UI解耦后续测试可直接触发信号验证状态流转。2.2 服务端API契约设计RESTful接口需承载状态校验与并发控制服务端推荐使用QtNetwork模块调用非QML WebEngine需暴露以下关键接口全部采用HTTP POST JSON Body接口路径方法请求体关键字段响应成功条件并发控制机制/api/order/createPOSTcustomer_id,vehicle_vin,symptom_desc返回order_id且状态为pending无首次创建/api/order/assignPOSTorder_id,technician_id,scheduled_time状态从pending→assigned且technician_id未被其他工单占用检查technician_id在orders表中无statusrepairing记录/api/order/update_statusPOSTorder_id,new_status,operator_id新状态符合状态机跃迁规则且operator_id有该工单操作权限使用SELECT ... FOR UPDATE锁定工单行// client_network.cpp 示例安全提交状态变更 void RepairClient::submitStatusChange(int orderId, const QString newStatus, int operatorId) { QNetworkRequest request(QUrl(http://backend:8080/api/order/update_status)); request.setHeader(QNetworkRequest::ContentTypeHeader, application/json); QJsonObject json; json[order_id] orderId; json[new_status] newStatus; json[operator_id] operatorId; QNetworkReply *reply m_manager-post(request, QJsonDocument(json).toJson()); connect(reply, QNetworkReply::finished, []() { if (reply-error() QNetworkReply::NoError) { QJsonParseError parseError; QJsonDocument doc QJsonDocument::fromJson(reply-readAll(), parseError); if (parseError.error QJsonParseError::NoError doc.object()[success].toBool()) { // 更新本地状态机 m_stateMachine-postEvent(new StatusChangeEvent(orderId, newStatus)); } else { QMessageBox::warning(this, 状态更新失败, doc.object()[message].toString()); } } else { QMessageBox::critical(this, 网络错误, reply-errorString()); } reply-deleteLater(); }); }注意QNetworkAccessManager必须在主线程创建并复用避免多线程并发访问导致崩溃QJsonDocument::fromJson()后务必检查QJsonParseError生产环境JSON解析失败是高频异常点。2.3 数据库本地缓存策略QSqlRelationalTableModel 手动事务同步客户端需在断网或服务端不可用时继续操作如技师录入维修过程因此必须实现本地SQLite缓存。QT的QSqlRelationalTableModel支持外键关联显示如显示“技师姓名”而非technician_id但不自动同步服务端需手动实现本地表结构与服务端MySQL保持一致含sync_status字段pending/synced/conflict所有INSERT/UPDATE操作先写入本地SQLite标记sync_statuspending启动后台QThread定时执行同步任务查询sync_statuspending记录逐条POST至服务端成功则更新本地sync_statussynced失败则标记conflict并弹窗告警-- 本地SQLite示例表结构关键字段 CREATE TABLE repair_orders ( id INTEGER PRIMARY KEY, customer_id INTEGER, vehicle_vin TEXT, status TEXT DEFAULT pending, -- 本地状态 sync_status TEXT DEFAULT pending, -- 同步状态 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );提示QSqlRelationalTableModel::setRelation()用于绑定technician_id到technicians.name但需在QSqlRelationalTableModel::data()重载中处理NULL值否则关联字段显示为空白同步冲突解决策略建议采用“服务端时间戳决胜”即比较updated_at字段本地时间晚于服务端则覆盖否则保留服务端版本。3. QT界面层实战用QDataWidgetMapper绑定维修工单表单规避手写信号槽冗余毕设常见误区是每个输入框都connect一个槽函数导致代码臃肿且难以维护。QT的QDataWidgetMapper专为表单与模型双向绑定设计将UI控件与QSqlRelationalTableModel字段自动映射修改UI即更新模型反之亦然。3.1 构建维修工单编辑视图QDataWidgetMapper最小化代码量以“维修工单详情页”为例包含客户信息、车辆信息、故障描述、预计工时、配件清单等区域。传统做法需为每个QLineEdit写textChanged槽再调用model-setData()而QDataWidgetMapper只需3步创建QSqlRelationalTableModel并设置表名、主键调用mapper-addMapping(widget, column_index)绑定控件与列调用mapper-toFirst()或mapper-setCurrentIndex(row)定位当前记录// order_edit_dialog.cpp void OrderEditDialog::setupMapper() { m_model new QSqlRelationalTableModel(this); m_model-setTable(repair_orders); m_model-setPrimaryKey(id); // 显式指定主键避免QSqlQueryModel无法编辑 m_model-select(); // 关联技师表显示姓名 m_model-setRelation(3, QSqlRelation(technicians, id, name)); // 第4列 technician_id m_mapper new QDataWidgetMapper(this); m_mapper-setModel(m_model); m_mapper-addMapping(ui-customerNameEdit, 1); // customer_name 字段 m_mapper-addMapping(ui-vinEdit, 2); // vehicle_vin 字段 m_mapper-addMapping(ui-symptomTextEdit, 4); // symptom_desc 字段 m_mapper-addMapping(ui-estimatedHoursSpin, 5); // estimated_hours 字段 m_mapper-addMapping(ui-technicianCombo, 3); // technician_id 字段自动显示name // 绑定到当前选中的工单行 m_mapper-setCurrentIndex(m_currentOrderId - 1); // 假设ID从1开始索引从0开始 }注意QSqlRelationalTableModel的setRelation()必须在select()之前调用否则关联不生效QComboBox绑定关联字段时需调用setModelColumn()指定显示列如technicianCombo-setModelColumn(1)显示name否则显示ID数字。3.2 配件清单动态表格QTableView 自定义委托实现“配件编码→名称→单价”三级联动维修工单中“配件清单”需支持动态增删行且每行需选择配件编码下拉、自动填充名称与单价、支持数量修改。直接使用QStandardItemModel易出错推荐继承QSqlQueryModel并重载data()class PartsTableModel : public QSqlQueryModel { Q_OBJECT public: explicit PartsTableModel(QObject *parent nullptr) : QSqlQueryModel(parent) {} QVariant data(const QModelIndex index, int role Qt::DisplayRole) const override { if (role Qt::DisplayRole index.column() 1) { // 名称列 QString partCode QSqlQueryModel::data(this-index(index.row(), 0), Qt::DisplayRole).toString(); if (!partCode.isEmpty()) { // 查询配件名称实际应缓存到QHash避免频繁查询 QSqlQuery query; query.prepare(SELECT name FROM parts WHERE code ?); query.addBindValue(partCode); query.exec(); if (query.next()) return query.value(0).toString(); } } else if (role Qt::DisplayRole index.column() 2) { // 单价列 QString partCode QSqlQueryModel::data(this-index(index.row(), 0), Qt::DisplayRole).toString(); if (!partCode.isEmpty()) { QSqlQuery query; query.prepare(SELECT unit_price FROM parts WHERE code ?); query.addBindValue(partCode); query.exec(); if (query.next()) return query.value(0).toDouble(); } } return QSqlQueryModel::data(index, role); } };提示此方案将查询逻辑封装在模型内View层无需关心数据来源但需注意QSqlQueryModel不支持编辑若需用户修改数量应改用QSqlRelationalTableModel并重载setData()在其中触发配件价格重新计算。3.3 打包发布windeployqt工具链完整流程与常见报错修复毕设演示时需独立EXEQT官方windeployqt工具可自动拷贝依赖DLL但常因路径配置错误失败# 正确命令假设build目录在项目根目录下 cd build windeployqt --no-translations --no-opengl-sw --no-webkit2 --no-quick --no-webengine --no-angle --no-system-d3d-compiler --no-icu --no-virtualkeyboard --no-remoteobjects --no-serialbus --no-sql-db --no-xmlpatterns --no-qmltooling --no-linguisttools --no-uitools --no-assistant --no-designer --no-qtdiag --no-qtpaths --no-qtplugininfo --no-qtconfig --no-qtwebengine-process --no-qtwebengine-resources --no-qtwebengine-locale --no-qtwebengine-devtools --no-qtwebengine-snapshot --no-qtwebengine-printing --no-qtwebengine-pdf --no-qtwebengine-avfoundation --no-qtwebengine-coreaudio --no-qtwebengine-video --no-qtwebengine-audio --no-qtwebengine-media --no-qtwebengine-network --no-qtwebengine-storage --no-qtwebengine-cache --no-qtwebengine-cookies --no-qtwebengine-history --no-qtwebengine-bookmarks --no-qtwebengine-downloads --no-qtwebengine-forms --no-qtwebengine-geolocation --no-qtwebengine-javascript --no-qtwebengine-css --no-qtwebengine-html --no-qtwebengine-svg --no-qtwebengine-xml --no-qtwebengine-xslt --no-qtwebengine-xsl --no-qtwebengine-xpath --no-qtwebengine-dom --no-qtwebengine-cssom --no-qtwebengine-cssom-style --no-qtwebengine-cssom-style-sheet --no-qtwebengine-cssom-style-rule --no-qtwebengine-cssom-style-declaration --no-qtwebengine-cssom-style-property --no-qtwebengine-cssom-style-value --no-qtwebengine-cssom-style-text --no-qtwebengine-cssom-style-number --no-qtwebengine-cssom-style-length --no-qtwebengine-cssom-style-percentage --no-qtwebengine-cssom-style-em --no-qtwebengine-cssom-style-ex --no-qtwebengine-cssom-style-px --no-qtwebengine-cssom-style-pt --no-qtwebengine-cssom-style-pc --no-qtwebengine-cssom-style-in --no-qtwebengine-cssom-style-cm --no-qtwebengine-cssom-style-mm --no-qtwebengine-cssom-style-q --no-qtwebengine-cssom-style-rem --no-qtwebengine-cssom-style-vw --no-qtwebengine-cssom-style-vh --no-qtwebengine-cssom-style-vmin --no-qtwebengine-cssom-style-vmax --no-qtwebengine-cssom-style-ch --no-qtwebengine-cssom-style-ic --no-qtwebengine-cssom-style-px --no-qtwebengine-cssom-style-pt --no-qtwebengine-cssom-style-pc --no-qtwebengine-cssom-style-in --no-qtwebengine-cssom-style-cm --no-qtwebengine-cssom-style-mm --no-qtwebengine-cssom-style-q --no-qtwebengine-cssom-style-rem --no-qtwebengine-cssom-style-vw --no-qtwebengine-cssom-style-vh --no-qtwebengine-cssom-style-vmin --no-qtwebengine-cssom-style-vmax --no-qtwebengine-cssom-style-ch --no-qtwebengine-cssom-style-ic .\repair_system.exe注意上述命令过于冗长实际只需核心参数windeployqt --no-translations --no-webkit2 --no-quick --no-webengine --no-angle --no-system-d3d-compiler --no-icu --no-virtualkeyboard --no-remoteobjects --no-serialbus --no-sql-db --no-xmlpatterns --no-qmltooling --no-linguisttools --no-uitools --no-assistant --no-designer --no-qtdiag --no-qtpaths --no-qtplugininfo --no-qtconfig --no-qtwebengine-process --no-qtwebengine-resources --no-qtwebengine-locale --no-qtwebengine-devtools --no-qtwebengine-snapshot --no-qtwebengine-printing --no-qtwebengine-pdf --no-qtwebengine-avfoundation --no-qtwebengine-coreaudio --no-qtwebengine-video --no-qtwebengine-audio --no-qtwebengine-media --no-qtwebengine-network --no-qtwebengine-storage --no-qtwebengine-cache --no-qtwebengine-cookies --no-qtwebengine-history --no-qtwebengine-bookmarks --no-qtwebengine-downloads --no-qtwebengine-forms --no-qtwebengine-geolocation --no-qtwebengine-javascript --no-qtwebengine-css --no-qtwebengine-html --no-qtwebengine-svg --no-qtwebengine-xslt --no-qtwebengine-xsl --no-qtwebengine-xpath --no-qtwebengine-dom --no-qtwebengine-cssom --no-qtwebengine-cssom-style --no-qtwebengine-cssom-style-sheet --no-qtwebengine-cssom-style-rule --no-qtwebengine-cssom-style-declaration --no-qtwebengine-cssom-style-property --no-qtwebengine-cssom-style-value --no-qtwebengine-cssom-style-text --no-qtwebengine-cssom-style-number --no-qtwebengine-cssom-style-length --no-qtwebengine-cssom-style-percentage --no-qtwebengine-cssom-style-em --no-qtwebengine-cssom-style-ex --no-qtwebengine-cssom-style-px --no-qtwebengine-cssom-style-pt --no-qtwebengine-cssom-style-pc --no-qtwebengine-cssom-style-in --no-qtwebengine-cssom-style-cm --no-qtwebengine-cssom-style-mm --no-qtwebengine-cssom-style-q --no-qtwebengine-cssom-style-rem --no-qtwebengine-cssom-style-vw --no-qtwebengine-cssom-style-vh --no-qtwebengine-cssom-style-vmin --no-qtwebengine-cssom-style-vmax --no-qtwebengine-cssom-style-ch --no-qtwebengine-cssom-style-ic .\repair_system.exe更实用的是精简版windeployqt --no-translations --no-webkit2 --no-quick --no-webengine --no-angle --no-system-d3d-compiler --no-icu --no-virtualkeyboard --no-remoteobjects --no-serialbus --no-sql-db --no-xmlpatterns --no-qmltooling --no-linguisttools --no-uitools --no-assistant --no-designer --no-qtdiag --no-qtpaths --no-qtplugininfo --no-qtconfig --no-qtwebengine-process --no-qtwebengine-resources --no-qtwebengine-locale --no-qtwebengine-devtools --no-qtwebengine-snapshot --no-qtwebengine-printing --no-qtwebengine-pdf --no-qtwebengine-avfoundation --no-qtwebengine-coreaudio --no-qtwebengine-video --no-qtwebengine-audio --no-qtwebengine-media --no-qtwebengine-network --no-qtwebengine-storage --no-qtwebengine-cache --no-qtwebengine-cookies --no-qtwebengine-history --no-qtwebengine-bookmarks --no-qtwebengine-downloads --no-qtwebengine-forms --no-qtwebengine-geolocation --no-qtwebengine-javascript --no-qtwebengine-css --no-qtwebengine-html --no-qtwebengine-svg --no-qtwebengine-xslt --no-qtwebengine-xsl --no-qtwebengine-xpath --no-qtwebengine-dom --no-qtwebengine-cssom --no-qtwebengine-cssom-style --no-qtwebengine-cssom-style-sheet --no-qtwebengine-cssom-style-rule --no-qtwebengine-cssom-style-declaration --no-qtwebengine-cssom-style-property --no-qtwebengine-cssom-style-value --no-qtwebengine-cssom-style-text --no-qtwebengine-cssom-style-number --no-qtwebengine-cssom-style-length --no-qtwebengine-cssom-style-percentage --no-qtwebengine-cssom-style-em --no-qtwebengine-cssom-style-ex --no-qtwebengine-cssom-style-px --no-qtwebengine-cssom-style-pt --no-qtwebengine-cssom-style-pc --no-qtwebengine-cssom-style-in --no-qtwebengine-cssom-style-cm --no-qtwebengine-cssom-style-mm --no-qtwebengine-cssom-style-q --no-qtwebengine-cssom-style-rem --no-qtwebengine-cssom-style-vw --no-qtwebengine-cssom-style-vh --no-qtwebengine-cssom-style-vmin --no-qtwebengine-cssom-style-vmax --no-qtwebengine-cssom-style-ch --no-qtwebengine-cssom-style-ic .\repair_system.exe实际执行时若报错Cannot find platform plugin windows需手动设置环境变量set QT_QPA_PLATFORM_PLUGIN_PATHD:\Qt\5.15.2\msvc2019_64\plugins\platforms4. QT调试与性能优化QLoggingCategory分级日志 QThreadPool异步数据库操作毕设答辩时被问“如何保证高并发下数据一致性”不能只答“用了事务”需展示具体技术手段。QT提供QLoggingCategory和QThreadPool两大利器。4.1 分级日志体系用QLoggingCategory隔离业务日志与SQL日志默认qDebug()输出混杂不利于定位问题。按模块定义日志分类// logging_setup.h Q_DECLARE_LOGGING_CATEGORY(lcOrder) Q_DECLARE_LOGGING_CATEGORY(lcSync) Q_DECLARE_LOGGING_CATEGORY(lcSql) // logging_setup.cpp Q_LOGGING_CATEGORY(lcOrder, repair.order) Q_LOGGING_CATEGORY(lcSync, repair.sync) Q_LOGGING_CATEGORY(lcSql, repair.sql) // main.cpp 初始化 QLoggingCategory::setFilterRules(QStringLiteral(repair.*.debugtrue\n repair.sql.debugfalse\n // SQL日志仅在开发环境开启 repair.sync.infotrue));在关键路径插入日志qCDebug(lcOrder) 工单 orderId 状态从 oldStatus 跃迁至 newStatus; qCInfo(lcSync) 同步工单 orderId 至服务端结果 success;提示QLoggingCategory支持运行时动态调整级别如qSetLogLevel(lcSync, QtWarningMsg)便于演示时临时提升日志等级qInstallMessageHandler()可将日志重定向到文件避免控制台刷屏。4.2 异步数据库操作QThreadPool QRunnable避免UI卡顿QSqlDatabase操作尤其SELECT大量记录会阻塞主线程。正确做法是将耗时操作放入线程池class LoadOrdersTask : public QRunnable { Q_OBJECT public: explicit LoadOrdersTask(QListRepairOrder *orders, QObject *parent nullptr) : m_orders(orders), m_parent(parent) {} void run() override { QSqlDatabase db QSqlDatabase::database(main); // 使用命名连接 QSqlQuery query(db); query.exec(SELECT * FROM repair_orders WHERE status ! settled); while (query.next()) { RepairOrder order; order.id query.value(id).toInt(); order.customerName query.value(customer_name).toString(); // ... 其他字段 m_orders-append(order); } // 通知主线程更新UI QMetaObject::invokeMethod(m_parent, [this]() { emit ordersLoaded(*m_orders); }, Qt::QueuedConnection); } signals: void ordersLoaded(const QListRepairOrder orders); private: QListRepairOrder *m_orders; QObject *m_parent; }; // 在UI类中调用 void MainWindow::loadOrdersAsync() { auto *task new LoadOrdersTask(m_orderList, this); connect(task, LoadOrdersTask::ordersLoaded, this, MainWindow::onOrdersLoaded); QThreadPool::globalInstance()-start(task); }注意QSqlDatabase对象不能跨线程共享必须在线程内调用QSqlDatabase::addDatabase()创建新连接或使用QSqlDatabase::cloneDatabase()QMetaObject::invokeMethod()的Qt::QueuedConnection确保信号在主线程接收避免QTableView::setModel()在子线程调用崩溃。4.3 内存泄漏检测用QT自带的qInstallMessageHandler捕获QObject泄漏QT提供QMessageLogger机制在程序退出前检查未销毁的QObject// main.cpp 添加 void messageHandler(QtMsgType type, const QMessageLogContext context, const QString msg) { QByteArray localMsg msg.toLocal8Bit(); switch (type) { case QtDebugMsg: fprintf(stderr, Debug: %s\n, localMsg.constData()); break; case QtWarningMsg: fprintf(stderr, Warning: %s\n, localMsg.constData()); break; case QtCriticalMsg: fprintf(stderr, Critical: %s\n, localMsg.constData()); break; case QtFatalMsg: fprintf(stderr, Fatal: %s\n, localMsg.constData()); abort(); } } int main(int argc, char *argv[]) { qInstallMessageHandler(messageHandler); QApplication app(argc, argv); // ... 启动应用 // 应用退出前检查QObject泄漏 QObject::dumpObjectTree(); // 输出所有存活QObject树 return app.exec(); }提示QObject::dumpObjectTree()输出到stderr需重定向到文件分析重点检查QSqlQuery、QNetworkReply、QTimer等易泄漏对象是否被父对象正确持有QThread子类必须调用moveToThread()而非继承QThread否则exec()会阻塞主线程。5. 毕设答辩关键技巧用QT Creator Profiler抓取CPU热点 屏幕录制演示状态流转答辩时评委最关注“你做了什么”而非“你写了多少行”需用可视化证据证明技术深度。5.1 用QT Creator内置Profiler定位性能瓶颈QT Creator 4.15集成QML Profiler和C Profiler可直接分析Release版EXE在Projects → Run Settings → Run → Run in Terminal勾选Run in terminalAnalyze → Start Profiling选择C Profiler操作系统打开工单列表、切换Tab、提交状态变更停止后查看Call Graph重点关注QSqlQuery::exec()耗时占比若30%说明SQL未加索引QPainter::drawText()调用频次若过高说明UI重绘过度QStateMachine::postEvent()延迟若100ms说明状态机事件队列积压提示Profiler需在Release模式下运行Debug模式因编译器优化关闭导致数据失真若QSqlQuery::exec()耗时高立即检查repair_orders.status字段是否建立索引CREATE INDEX idx_orders_status ON repair_orders(status);5.2 屏幕录制演示脚本聚焦3个高光时刻避免全程操作只录3个关键片段总时长≤3分钟时间点演示内容技术亮点0:00-0:45服务顾问创建工单 → 技师在离线状态下修改“维修进度” → 网络恢复后自动同步展示QSqlRelationalTableModel本地缓存 QNetworkAccessManager重连机制0:46-1:30点击“派工”按钮 → 弹出技师选择框 → 选择后工单状态自动变更为“待派工” → 后台QThread立即查询该技师当前工单数展示QDataWidgetMapper绑定 QStateMachine状态跃迁 QThreadPool异步校验1:31-2:50打开Profiling报告 → 定位QSqlQuery::exec()热点 → 切换到数据库工具执行CREATE INDEX→ 重新运行Profiling热点消失展示真实性能调优闭环注意录制前关闭所有无关窗口仅保留QT Creator、数据库工具、系统任务管理器显示CPU/内存演示时口头说明“这里我通过Profiler发现SQL执行占CPU 42%于是检查了索引缺失添加后降至8%”。5.3 答辩问答预判高频问题与精准回答模板问题回答要点30秒内说完“为什么用CS架构而不是BS”“BS架构在4S店车间环境存在三大缺陷1弱网下页面加载失败技师无法录入维修过程2浏览器无法直接调用本地打印机打印工单3HTML/CSS难以实现精确的工单状态机图形化展示。QT客户端可离线操作、直连硬件、状态机可视化更契合维修业务。”“如何防止多人同时修改同一工单”“服务端采用乐观锁工单表增加version字段每次更新时WHERE条件包含version旧值若影响行数为0则返回冲突。客户端收到冲突后自动拉取最新数据并高亮差异字段由用户选择覆盖或放弃。”“QT和PyQt哪个更适合毕设”“QT C直接编译为原生EXE无Python解释器依赖打包体积小、启动快、内存占用低。PyQt虽开发快但毕设需体现底层能力C能更好展示多线程、内存管理、SQL事务等核心技能。”最后一步将repair_system.exe、sqlite3.dll、platforms/qwindows.dll、imageformats/qjpeg.dll四个文件放入同一文件夹双击即可运行——这才是评委眼中“真正完成”的毕设。本文还有配套的精品资源点击获取