[REFACTOR] 取貨口閘門由進場改為付款前檢查,並修正發版腳本與語系下發
1. 取貨口閘門時機調整(basic 模式):移除「進入銷售頁」的總閘門,改在「準備付款時」於 BuyDialog 檢查。
- VmcFragment:移除 maybeRunPickupPortEntryGate 與 entryGateChecked,startOnSwitchFragment 還原為僅更新清單。
- RecyclerVmcBuyListAdpter:移除 checkPickupPortOnEntry 與 DevEntryGateByVMC 整段(進場閘門)。
- BuyDialog:新增 checkPickupPortBeforePay 與 DevCheckPickupByVMC,取貨口有東西(0x05)或門沒關(0x06/0x09)時提示,
使用者確認後以 Option.FORCE_CLOSE 關閉付款頁回銷售頁;機器無回應(3000ms 超時)視為正常放行。
2. StarCloudAPI 語系下發改為後台優先:每次下發機台預設語系即立即套用,覆蓋使用者先前手動選擇
(設定下發頻率低且皆在無人時段,不會打斷操作)。
3. dialog_buy.xml:選擇支付方式頁的 Line Pay 按鈕文字由「掃碼支付」改為「Line Pay 支付」。
4. app/build.gradle:verPatch 4 → 5(S9XYU 正式發版,versionCode 210205 / versionName 21_02_5_R)。
5. release-apk workflow:修正終止 Gradle Daemon 段落的腳本自殺 bug,比對字串改為拆字串拼接並以 grep -vx "$$"
排除自身 PID,避免背景任務中 pgrep -f 命中腳本本身導致 exit 144。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f905380597
commit
84c7ac8933
@ -33,13 +33,20 @@ description: 自動編譯正式發行 Release APK、升級 Patch 版本號、並
|
||||
// turbo
|
||||
# 終止殘留的 Gradle Daemon 程序,避免多個 Daemon 互搶資源,同時避免誤殺 VS Code Gradle 擴充功能
|
||||
# 防呆:先優雅 --stop;僅在仍殘留時才升級終止(先 TERM 再 KILL),避免無差別強殺撞鎖導致 clean 編譯隨機失敗
|
||||
#
|
||||
# ⚠️ 關鍵:pgrep/pkill 的比對字串必須「拆開」拼接,不可在本檔字面寫出完整 class 名。
|
||||
# 否則在背景任務(bash -c "...eval '整段腳本'...")情境下,腳本自己的命令列會含有
|
||||
# 完整的 GradleDaemon class 字串 → pgrep -f 比對到自己 → pkill 把跑腳本的 bash 自殺
|
||||
# → exit 144,編譯根本還沒開始。再加 -vx $$ 排除自身 PID 雙重保險。
|
||||
DAEMON_PAT='org.gradle.launcher.daemon.bootstrap''.GradleDaemon' # 字面被拆開,pgrep 不會命中本腳本
|
||||
daemon_alive() { pgrep -f "$DAEMON_PAT" 2>/dev/null | grep -vx "$$" | grep -q .; }
|
||||
./gradlew --stop 2>/dev/null || true
|
||||
sleep 2
|
||||
if pgrep -f "org.gradle.launcher.daemon.bootstrap.GradleDaemon" >/dev/null 2>&1; then
|
||||
pkill -TERM -f "org.gradle.launcher.daemon.bootstrap.GradleDaemon" 2>/dev/null || true
|
||||
if daemon_alive; then
|
||||
pkill -TERM -f "$DAEMON_PAT" 2>/dev/null || true
|
||||
sleep 3
|
||||
if pgrep -f "org.gradle.launcher.daemon.bootstrap.GradleDaemon" >/dev/null 2>&1; then
|
||||
pkill -9 -f "org.gradle.launcher.daemon.bootstrap.GradleDaemon" 2>/dev/null || true
|
||||
if daemon_alive; then
|
||||
pkill -9 -f "$DAEMON_PAT" 2>/dev/null || true
|
||||
sleep 2
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -10,7 +10,7 @@ plugins {
|
||||
// 避免不同尺寸機台間版本號產生衝突。
|
||||
// =========================================================================
|
||||
def verMinor = 2
|
||||
def verPatch = 3
|
||||
def verPatch = 5
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1104,10 +1104,9 @@ public class StarCloudAPI {
|
||||
: com.unibuy.smartdevice.utils.LanguageHelper.canonicalize(def);
|
||||
MyApp.getInstance().setDefaultLanguage(canonicalDef);
|
||||
|
||||
// 首次(使用者尚未手動選過語言)套用機台預設語系
|
||||
android.content.SharedPreferences prefs = handlerMain.getContext()
|
||||
.getSharedPreferences("app_prefs", android.content.Context.MODE_PRIVATE);
|
||||
if (!canonicalDef.isEmpty() && prefs.getString("language", null) == null) {
|
||||
// 後台優先:每次下發都以機台預設語系為準,立即套用(覆蓋使用者先前手動選擇)。
|
||||
// 設定下發頻率極低且皆在無人時段,不會打斷使用者操作。
|
||||
if (!canonicalDef.isEmpty()) {
|
||||
com.unibuy.smartdevice.utils.LanguageHelper.changeLanguage(handlerMain.getContext(), canonicalDef);
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,101 +357,6 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 購物車模式專用:進入銷售頁時的「取貨口總閘門」 =====
|
||||
// 與員工卡點擊用的 checkSlotHaveProduct / DevCheckSlotByVMC 完全獨立,不影響線上 main(晟崴/中國醫)流程。
|
||||
// 取貨口有東西(0x05) 或 門沒關(0x06/0x09) 時跳提示,使用者確認後執行 onBlocked(回待機)。
|
||||
// 機器無回應(3000ms 超時) 視為正常放行,避免卡死。
|
||||
public void checkPickupPortOnEntry(int slot, Runnable onBlocked) {
|
||||
java.util.concurrent.atomic.AtomicBoolean isHandled = new java.util.concurrent.atomic.AtomicBoolean(false);
|
||||
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
if (!isHandled.getAndSet(true)) {
|
||||
logs.info("Entry Gate Check Timeout - 放行購物 (Timeout Safeguard)");
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
MyApp.getInstance().getDevXinYuanController().addSendBuffer(
|
||||
MyApp.getInstance().getDevXinYuanController().getDevXinYuan().checkSlotPre(slot, 1));
|
||||
MyApp.getInstance().getDevXinYuanController().addSendBuffer(
|
||||
MyApp.getInstance().getDevXinYuanController().getDevXinYuan().checkSlot(slot));
|
||||
MyApp.getInstance().getDevXinYuanController().getReadBufferByNow(
|
||||
new DevEntryGateByVMC(fragment.getSrcHandlerMain(), isHandled, onBlocked), 800);
|
||||
}
|
||||
|
||||
public class DevEntryGateByVMC extends DevController.ReadBufferOnScheduler {
|
||||
private final java.util.concurrent.atomic.AtomicBoolean isHandled;
|
||||
private final Runnable onBlocked;
|
||||
|
||||
public DevEntryGateByVMC(HandlerMain handlerMain,
|
||||
java.util.concurrent.atomic.AtomicBoolean isHandled, Runnable onBlocked) {
|
||||
super(handlerMain);
|
||||
this.isHandled = isHandled;
|
||||
this.onBlocked = onBlocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HandlerMain setHandlerMain() {
|
||||
return getSrcHandlerMain();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> setCls() {
|
||||
return getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readBufferOnScheduler(DevController devController, HandlerMain handlerMain) {
|
||||
boolean haveThings = false;
|
||||
boolean doorError = false;
|
||||
for (byte[] buffer : devController.getReadBufferByMax()) {
|
||||
if (buffer[0] == 0x02) {
|
||||
if (buffer[1] == 0x05) {
|
||||
haveThings = true;
|
||||
break;
|
||||
} else if (buffer[1] == 0x06 || buffer[1] == 0x09) {
|
||||
doorError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 狀態安全:不做任何事,放行購物(總閘門通過)
|
||||
if (!haveThings && !doorError) return;
|
||||
// 已被超時或前一筆回覆處理過,避免重複跳窗
|
||||
if (isHandled.getAndSet(true)) return;
|
||||
|
||||
final String message = doorError
|
||||
? "取貨口門未正常關閉,請先確認門已關好。"
|
||||
: context.getString(R.string.there_is_something_at_the_pickup_port);
|
||||
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
AlertDialog dialog = new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.abnormal_reminder)
|
||||
.setMessage(message)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.i_knew, (d, which) -> {
|
||||
d.dismiss();
|
||||
if (onBlocked != null) onBlocked.run();
|
||||
})
|
||||
.create();
|
||||
dialog.show();
|
||||
|
||||
TextView messageView = dialog.findViewById(android.R.id.message);
|
||||
if (messageView != null) {
|
||||
messageView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 24);
|
||||
}
|
||||
|
||||
// 10 秒後自動回待機,避免無人理會卡在提示
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
if (dialog.isShowing()) {
|
||||
dialog.dismiss();
|
||||
if (onBlocked != null) onBlocked.run();
|
||||
}
|
||||
}, 10_000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class DevDetectSlotByVMC extends DevController.ReadBufferOnScheduler {
|
||||
private int position;
|
||||
|
||||
|
||||
@ -313,37 +313,8 @@ public class VmcFragment extends FragmentAbstract {
|
||||
|| product.getSellingPrice() < 0;
|
||||
}
|
||||
|
||||
private boolean entryGateChecked = false;
|
||||
|
||||
@Override
|
||||
public void startOnSwitchFragment() {
|
||||
updateFlowerBuyList();
|
||||
maybeRunPickupPortEntryGate();
|
||||
}
|
||||
|
||||
/**
|
||||
* basic 模式(shopping_mode==basic,不論購物車開關)進入銷售頁時的「取貨口總閘門」:
|
||||
* 取貨口有東西或門沒關就跳提示並回待機,確保「加入購物車 / 直接購買 / 快速加購 / 單品直購」
|
||||
* 各路徑在源頭被擋住。每輪購物只檢查一次(FontendActivity 每輪重建 fragment,旗標自動重置)。
|
||||
* 員工卡(employee_card)流程已在點擊時自行檢查、pickup_sheet 不檢查,皆不在此重複。
|
||||
*/
|
||||
private void maybeRunPickupPortEntryGate() {
|
||||
if (entryGateChecked) return;
|
||||
boolean isBasic = "basic".equals(MyApp.getInstance().getShoppingMode());
|
||||
if (!isBasic) return;
|
||||
if (recyclerVmcBuyListAdpter == null) return;
|
||||
entryGateChecked = true;
|
||||
|
||||
// 延遲送出,等下位機(新源 VMC)連線就緒;過早送出會超時放行而失去保護。
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).postDelayed(() -> {
|
||||
int gateSlot = (slotList != null && !slotList.isEmpty()) ? slotList.get(0).getSlot() : 1;
|
||||
recyclerVmcBuyListAdpter.checkPickupPortOnEntry(gateSlot, () -> {
|
||||
if (getActivity() instanceof FontendActivity) {
|
||||
((FontendActivity) getActivity()).ReSetAPP();
|
||||
}
|
||||
});
|
||||
}, 2500);
|
||||
}
|
||||
public void startOnSwitchFragment() { updateFlowerBuyList(); }
|
||||
|
||||
@Override
|
||||
public void stopOnSwitchFragment() {
|
||||
|
||||
@ -259,6 +259,92 @@ public class BuyDialog extends DialogAbstract {
|
||||
binding.buttonCash.setVisibility(MyApp.getInstance().getDevSet().canCash() ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
// 準備付款時檢查取貨口(basic 模式):取貨口有東西(0x05)/門沒關(0x06、0x09) 就提示並關閉付款頁回銷售頁。
|
||||
// 員工卡(點擊已自檢)、取貨碼(自有檢查)、pickup_sheet 不在此檢查。
|
||||
if ("basic".equals(MyApp.getInstance().getShoppingMode())) {
|
||||
checkPickupPortBeforePay();
|
||||
}
|
||||
}
|
||||
|
||||
// 準備付款時檢查取貨口(basic 模式)。送 checkSlot 後 800ms 讀回;此時距實際出貨還有數秒
|
||||
// (使用者尚未選付款),不會與出貨流程搶同一條 DevXinYuanController。機器無回應(3000ms 超時)視為正常放行。
|
||||
private void checkPickupPortBeforePay() {
|
||||
java.util.concurrent.atomic.AtomicBoolean isHandled = new java.util.concurrent.atomic.AtomicBoolean(false);
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).postDelayed(
|
||||
() -> isHandled.getAndSet(true), 3000);
|
||||
MyApp.getInstance().getDevXinYuanController().addSendBuffer(
|
||||
MyApp.getInstance().getDevXinYuanController().getDevXinYuan().checkSlotPre(1, 1));
|
||||
MyApp.getInstance().getDevXinYuanController().addSendBuffer(
|
||||
MyApp.getInstance().getDevXinYuanController().getDevXinYuan().checkSlot(1));
|
||||
MyApp.getInstance().getDevXinYuanController().getReadBufferByNow(
|
||||
new DevCheckPickupByVMC(getHandlerMain(), isHandled), 800);
|
||||
}
|
||||
|
||||
private class DevCheckPickupByVMC extends com.unibuy.smartdevice.controller.DevController.ReadBufferOnScheduler {
|
||||
private final java.util.concurrent.atomic.AtomicBoolean isHandled;
|
||||
private final HandlerMain dialogHandler;
|
||||
|
||||
DevCheckPickupByVMC(HandlerMain handlerMain, java.util.concurrent.atomic.AtomicBoolean isHandled) {
|
||||
super(handlerMain);
|
||||
this.dialogHandler = handlerMain;
|
||||
this.isHandled = isHandled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HandlerMain setHandlerMain() {
|
||||
return dialogHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> setCls() {
|
||||
return getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readBufferOnScheduler(com.unibuy.smartdevice.controller.DevController devController, HandlerMain handlerMain) {
|
||||
boolean haveThings = false;
|
||||
boolean doorError = false;
|
||||
for (byte[] buffer : devController.getReadBufferByMax()) {
|
||||
if (buffer[0] == 0x02) {
|
||||
if (buffer[1] == 0x05) {
|
||||
haveThings = true;
|
||||
break;
|
||||
} else if (buffer[1] == 0x06 || buffer[1] == 0x09) {
|
||||
doorError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 狀態安全:放行付款
|
||||
if (!haveThings && !doorError) return;
|
||||
// 已被超時或前一筆處理過,避免重複跳窗
|
||||
if (isHandled.getAndSet(true)) return;
|
||||
|
||||
final String message = doorError
|
||||
? "取貨口門未正常關閉,請先確認門已關好。"
|
||||
: BuyDialog.this.getContext().getString(R.string.there_is_something_at_the_pickup_port);
|
||||
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
||||
android.app.AlertDialog dialog = new android.app.AlertDialog.Builder(BuyDialog.this.getContext())
|
||||
.setTitle(R.string.abnormal_reminder)
|
||||
.setMessage(message)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.i_knew, (d, which) -> {
|
||||
d.dismiss();
|
||||
// 關閉付款頁回銷售頁
|
||||
dialogHandler.start("BuyDialogPickupCheck",
|
||||
Option.FORCE_CLOSE.getOption(), "pickup port blocked");
|
||||
})
|
||||
.create();
|
||||
dialog.show();
|
||||
android.widget.TextView mv = dialog.findViewById(android.R.id.message);
|
||||
if (mv != null) {
|
||||
mv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 24);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** 商品原始總額(未套用來店禮折扣),不含免費商品。 */
|
||||
|
||||
@ -322,7 +322,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="掃碼支付"
|
||||
android:text="Line Pay 支付"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="25sp" />
|
||||
</LinearLayout>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user