源碼拆解:從接車到結算的完整業(yè)務閉環(huán)實現(xiàn))
簡介這是一套面向汽車修理廠日常運營場景的數(shù)字化管理軟件源碼適合計算機專業(yè)學生、課程設計開發(fā)者以及中小型汽修門店的信息化建設者參考。系統(tǒng)圍繞客戶檔案、預約排程、維修訂單、配件庫存、財務收支、員工績效與統(tǒng)計報表等模塊展開幫助解決手工記賬混亂、庫存預警滯后、經(jīng)營數(shù)據(jù)難以匯總等實際問題。資源包共53個文件約2.66MB以C源碼cpp、h為核心配合MFC工程文件dsp、dsw、clw、編譯中間產(chǎn)物obj、pch、idb以及Access數(shù)據(jù)庫Car.mdb另含圖標、音效與資源腳本構成一套可直接編譯運行的完整工程。已有678人學習下載。通過閱讀源碼讀者可掌握基于MFC與ADO數(shù)據(jù)庫訪問的桌面管理程序結構理解各功能對話框與數(shù)據(jù)表的映射關系并借鑒其模塊劃分與權限控制思路用于二次開發(fā)或畢業(yè)設計參考。1. 汽修廠老板的賬本困局這套管理系統(tǒng)到底能解決什么我見過一個開了八年修理廠的老板接車用粉筆寫在白板上配件進出靠微信語音月底對賬時發(fā)現(xiàn)三輛車修完了沒收錢。這不是段子是很多中小汽修門店的真實狀態(tài)。這套「汽車修理廠汽車修理管理系統(tǒng)」就是沖著這個場景來的——它把接車登記、維修派工、配件領用、結算收款串成一條線讓每一輛進廠的車都有跡可循。適合誰用單店或兩三個工位的社區(qū)修理廠、快修快保店以及想拿一套完整業(yè)務系統(tǒng)做二次開發(fā)練手的開發(fā)者。技術棧上這類系統(tǒng)常見做法是后端用 Spring Boot 或 Python Flask 提供 REST 接口前端用 Vue 或原生 HTML 加模板渲染數(shù)據(jù)庫選 MySQL部署在一臺普通云主機或門店內網(wǎng)機器上就能跑。下面我按「能干什么、怎么跑起來、怎么改」的順序把這份源碼拆開講。2. 系統(tǒng)架構與目錄結構從一張工單看數(shù)據(jù)怎么流轉2.1 業(yè)務閉環(huán)一輛車從進廠到結算經(jīng)過哪些表先別急著看代碼把業(yè)務跑通比什么都重要。一輛車進廠前臺登記車牌、車型、車主電話、故障描述系統(tǒng)生成一張維修工單狀態(tài)是「待派工」。車間主管把工單指派給某個技師狀態(tài)變「維修中」。技師在維修過程中領用配件系統(tǒng)扣減庫存并記錄領料明細。維修完成后工單轉「待結算」前臺按工時費加配件費生成結算單收款后狀態(tài)變「已結算」同時這輛車的維修歷史歸檔下次再來能直接調出。這條鏈路對應到數(shù)據(jù)庫核心是四張表vehicle車輛檔案、repair_order維修工單、part配件庫存、order_part工單領料明細。工單表通過vehicle_id關聯(lián)車輛領料明細表通過order_id和part_id把工單和配件連起來。搞清這個關系后面看任何一段代碼都不會迷路。-- 維修工單核心表結構簡化版 CREATE TABLE repair_order ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL UNIQUE COMMENT 工單號如 RO20240501001, vehicle_id BIGINT NOT NULL COMMENT 關聯(lián)車輛, fault_desc VARCHAR(500) COMMENT 故障描述, status TINYINT DEFAULT 0 COMMENT 0待派工 1維修中 2待結算 3已結算, technician_id BIGINT COMMENT 指派技師, labor_fee DECIMAL(10,2) DEFAULT 0 COMMENT 工時費, part_fee DECIMAL(10,2) DEFAULT 0 COMMENT 配件費合計, created_at DATETIME DEFAULT CURRENT_TIMESTAMP );字段說明里最關鍵的是status它驅動了整個系統(tǒng)的頁面流轉和權限控制。order_no用日期加流水號生成方便前臺口頭報單號查進度。labor_fee和part_fee分開存是因為結算時經(jīng)常要按項目打折分開算比混在一起靈活。2.2 目錄結構前后端怎么分配置文件在哪拿到源碼包先看根目錄。這類管理系統(tǒng)常見做法是前后端分離目錄大致長這樣repair-system/ ├── backend/ # 后端服務 │ ├── src/main/java/... # 控制器、服務、數(shù)據(jù)訪問層 │ ├── src/main/resources/ │ │ ├── application.yml # 數(shù)據(jù)庫連接、端口配置 │ │ └── mapper/ # MyBatis 的 SQL 映射文件 │ └── pom.xml # Maven 依賴 ├── frontend/ # 前端頁面 │ ├── src/views/ # 各業(yè)務頁面接車、派工、結算 │ ├── src/api/ # 接口請求封裝 │ └── package.json └── sql/ └── init.sql # 建庫建表加初始數(shù)據(jù)后端如果用的是 Spring Bootapplication.yml里改數(shù)據(jù)庫地址和密碼就能連自己的庫前端src/api目錄下通常有一個request.js里面配了后端接口的基礎地址部署時改成實際 IP 或域名。sql/init.sql是救命文件第一次跑必須先執(zhí)行它否則表都沒有登錄都進不去。2.3 權限與角色為什么前臺看不到成本價系統(tǒng)一般內置三種角色管理員、前臺、技師。管理員能看所有數(shù)據(jù)和報表前臺能接車、派工、結算但看不到配件的進價技師只能看指派給自己的工單和領料。這個權限控制在代碼里通??恳粋€攔截器加角色字段判斷實現(xiàn)。// 簡化的權限攔截邏輯 public boolean checkPermission(String role, String apiPath) { if (ADMIN.equals(role)) return true; // 管理員放行 if (FRONT.equals(role) apiPath.startsWith(/order)) return true; if (TECH.equals(role) apiPath.startsWith(/task)) return true; return false; // 其余一律拒絕 }這段邏輯看著簡單但它是整個系統(tǒng)安全感的來源。參數(shù)role從登錄后寫入 session 或 token 里取apiPath是當前請求路徑。實際項目里會做得更細比如前臺能改工單但不能刪工單這些差異都落在checkPermission的分支里。改權限就是改這里的分支條件比滿項目找if靠譜得多。3. 本地跑起來數(shù)據(jù)庫、后端、前端三步走3.1 建庫導數(shù)據(jù)init.sql 里有什么坑第一步永遠是數(shù)據(jù)庫。打開sql/init.sql里面通常包含建庫語句、建表語句和幾條初始數(shù)據(jù)比如默認管理員賬號。執(zhí)行方式有兩種命令行mysql -u root -p init.sql或者用圖形化工具打開文件直接運行。# 登錄數(shù)據(jù)庫并執(zhí)行初始化腳本 mysql -u root -p CREATE DATABASE repair_db DEFAULT CHARSET utf8mb4; USE repair_db; SOURCE /path/to/sql/init.sql;這里有個血淚經(jīng)驗字符集一定要用utf8mb4別用utf8。汽修系統(tǒng)里車主姓名、故障描述經(jīng)常出現(xiàn)生僻字utf8存進去會變問號結算單打出來車主名字是亂碼客戶當場就不信任你了。另外init.sql里的初始密碼通常是明文或簡單加密第一次登錄后立刻改掉別留著默認賬號跑在公網(wǎng)上。3.2 后端啟動改配置、裝依賴、看日志數(shù)據(jù)庫通了之后進backend目錄。如果是 Maven 項目先改application.ymlspring: datasource: url: jdbc:mysql://127.0.0.1:3306/repair_db?useUnicodetruecharacterEncodingutf8mb4 username: root password: 你的密碼 server: port: 8080url里的characterEncodingutf8mb4和數(shù)據(jù)庫字符集對應別漏。然后執(zhí)行mvn clean package打包或者直接在 IDE 里跑主啟動類。啟動成功的標志是日志最后出現(xiàn)Started Application in x seconds并且沒有Communications link failure這類數(shù)據(jù)庫連接報錯。# 打包并運行 mvn clean package -DskipTests java -jar target/repair-system-1.0.jar-DskipTests是跳過測試加快打包第一次跑建議加上等系統(tǒng)跑通了再回頭跑測試。如果啟動報端口占用改server.port就行別去殺進程容易誤傷別的服務。3.3 前端啟動接口地址別寫死前端進frontend目錄先npm install裝依賴再npm run dev起開發(fā)服務器。關鍵動作是找到接口基礎地址的配置通常在.env.development或src/api/request.js里。// src/api/request.js 里的基礎地址配置 const baseURL process.env.VUE_APP_BASE_API || http://127.0.0.1:8080; // 開發(fā)環(huán)境指向本地后端生產(chǎn)環(huán)境改成實際服務器地址很多人本地跑不通就是卡在這后端在 8080前端請求卻發(fā)到了別的端口瀏覽器控制臺一片 404。改完地址重啟前端用初始管理員賬號登錄能看到接車頁面就說明整條鏈路通了。這時候別急著錄入真實數(shù)據(jù)先隨便建一輛測試車走一遍完整流程確認工單狀態(tài)能正常流轉。4. 核心模塊拆解接車、派工、結算三段代碼4.1 接車登記工單號怎么生成才不重復接車是整個系統(tǒng)的入口代碼質量直接影響后面所有環(huán)節(jié)。核心是生成一個唯一工單號并落庫。// 工單號生成日期 4位當日流水 public String generateOrderNo() { String datePart LocalDate.now().format(DateTimeFormatter.ofPattern(yyyyMMdd)); // 查詢當天已有多少工單加一作為流水號 int todayCount orderMapper.countByDate(datePart); return RO datePart String.format(%04d, todayCount 1); }邏輯說明datePart取當天日期countByDate查當天工單數(shù)量加一后補零成四位。參數(shù)上%04d保證流水號至少四位當天超過 9999 單才會溢出中小修理廠根本到不了。這里有個并發(fā)隱患兩個人同時接車可能拿到同一個流水號。常見做法是給order_no加唯一索引插入失敗就重試一次或者直接用數(shù)據(jù)庫自增 ID 拼日期更省心。4.2 派工與領料庫存扣減必須和工單綁定派工是把工單指派給技師領料是技師從倉庫拿配件。這兩步必須在一個事務里完成否則會出現(xiàn)「配件領走了但工單沒記錄」的糊涂賬。Transactional // 事務注解保證扣庫存和寫明細同時成功或同時失敗 public void assignAndPickParts(Long orderId, Long technicianId, ListPickItem items) { // 1. 更新工單狀態(tài)和技師 orderMapper.updateStatusAndTech(orderId, 1, technicianId); // 2. 逐項扣減庫存并寫領料明細 for (PickItem item : items) { int affected partMapper.reduceStock(item.getPartId(), item.getQty()); if (affected 0) { throw new RuntimeException(配件庫存不足 item.getPartId()); } orderPartMapper.insert(orderId, item.getPartId(), item.getQty()); } }Transactional是這段代碼的靈魂。reduceStock的 SQL 里帶WHERE stock #{qty}條件庫存不夠時返回影響行數(shù) 0直接拋異?;貪L整個操作。參數(shù)items是技師勾選的配件列表每項含配件 ID 和數(shù)量。這樣即使中途某個配件不夠前面扣掉的庫存也會回滾不會出現(xiàn)半截賬。4.3 結算收款工時費和配件費怎么算準結算要把工時費和配件費匯總生成最終金額。配件費從領料明細里按當時售價累加工時費按工單上記錄的金額取。-- 匯總某工單的配件費 SELECT IFNULL(SUM(op.qty * p.sale_price), 0) AS part_fee FROM order_part op JOIN part p ON op.part_id p.id WHERE op.order_id #{orderId};IFNULL是防止沒有領料時返回 null導致前端顯示空白。sale_price取的是配件表里的當前售價這里有個細節(jié)如果配件調過價歷史工單的配件費會跟著變。嚴謹做法是在order_part表里冗余一個unit_price字段領料時把當時售價存進去結算就按這個存下來的價格算不受后續(xù)調價影響。這是很多新手會翻車的地方改起來不難加個字段的事。5. 避坑與常見問題跑不起來先看這幾條5.1 啟動報數(shù)據(jù)庫連接失敗現(xiàn)象后端啟動日志里出現(xiàn)Communications link failure或Access denied for user。原因通常是application.yml里的地址、端口、賬號密碼和實際數(shù)據(jù)庫對不上或者數(shù)據(jù)庫服務根本沒啟動。解決先用命令行mysql -u root -p確認能連上再核對配置文件里的每一項特別注意密碼里有沒有特殊字符需要轉義。5.2 頁面能打開但接口全 404現(xiàn)象前端登錄頁面正常顯示點登錄沒反應瀏覽器控制臺一堆 404。原因基本是前端接口基礎地址配錯了或者后端沒起在預期端口。解決打開瀏覽器開發(fā)者工具的 Network 面板看請求實際發(fā)到了哪個地址和request.js里的baseURL對比改成一致即可。5.3 中文亂碼現(xiàn)象錄入的車主姓名、故障描述存進數(shù)據(jù)庫變成問號或者頁面顯示亂碼。原因有三處可能數(shù)據(jù)庫字符集不是utf8mb4、連接串沒加characterEncoding、前端頁面沒聲明 UTF-8。解決按數(shù)據(jù)庫、連接串、頁面三層逐一排查建庫時就用utf8mb4最省事。5.4 工單狀態(tài)卡住不流轉現(xiàn)象派工后工單還是顯示「待派工」或者結算后狀態(tài)沒變。原因多半是狀態(tài)更新的 SQL 條件寫死了舊狀態(tài)比如WHERE status 0但實際狀態(tài)已經(jīng)不是 0 了。解決檢查更新語句的WHERE條件確認它和當前實際狀態(tài)匹配或者干脆只按id更新狀態(tài)值由業(yè)務代碼控制。5.5 配件庫存扣成負數(shù)現(xiàn)象庫存表里出現(xiàn)負庫存。原因是扣減時沒加庫存充足判斷或者并發(fā)下兩個請求同時扣。解決扣減 SQL 必須帶WHERE stock #{qty}并在業(yè)務層判斷影響行數(shù)為 0 就拋異?;貪L。高并發(fā)場景再加數(shù)據(jù)庫行鎖或樂觀鎖版本號。6. 二次開發(fā)從改一個字段到加一張報表拿到這套源碼最值錢的不是原樣跑起來而是按自己門店的規(guī)矩改。我一般從三個方向下手按難度遞增。第一層改字段和文案。比如工單表想加一個「預計交車時間」字段改動路徑是init.sql加列、實體類加屬性、Mapper 的 insert 和 update 語句加參數(shù)、前端表單加輸入框。四步缺一不可漏了哪步都會出現(xiàn)「填了不保存」或「保存了不顯示」。這類改動最安全適合先練手熟悉代碼結構。第二層加業(yè)務規(guī)則。比如「結算時必須先確認所有領料都已歸還或核銷」。做法是在結算接口里加一段校驗查order_part表里有沒有未核銷的記錄有就返回錯誤提示。這類改動要動 Service 層改完務必用測試數(shù)據(jù)走一遍完整流程別只測單個接口。第三層加報表和統(tǒng)計。修理廠老板最想看的是「這個月修了多少車、哪個技師產(chǎn)值最高、哪些配件周轉最快」。加報表的思路是新建一個統(tǒng)計接口用 SQL 聚合查詢出數(shù)據(jù)前端加一個圖表頁面。下面是一個技師產(chǎn)值的統(tǒng)計示例-- 按月統(tǒng)計各技師完成的工單數(shù)和工時費合計 SELECT t.name AS technician, COUNT(o.id) AS order_count, IFNULL(SUM(o.labor_fee), 0) AS total_labor FROM repair_order o JOIN technician t ON o.technician_id t.id WHERE o.status 3 -- 只統(tǒng)計已結算工單 AND DATE_FORMAT(o.created_at, %Y-%m) #{month} GROUP BY t.id, t.name ORDER BY total_labor DESC;status 3是關鍵過濾條件只算已結算的才算真實產(chǎn)值維修中的工單不能計入。DATE_FORMAT按月份分組前端傳2024-05這樣的參數(shù)就能查指定月份。這個查詢在數(shù)據(jù)量大的時候會慢常見做法是給created_at和status加聯(lián)合索引。改造時有個習慣我一直保持每次改完數(shù)據(jù)庫結構先手動執(zhí)行一遍建表語句確認無誤再重啟后端最后清瀏覽器緩存刷新前端。這三步走完再測功能能省掉大量「明明改了卻沒生效」的玄學時間。有次我改了個字段類型沒同步改實體類排查了半小時才發(fā)現(xiàn)是類型不匹配導致插入靜默失敗從那以后我每次動表結構都強制走一遍「SQL、實體、Mapper、前端」四件套核對。希望這套拆解能幫你少走點彎路把這份源碼真正變成自己門店能用的系統(tǒng)。本文還有配套的精品資源點擊獲取