feat(sale): 進付款前確認下位機(XinYuan)連線,失連自動重連 (移植 Honlifeng)
點商品進付款(onBuyRequested)前先 ping 主櫃下位機;失連→checkAndReconnectDev 重連→再確認, 連上才開 BuyDialog、連不上跳大字提示擋住。檢查期間顯示「下位機連線判斷中」轉圈框。 MyApp 新增 pingXinYuanOnce/isXinYuanAlive/ensureXinYuanConnected。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
54b44f5cf4
commit
c1da062d1d
@ -643,6 +643,40 @@ public class MyApp extends Application {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 進支付前用:送同步包確認主櫃(XinYuan)下位機是否真的有回應。
|
||||
* 先清掉舊 buffer 再送,避免讀到先前殘留的回應誤判為已連線。
|
||||
* 注意:會 Thread.sleep,請在背景執行緒呼叫。
|
||||
*/
|
||||
private static boolean pingXinYuanOnce(long waitMs) {
|
||||
if (devXinYuanController == null) return false;
|
||||
try {
|
||||
devXinYuanController.clearReadBuffers();
|
||||
devXinYuanController.addSendBuffer(
|
||||
devXinYuanController.getDevXinYuan().syncPackNo((byte) 0x01));
|
||||
Thread.sleep(waitMs);
|
||||
return !devXinYuanController.getReadBufferByMax().isEmpty();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 連送同步包兩次,任一次有回應即視為連線,降低偶發誤判(單次沒回不代表失連)。 */
|
||||
public static boolean isXinYuanAlive() {
|
||||
return pingXinYuanOnce(300) || pingXinYuanOnce(300);
|
||||
}
|
||||
|
||||
/**
|
||||
* 進支付前用:確認主櫃下位機連線;若失連則主動重連後再確認。
|
||||
* 回傳最終是否連線成功(false=連不上,呼叫端應擋住不進支付)。
|
||||
* 注意:會 Thread.sleep,請在背景執行緒呼叫。
|
||||
*/
|
||||
public static boolean ensureXinYuanConnected() {
|
||||
if (isXinYuanAlive()) return true;
|
||||
checkAndReconnectDev(); // 主動重連
|
||||
return isXinYuanAlive(); // 重連後再確認
|
||||
}
|
||||
|
||||
public void initMqtt() {
|
||||
String machineId = MyApp.getInstance().getMachine().getMachineID();
|
||||
String apiKey = MyApp.getInstance().getMachine().getApiKey();
|
||||
|
||||
@ -28,7 +28,81 @@ public class BasicSaleFlow extends SaleFlowHandler {
|
||||
|
||||
@Override
|
||||
public void onBuyRequested() {
|
||||
new BuyDialog(context, handlerMain).show();
|
||||
// 進支付前先確認主櫃下位機(XinYuan)連線:
|
||||
// 僅當購物清單含主櫃(VMC)商品才檢查;失連→主動重連→仍連不上則擋住不進支付。
|
||||
if (!buyListHasMainCabinetItem()) {
|
||||
new BuyDialog(context, handlerMain).show();
|
||||
return;
|
||||
}
|
||||
// 顯示「連線判斷中」轉圈提示,避免客戶以為當機。
|
||||
final android.app.AlertDialog progress = buildConnectingDialog();
|
||||
try { progress.show(); } catch (Exception ignore) {}
|
||||
// ensureXinYuanConnected 內含 Thread.sleep,必須在背景執行緒跑。
|
||||
new Thread(() -> {
|
||||
boolean connected = MyApp.ensureXinYuanConnected();
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
||||
try { if (progress.isShowing()) progress.dismiss(); } catch (Exception ignore) {}
|
||||
if (!connected) {
|
||||
showNotConnectedDialog();
|
||||
return;
|
||||
}
|
||||
new BuyDialog(context, handlerMain).show();
|
||||
});
|
||||
}).start();
|
||||
}
|
||||
|
||||
/** 購物清單是否含主櫃(VMC)商品;非主櫃商品不需檢查主櫃下位機連線。 */
|
||||
private boolean buyListHasMainCabinetItem() {
|
||||
for (BuyStructure b : MyApp.getInstance().getBuyList()) {
|
||||
if (b.getField() == com.unibuy.smartdevice.devices.SlotField.VMC.getField()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** 連線判斷中:轉圈圈 + 提示文字(不可取消)。 */
|
||||
private android.app.AlertDialog buildConnectingDialog() {
|
||||
android.widget.LinearLayout layout = new android.widget.LinearLayout(context);
|
||||
layout.setOrientation(android.widget.LinearLayout.HORIZONTAL);
|
||||
layout.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||
int pad = dp(32);
|
||||
layout.setPadding(pad, pad, pad, pad);
|
||||
|
||||
android.widget.ProgressBar spinner = new android.widget.ProgressBar(context);
|
||||
android.widget.LinearLayout.LayoutParams sp =
|
||||
new android.widget.LinearLayout.LayoutParams(dp(56), dp(56));
|
||||
sp.rightMargin = dp(24);
|
||||
layout.addView(spinner, sp);
|
||||
|
||||
android.widget.TextView tv = new android.widget.TextView(context);
|
||||
tv.setText("下位機連線判斷中......");
|
||||
tv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 28);
|
||||
tv.setTextColor(android.graphics.Color.BLACK);
|
||||
layout.addView(tv);
|
||||
|
||||
return new android.app.AlertDialog.Builder(context)
|
||||
.setView(layout)
|
||||
.setCancelable(false)
|
||||
.create();
|
||||
}
|
||||
|
||||
/** 主櫃未連線:跳出大字提示框。 */
|
||||
private void showNotConnectedDialog() {
|
||||
android.app.AlertDialog dialog = new android.app.AlertDialog.Builder(context)
|
||||
.setMessage("主櫃尚未連線,請稍後再試")
|
||||
.setCancelable(false)
|
||||
.setPositiveButton("確定", (d, w) -> d.dismiss())
|
||||
.create();
|
||||
try { dialog.show(); } catch (Exception ignore) { return; }
|
||||
android.widget.TextView msg = dialog.findViewById(android.R.id.message);
|
||||
if (msg != null) msg.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 28);
|
||||
android.widget.Button btn = dialog.getButton(android.app.AlertDialog.BUTTON_POSITIVE);
|
||||
if (btn != null) btn.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, 24);
|
||||
}
|
||||
|
||||
private int dp(int v) {
|
||||
return Math.round(v * context.getResources().getDisplayMetrics().density);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
Reference in New Issue
Block a user