設計與實現(xiàn):從數(shù)據(jù)庫到接口全解析)
先聊點實際的。微信小程序健身管理系統(tǒng)這個名字在各類畢設選題里出現(xiàn)頻率相當高CSDN、GitHub上隨便一搜就是一大堆但真正能跑通、邏輯清晰、能經(jīng)得起答辯追問的項目其實不多。這個題目之所以熱門是因為它兼顧了“前端交互展示”和“后端業(yè)務邏輯”兩頭不管是小程序端還是管理端都有足夠的內(nèi)容可寫工作量飽滿技術棧也有一定的延展空間對本科畢設來說是個非常合適的選題。我手頭這套基于微信小程序實現(xiàn)的健身管理系統(tǒng)功能上覆蓋了用戶端和小程序內(nèi)部的管理端雙角色。用戶端主要解決“選課、約課、練后記錄”這條主鏈路管理端處理“課程排期、用戶審核、健身數(shù)據(jù)復核”這些偏后臺的事。整體技術路線走的是微信小程序原生 后端接口 MySQL 數(shù)據(jù)庫的經(jīng)典組合結構清晰也方便后續(xù)擴展。接下來我會把整套系統(tǒng)的設計思路、核心功能拆解、具體實現(xiàn)的關鍵代碼片段、踩坑記錄以及論文寫作時需要注意的要點一次性梳理清楚。1. 健身管理系統(tǒng)整體設計思路1.1 為什么選微信小程序而不是獨立App很多人在選題時會糾結健身管理系統(tǒng)用微信小程序做為什么不干脆做個App這個問題的答案其實取決于使用場景和目標用戶。健身管理系統(tǒng)面向的是健身房會員和運營人員。會員的典型動作是翻看課程表、預約一節(jié)團課、查看自己的鍛煉記錄。這些操作都是“低頻但必須隨時可用”的用戶不可能為了約一節(jié)瑜伽課專門下載一個幾十兆的App。微信小程序“用完即走”的特性恰好匹配這個場景在微信里搜索一下或掃個碼就能進入預約完就退出下次需要時再打開。從開發(fā)成本上看小程序前端基于微信提供的組件體系和API開發(fā)門檻低于原生App一套代碼在iOS和Android上都能跑不需要分別維護兩套工程。再加上微信生態(tài)本身就解決了登錄授權的問題通過wx.login拿到code后端再用code換openid就能識別用戶身份省去了自己搭建賬號體系和短信驗證的成本。還有一個很多人容易忽略的點健身管理系統(tǒng)作為畢設或課程設計項目小程序的形式更容易展示。答辯現(xiàn)場用微信掃一掃就能在手機上看效果比在電腦上啟動一個模擬器要直觀得多。如果做成App還要考慮簽名、打包、安裝的問題這些對于非專業(yè)安卓開發(fā)的同學來說都是額外的時間消耗。1.2 系統(tǒng)角色與核心功能劃分健身管理系統(tǒng)從業(yè)務上天然分成兩類角色普通用戶會員和健身管理員教練或運營人員。兩方在小程序端看到的界面和能執(zhí)行的操作完全不同。用戶端的核心功能我梳理下來主要圍繞三條主鏈路展開看課瀏覽團課課程列表查看課程詳情包括教練信息、上課時間、課程強度、剩余名額。約課選擇心儀的課程時間段進行預約預約后在我的預約中查看狀態(tài)支持取消預約。記錄每次鍛煉結束后記錄訓練內(nèi)容、時長、消耗熱量系統(tǒng)對歷史記錄做統(tǒng)計分析用圖表展示每周的訓練趨勢。管理端因為是小程序內(nèi)嵌的管理模式功能不追求大而全但必須覆蓋運營的基本訴求課程管理發(fā)布新課程、設置課程容量、管理排期。預約管理查看所有預約記錄處理異常預約統(tǒng)計約課率。用戶管理查看注冊用戶列表對用戶進行備注或標記。角色體系的劃分用一個role字段就能區(qū)分用戶表中role1是普通會員role2是管理員。管理員登錄后通過條件渲染切換導航欄和頁面入口不需要做復雜的路由攔截。當然這只是前端層面的控制真正的權限校驗必須放在后端接口里做這個后面在接口設計部分詳細說。1.3 技術選型的考慮與得失這套系統(tǒng)的后端我選的是Node.js Express數(shù)據(jù)庫用MySQL。選這個組合的原因很簡單JavaScript全棧前后端語言統(tǒng)一代碼寫起來順手而且Express的中間件機制做接口鑒權非常方便。如果你用的是Java Spring Boot或者Python Django本質(zhì)上沒區(qū)別只是語言層面的不同。選型時有一個原則需要守住選自己最熟悉、最快能出活的技術棧不要為了追求所謂的高并發(fā)、分布式去強行上微服務那是給自己找麻煩。微信小程序端用的是原生開發(fā)沒有引入vant-weapp這類UI組件庫。原因是原生組件在小程序里的穩(wěn)定性最好自定義樣式的可控度也最高。雖然vant組件庫確實好看好用但引入后還會帶來樣式覆蓋、組件升級適配等額外問題對于這種體量的項目原生寫法反而更省心。數(shù)據(jù)庫表設計是整個項目的地基我踩過一次坑后把表結構重構過一版最終的方案值得重點說一下。2. 數(shù)據(jù)庫設計與核心接口實現(xiàn)2.1 核心數(shù)據(jù)表結構健身管理系統(tǒng)最核心的表有四張用戶表、課程表、預約表、訓練記錄表。另外還有一張管理員的公告表用來發(fā)布站內(nèi)通知功能不復雜但能讓系統(tǒng)顯得完整。用戶表字段并不需要很多核心字段是openid、nickname、avatar_url、phone、role。openid是用戶在小程序里的唯一標識后端通過微信的code2Session接口換取它才是用戶身份的真正主鍵。nickname和avatar_url是用戶在小程序里主動授權后獲取的個人信息。role區(qū)分用戶和管理員。課程表重點在于排期概念。一門實體課程比如“燃脂搏擊”一周可能有多節(jié)課每節(jié)課有自己獨立的時間段、教練、剩余名額所以課程表其實存儲的是“課程實例”字段包括course_name、coach_name、start_time、end_time、capacity、booked_count、difficulty、cover_url。booked_count是已預約人數(shù)每次有人成功預約就加1取消預約就減1前端詳情頁直接展示這個字段來判斷名額是否已滿。預約表存儲的是用戶和課程實例的多對多關系id、user_id、course_id、status、create_time。status字段有幾種取值0表示已取消、1表示已預約、2表示已完成。當課程時間過去后用戶可以打卡確認完成這時status更新為2。訓練記錄表比較簡單記錄用戶自主提交的訓練數(shù)據(jù)user_id、exercise_type、duration_minutes、calories、record_date、remark。它的作用就是為統(tǒng)計圖表提供數(shù)據(jù)來源。2.2 預約狀態(tài)機設計預約是整個系統(tǒng)里業(yè)務邏輯最復雜的一個環(huán)節(jié)因為它涉及到狀態(tài)流轉。我一開始想得簡單了以為只要一個status字段就夠了后來發(fā)現(xiàn)不行。比如用戶預約了一節(jié)課這節(jié)課還沒開始用戶想取消這個狀態(tài)是“已預約但未開始”可以取消。但如果這節(jié)課已經(jīng)結束了呢用戶就不能再取消了只能標記完成或直接棄課。最終我設計了一套簡單的預約狀態(tài)機一共四個狀態(tài)已預約status1預約成功課程未開始此時用戶可以取消預約。已取消status0用戶主動取消或管理員后臺取消名額釋放。已完成status2課程已結束且用戶完成了打卡這個狀態(tài)由用戶操作觸發(fā)。已過期status3課程結束但用戶未打卡系統(tǒng)定時任務自動將這類預約標記為已過期。這個設計在事務層面有幾個細節(jié)必須處理用戶發(fā)起預約時要判斷當前時間是否已經(jīng)超過開課時間如果超過了直接拒絕預約。還要判斷課程實例的booked_count是否小于capacity如果不小于說明已經(jīng)約滿不能再約。這里容易踩的坑是并發(fā)問題——兩個人同時提交預約都讀到剩余名額為1然后同時寫入預約記錄最終導致超賣。解決辦法是給booked_count的更新加一個條件UPDATE course SET booked_count booked_count 1 WHERE id ? AND booked_count capacity讓數(shù)據(jù)庫層面的原子操作來兜底。2.3 后端接口設計與權限校驗后端接口統(tǒng)一以/api為前綴按模塊劃分路由。核心接口我整理了一張表方便對照接口路徑方法功能說明權限要求/api/user/loginPOST微信登錄code換openid公開/api/user/profileGET獲取當前用戶信息用戶級/api/course/listGET獲取課程列表公開/api/course/detailGET獲取課程詳情公開/api/booking/createPOST創(chuàng)建預約用戶級/api/booking/cancelPOST取消預約用戶級/api/booking/listGET獲取我的預約列表用戶級/api/record/addPOST添加訓練記錄用戶級/api/record/statsGET獲取統(tǒng)計圖表數(shù)據(jù)用戶級/api/admin/course/addPOST新增課程排期管理員/api/admin/booking/listGET查看全部預約管理員權限校驗用的是最經(jīng)典的token方案。用戶登錄成功后后端返回一個自定義token前端把token存入wx.setStorageSync之后每個請求在header里帶上Authorization: Bearer token。后端寫一個認證中間件從header里取出token解析出user_id和role掛載到req對象上。然后每個路由按需聲明權限等級// auth.js 中間件核心邏輯 const verifyToken (req, res, next) { const authHeader req.headers[authorization]; if (!authHeader || !authHeader.startsWith(Bearer )) { return res.status(401).json({ message: 未登錄 }); } const token authHeader.split( )[1]; try { const decoded jwt.verify(token, SECRET_KEY); req.userId decoded.userId; req.userRole decoded.role; next(); } catch (err) { return res.status(401).json({ message: token無效或已過期 }); } }; const requireAdmin (req, res, next) { if (req.userRole ! 2) { return res.status(403).json({ message: 無管理員權限 }); } next(); };前端頁面雖然做了角色區(qū)分但真正防住越權操作的是后端這層校驗。管理端的接口必須加上requireAdmin不然任何人只要修改小程序的存儲數(shù)據(jù)就有權限調(diào)用管理接口這是開發(fā)階段最容易忽視的安全漏洞。3. 小程序端核心功能實操3.1 登錄授權與用戶識別微信小程序的登錄流程跟普通Web網(wǎng)站的登錄完全不一樣。它沒有用戶名密碼的概念核心是微信的openid識別機制。具體流程是這樣的第一步小程序前端通過wx.login接口獲取一個臨時code這個code的有效期只有5分鐘而且只能用一次。第二步前端把code發(fā)給自己的后端接口后端拿到code后調(diào)用微信官方的code2Session接口用code換回openid和session_key。第三步后端拿著openid去數(shù)據(jù)庫里查用戶如果從來沒注冊過就自動建一條新記錄。最后后端自己簽發(fā)一個token返回給前端前端存起來供后續(xù)請求使用。這里有一點值得注意wx.login拿到的code只能換一次openid如果換成功了你重新調(diào)用wx.login拿新code之前的code就失效了。所以在寫代碼時不要在一個頁面里反復調(diào)用wx.login應該把登錄邏輯放到一個統(tǒng)一的入口處理。用戶昵稱頭像的獲取現(xiàn)在微信政策收緊后無法直接通過wx.getUserProfile無限次彈窗獲取了。新方案是在頁面里放一個按鈕用戶主動點擊“授權頭像昵稱”后通過button的open-typechooseAvatar拿到頭像地址typenickname拿到昵稱輸入框。這兩塊的操作是小程序開發(fā)里比較容易被卡住的點因為舊接口在基礎庫版本升級后已經(jīng)不能用了。3.2 課程列表與預約流程實現(xiàn)課程列表是這個系統(tǒng)里用戶最常用的頁面。列表頁用onShow生命周期加載數(shù)據(jù)因為用戶從詳情頁返回列表頁時名額可能已經(jīng)被搶占了需要刷新。我用wx.request請求課程列表接口把返回的數(shù)據(jù)渲染成卡片// courseList.js 關鍵請求邏輯 onShow() { this.fetchCourseList(); }, fetchCourseList() { wx.request({ url: ${BASE_URL}/api/course/list, method: GET, success: (res) { const list res.data.map((item) { // 計算課程狀態(tài)0-可預約 1-已約滿 2-已開始 const now new Date(); const start new Date(item.start_time); let status 0; if (item.booked_count item.capacity) status 1; if (now start) status 2; return { ...item, status }; }); this.setData({ courseList: list }); } }); }預約按鈕的處理邏輯最核心的一點是先判斷狀態(tài)再調(diào)接口。前端判斷當前課程是否可約后端再次判斷并做原子更新雙重校驗。前端判斷是為了體驗后端判斷是為了正確性。用戶點擊“立即預約”時先彈一次確認框然后調(diào)預約接口。預約成功后不要急著跳轉直接把當前課程的booked_count更新一下讓用戶立刻看到名額變化。如果接口返回“約滿了”之類的錯誤彈toast提示并刷新列表。取消預約我額外加了一個時間限制開課前30分鐘內(nèi)不允許取消。這個限制放在后端做前端只做展示。為什么因為用戶端時間可能不準依賴用戶設備時間做業(yè)務判斷是危險的以服務器時間為準才是正確姿勢。3.3 訓練打卡與圖表統(tǒng)計訓練記錄模塊的價值在于給用戶一個正向反饋閉環(huán)。每次練完用戶錄入訓練類型、時長、消耗熱量這些數(shù)據(jù)累積起來就能用圖表展示趨勢。圖表功能我一開始想用ec-canvasECharts的小程序版但后來發(fā)現(xiàn)項目體積會增加不少而且在小程序Canvas里的渲染效果在低端機上有點卡。最后我方案改成用CSS手繪簡易柱狀圖雖然不如ECharts好看但勝在輕量、穩(wěn)定、零依賴。簡化版的柱狀圖實現(xiàn)思路是后端返回一周內(nèi)每天的鍛煉時長總和前端把七天數(shù)據(jù)渲染成七根豎條高度按比例計算view classchart view classbar-item wx:for{{weeklyStats}} wx:keyindex view classbar-value styleheight: {{item.percent}}%{{item.duration}}min/view view classbar-label{{item.label}}/view /view /view這里最需要注意的細節(jié)是percent字段的計算規(guī)則最長的一天設為100%其他天數(shù)按比例換算而不是按所有天數(shù)的總和換算。如果按總和換算會出現(xiàn)一周只練了一次但柱子也頂?shù)胶芨叩那闆r視覺上會誤導用戶。統(tǒng)計接口的SQL其實也不復雜就是按日期分組求和SELECT DATE(record_date) AS record_day, SUM(duration_minutes) AS total_duration FROM fitness_record WHERE user_id ? AND record_date DATE_SUB(CURDATE(), INTERVAL 7 DAY) GROUP BY DATE(record_date) ORDER BY record_day4. 常見問題與排查技巧實錄4.1 網(wǎng)絡請求失敗的排查清單小程序開發(fā)中wx.request請求失敗是出現(xiàn)頻率最高的問題。我總結過一張排查清單遇到請求失敗按順序查基本不跑偏第一域名是否配置到合法域名。開發(fā)時可以在開發(fā)者工具里勾選“不校驗合法域名”但真機預覽時必須把后端域名加到小程序后臺的request合法域名列表里。很多人本地調(diào)試沒問題一上真機就請求失敗九成是這個原因。需要注意這個小程序后臺有個“校驗合法域名”的開關如果域名沒有備案就算加進去了也會校驗失敗。第二請求頭是否缺少參數(shù)。后端接口要求必須在header里帶上token如果token沒存進去或已過期后端返回401前端拿到錯誤碼后沒有做統(tǒng)一處理就會表現(xiàn)為“請求失敗”。我的做法是在請求封裝里統(tǒng)一響應401狀態(tài)自動清除緩存的過期token并跳轉到登錄頁。第三WXS腳本里發(fā)起不了請求。WXS是在視圖層運行的腳本它和JavaScript運行環(huán)境是隔離的無法調(diào)用wx.request。有次我寫了個需求想在wxs里實時判斷課程是否開始結果發(fā)現(xiàn)wxs里連new Date()都有兼容問題更別提發(fā)請求了。正確的做法是在wxs里只做純計算判斷邏輯放到事件處理函數(shù)中。小程序請求封裝的推薦寫法是統(tǒng)一封裝一個request方法把baseURL、token注入、錯誤碼處理都收攏到一處不要在每個頁面里直接裸調(diào)wx.request。這樣后面對接新接口、統(tǒng)一加loading效果都方便。4.2 緩存數(shù)據(jù)更新不及時的問題關于緩存我踩過一個很典型的坑。課程列表數(shù)據(jù)在onShow里刷新了但課程詳情頁的數(shù)據(jù)是寫在onLoad里的。因為小程序頁面的onLoad在頁面實例創(chuàng)建時只執(zhí)行一次從詳情頁跳到列表頁再回來詳情頁不會重新觸發(fā)onLoad于是展示的還是舊數(shù)據(jù)。解決辦法是區(qū)分onLoad和onShow的職責第一次進入頁面時拉取數(shù)據(jù)放在onLoad里從其他頁面返回需要刷新時把拉取動作放在onShow里。具體場景里我會在詳情頁的onShow里判斷一個參數(shù)如果從預約成功的回調(diào)返回就刷新數(shù)據(jù)否則沿用原有數(shù)據(jù)。關于wx.setStorageSync緩存設置了過期時間的問題小程序原生的Storage API不帶過期機制存進去就一直在。如果不想讓某個緩存數(shù)據(jù)一直是臟數(shù)據(jù)可以在存入時附帶一個時間戳讀取時判斷const CACHE_KEY course_list; const CACHE_TTL 5 * 60 * 1000; // 5分鐘 function getCourseListFromCache() { const cached wx.getStorageSync(CACHE_KEY); if (!cached) return null; if (Date.now() - cached.timestamp CACHE_TTL) { wx.removeStorageSync(CACHE_KEY); return null; } return cached.data; }這種帶過期時間的緩存在課程列表這種對實時性要求不高的場景下很合適既能減少后端壓力又能避免用戶每次進入都看到加載動畫。4.3 組件層級的兼容性問題實現(xiàn)底部導航欄時小程序原生的tabBar只能配置固定的兩個位置的功能頁。因為健身管理系統(tǒng)里有“首頁”“課程”“記錄”“我的”四個頁面剛好四個tab直接用原生tabBar完全沒有問題。真正麻煩的是自定義導航欄。有些頁面需要根據(jù)滾動位置調(diào)整導航欄背景色這種效果用原生導航欄實現(xiàn)不了要設置navigationStyle: custom。自定義后就涉及到狀態(tài)欄高度適配的問題不同機型的頂部安全區(qū)高度不一樣。我用的是wx.getWindowInfo()獲取狀態(tài)欄高度再手動加上自定義導航欄的高度const { statusBarHeight } wx.getWindowInfo(); this.setData({ navHeight: statusBarHeight 44 });這個44是navigationBar的標準高度。iPhone X系列和普通機型在這個值上沒有區(qū)別區(qū)別都在狀態(tài)欄高度上。如果適配不對會出現(xiàn)導航欄按鈕被劉海遮擋的問題。還有textarea組件層級穿透的問題在表單頁面需要錄入訓練備注時textarea是原生組件層級高于普通view會出現(xiàn)z-index設了也沒用的現(xiàn)象。如果非要用textarea通常配合cover-view來解決。為了規(guī)避這個坑我在訓練記錄頁面直接用input代替了textarea訓練備注一般也就一句話input的單行輸入完全夠用也省了一堆適配工作。4.4 預約并發(fā)超賣問題的處理開發(fā)初期我模擬過兩個人同時搶同一個課程最后一個名額的情況果然出現(xiàn)了超賣——兩個人都預約成功了但課程容量只有20人最后booked_count變成了21。原因很簡單我原本的邏輯是SELECT判斷名額再INSERT預約記錄中間有時間差兩個請求都通過了判斷。修復方式前面提到過用一條原子SQLconst updateResult await db.query( UPDATE course SET booked_count booked_count 1 WHERE id ? AND booked_count capacity, [courseId] ); if (updateResult.affectedRows 0) { return res.json({ message: 該課程已約滿 }); } // 只有更新成功才插入預約記錄這種樂觀鎖方案實現(xiàn)簡單對課程預約這種場景完全夠用。如果硬要用Redis分布式鎖那是殺雞用牛刀而且還要額外部署Redis增加了項目的復雜度。5. 論文寫作與答辯準備心得5.1 論文結構怎么組織“項目源碼論文說明”這個組合意味著論文說明部分同樣很重要。很多人的項目能跑通但論文寫得一塌糊涂答辯時被老師一問就露餡。我建議按以下結構組織緒論講背景、意義、國內(nèi)外研究現(xiàn)狀。注意這個部分不要抄書重點寫清楚“為什么健身管理需要系統(tǒng)化”這個問題。相關技術介紹微信小程序技術框架、Node.js技術棧、MySQL數(shù)據(jù)庫。寫技術介紹時注意不要只寫概念最好把“為什么選這個技術”“它解決什么問題”寫透。需求分析功能性需求用戶端和管理端的用例圖、非功能性需求性能、安全、易用性。系統(tǒng)設計總體架構圖、功能模塊設計、數(shù)據(jù)庫E-R圖、核心表結構設計字段說明。系統(tǒng)實現(xiàn)每個模塊的實現(xiàn)截圖配關鍵代碼說明。代碼不需要全部貼貼核心片段加解釋即可。系統(tǒng)測試功能測試用例表、測試結果。測試部分一定要真實寫不要只寫“全部通過”要寫清楚測試了哪些場景、有沒有發(fā)現(xiàn)bug、怎么修復的。寫論文時有一個非常實用的建議先畫圖表再圍繞圖表寫文字。系統(tǒng)架構圖、用例圖、時序圖、E-R圖這四張圖畫出來論文的核心骨架就定下來了。文字是在骨架上填肉的過程圖片可以自己做也可以用在線繪圖工具。5.2 數(shù)據(jù)庫設計的編寫要點論文里的數(shù)據(jù)庫設計部分不建議把所有表的所有字段都羅列一遍那樣太長太啰嗦。正確姿勢是選擇最核心的表詳細說明其他表用一張匯總表帶過。比如用戶表、課程表、預約表這三張表是系統(tǒng)最核心的業(yè)務表每張表單獨用一個表格列出字段名、數(shù)據(jù)類型、是否主鍵、是否為空、字段說明。訓練記錄表、公告表這些輔助表可以合并成一個表格展示。這樣既體現(xiàn)了設計深度又不至于讓論文變成數(shù)據(jù)庫字典。數(shù)據(jù)庫設計的圖示我用的是E-R圖。E-R圖不需要畫得有多精美關鍵是實體、屬性、聯(lián)系要理清楚。用戶和課程的預約關系是多對多通過預約表作為中間表來分解這個關系一定要在E-R圖里清楚表達出來很多答辯老師喜歡盯著E-R圖問。5.3 答辯前的加試準備答辯環(huán)節(jié)被問得最多的問題我整理過一份清單提前準備基本都能應對系統(tǒng)有哪些角色權限怎么控制的答用戶角色和管理員角色后端用JWT鑒權中間件控制管理接口額外校驗角色字段。預約功能并發(fā)沖突怎么處理答數(shù)據(jù)庫原子更新條件判斷s booked_count capacity受影響行數(shù)為0則拒絕預約。數(shù)據(jù)庫為什么要設計預約表答因為用戶和課程是多對多關系需要中間表解除復雜關聯(lián)。token過期了怎么辦答前端攔截401響應清除本地緩存跳轉登錄頁重新獲取token。系統(tǒng)有什么可以改進的地方答可擴展消息推送、引入ECharts做更豐富的可視化、部署到云服務器統(tǒng)一域名訪問。還有一個容易被問到的點登錄功能為什么要通過自己的后端中轉而不是小程序直接調(diào)微信接口換openid答案是安全因素。微信的code2Session接口需要用到AppSecret這個密鑰一旦暴露在小程序前端就等于公開了任何人都能冒充你的小程序身份。所以必須由后端調(diào)用微信接口AppSecret只保存在后端環(huán)境變量里。6. 開發(fā)過程中的時間與版本管理建議這個系統(tǒng)我一個人從數(shù)據(jù)庫設計到小程序上線調(diào)試前后用了三周半時間。時間分配大致是數(shù)據(jù)庫設計及表結構優(yōu)化用了3天后端接口編碼和自測用了5天小程序前端頁面開發(fā)用了7天前后端聯(lián)調(diào)和修Bug用了4天論文寫作和答辯準備用了6天。版本管理一定要用Git哪怕只有一個人寫也要用。理由很簡單你在加新功能時改著改著發(fā)現(xiàn)舊的邏輯更合理要回退有Git就一條git checkout命令的事。我第一版預約狀態(tài)機設計得過于復雜后來花了半天時間回退到簡單四狀態(tài)方案。代碼提交時養(yǎng)成寫清晰message的習慣比如feat: 新增課程列表頁面、fix: 修復預約并發(fā)超賣問題。習慣的養(yǎng)成對于論文里的“系統(tǒng)測試”章節(jié)也很有用因為你可以翻Git提交記錄來回憶什么時候修了哪些問題。最后再分享一個實際開發(fā)中的小技巧wx.request的timeout默認是60000毫秒但有些接口在高并發(fā)下響應慢。如果用戶看不到加載中的提示就會反復點擊預約按鈕造成重復請求??梢栽陬A約接口里加一個冪等判斷同一用戶在同一秒內(nèi)重復提交相同課程預約直接返回“處理中”不要走第二次數(shù)據(jù)庫更新邏輯。健身管理系統(tǒng)這個項目邊界清晰、需求明確、技術棧常見用來做畢設或面試作品都很合適。希望這篇拆解能幫你把系統(tǒng)做得更扎實。