跳至主要内容
💬 回報這一頁

硬鎖定與明確解鎖

問題

一筆單據被「確認」之後,還能不能改?

這題沒有共識就上線,一定會吵一次。常見的三種答案:

做法問題
完全不能改打錯字也不能改,使用者只好開一張沖銷單
能改,改了自動解除確認最危險:使用者不知道自己剛剛把已核准的東西打回未核准
能改,但要明確解鎖← 本模式

做法

確認 = 資料凍結。要改,必須先明確解除確認。

未確認 ──確認──→ 已確認(凍結)

└──明確「取消確認」──→ 未確認(可改)

三個層次的守衛,缺一不可:

1. 資料層守衛(權威)

所有寫入操作在資料層檢查鎖定狀態,已鎖定就直接 no-op。 不是回傳錯誤,是什麼都不做——因為到這一層才擋,代表 UI 已經漏了, 這時候最重要的是資料不能壞。

2. UI 預攔

按下去之前就擋,並且說清楚原因與解法:「此筆已確認,需先取消確認才能修改」。

3. 視覺標示

鎖定的欄位顯示鎖頭,而且仍然可以聚焦——螢幕報讀器要唸得到為什麼不能改。

取捨

代價:多一個步驟。 使用者要改已確認的資料時,得先解鎖。

這個代價是故意的。它把「我要改一筆已經核准的東西」這件事變成一個 需要刻意做的決定,而不是一次不小心的點擊。

反例

✅ 這樣做

解鎖是一個明確動作,而且會被記錄下來(誰、何時、為什麼解鎖)。

🚫 不要這樣

「編輯自動解除確認」。使用者只是想看看能不能改, 點了一下,整筆單據就退回未確認狀態——而且沒有任何提示。 下游流程(結案、請款)跟著全部回捲。

✅ 這樣做

解除確認時連帶處理衍生資料(例如刪掉當期的凍結快照), 重新確認時再重建。

🚫 不要這樣

不要只改狀態旗標。留著舊快照的話,會出現「狀態是未確認、 但報表還是舊數字」的鬼故事。

實作提示

  • 鎖定判定寫成一個函式isLocked(period)),資料層與 UI 共用同一份邏輯
  • 所有 mutation 開頭第一行就是這個守衛,不要散在各處
  • 寫一個測試:對已鎖定的資料呼叫每一個 mutation,斷言狀態完全不變