소스 검색

调整外置rfid读取白名单,支持外置rfid标签读取及绑定

angelcstt 1 주 전
부모
커밋
29fa2bcfb3
25개의 변경된 파일634개의 추가작업 그리고 93개의 파일을 삭제
  1. 19 0
      app/src/main/java/com/rc/core/ui/activity/BaseActivity.java
  2. 3 0
      app/src/main/java/xn/hxp/app/ChemicalApp.kt
  3. 62 0
      app/src/main/java/xn/hxp/receiver/UhfRfidKeyEventHelper.kt
  4. 127 0
      app/src/main/java/xn/hxp/receiver/UhfRfidManager.kt
  5. 5 0
      app/src/main/java/xn/hxp/ui/MainActivity.java
  6. 88 0
      app/src/main/java/xn/hxp/ui/SettingActivity.java
  7. 36 3
      app/src/main/java/xn/hxp/ui/StartActivity.java
  8. 5 0
      app/src/main/java/xn/hxp/ui/discard/WasteChemicalsActivity.kt
  9. 18 0
      app/src/main/java/xn/hxp/ui/inquiry/InquiryActivity.java
  10. 5 0
      app/src/main/java/xn/hxp/ui/login/FacialCardActivity.kt
  11. 5 0
      app/src/main/java/xn/hxp/ui/login/SwipeActivity.kt
  12. 4 0
      app/src/main/java/xn/hxp/ui/plan/PlanAddActivity.java
  13. 5 25
      app/src/main/java/xn/hxp/ui/still/ChemicalsAlsoActivity.kt
  14. 4 0
      app/src/main/java/xn/hxp/ui/verify/DoubleVerifyActivity.java
  15. 5 0
      app/src/main/java/xn/hxp/ui/verify/SwipeCodeTwoActivity.kt
  16. 5 0
      app/src/main/java/xn/hxp/ui/verify/TwoVerificationActivity.kt
  17. 11 26
      app/src/main/java/xn/hxp/ui/warehousing/ChemicalLabelingActivity.kt
  18. 20 21
      app/src/main/java/xn/hxp/weidith/AirBottleDialog.kt
  19. 21 14
      app/src/main/java/xn/hxp/weidith/AirBottleNewDialog.kt
  20. 27 2
      app/src/main/java/xn/hxp/weidith/LabelDialog.kt
  21. 5 0
      app/src/main/java/xn/hxp/weidith/UsageLabelDialog.java
  22. 119 0
      app/src/main/res/layout/activity_setting.xml
  23. 1 1
      app/src/main/res/layout/item_chemical_labeling.xml
  24. 31 0
      chinaSafetyReq.md
  25. 3 1
      settings.gradle

+ 19 - 0
app/src/main/java/com/rc/core/ui/activity/BaseActivity.java

@@ -1,6 +1,7 @@
 package com.rc.core.ui.activity;
 
 import android.os.Bundle;
+import android.view.KeyEvent;
 import android.view.ViewGroup;
 
 import androidx.annotation.Nullable;
@@ -19,6 +20,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable;
 import io.reactivex.rxjava3.disposables.Disposable;
 import xn.hxp.app.ChemicalApp;
 import xn.hxp.comm.Constants;
+import xn.hxp.receiver.UhfRfidManager;
 
 public abstract class BaseActivity extends AppCompatActivity {
 
@@ -157,4 +159,21 @@ public abstract class BaseActivity extends AppCompatActivity {
         isCountCdTime = false;
         ThreadUtils.cancel(cdTask);
     }
+
+    /**
+     * 统一拦截外置超高频RFID读卡器的KeyEvent
+     * 所有继承BaseActivity的页面默认丢弃外置读卡器输入,防止crash
+     * 需要处理的页面(白名单业务)在子类中override并自行处理
+     */
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        try {
+            if (UhfRfidManager.INSTANCE.isEnabled(this) && UhfRfidManager.INSTANCE.isUhfRfidEvent(this, event)) {
+                return true;
+            }
+        } catch (Exception e) {
+            // 防御性处理,避免任何异常导致crash
+        }
+        return super.dispatchKeyEvent(event);
+    }
 }

+ 3 - 0
app/src/main/java/xn/hxp/app/ChemicalApp.kt

@@ -25,6 +25,7 @@ import com.rc.httpcore.bean.UserData
 import com.tencent.smtt.export.external.TbsCoreSettings
 import com.tencent.smtt.sdk.QbSdk
 import xn.hxp.R
+import xn.hxp.receiver.UhfRfidManager
 import xn.hxp.utils.Tool
 import xn.hxp.utils.bluetooth.SppTool
 
@@ -103,6 +104,8 @@ class ChemicalApp : Application() {
         appContext = applicationContext
         initLog()
         Toaster.init(this)
+        // 初始化外置超高频RFID读卡器管理器(从SharedPreferences加载配置)
+        // UhfRfidManager 是 object 单例,配置通过 SharedPreferences 按需读取
     }
 
     private fun initLog() {

+ 62 - 0
app/src/main/java/xn/hxp/receiver/UhfRfidKeyEventHelper.kt

@@ -0,0 +1,62 @@
+package xn.hxp.receiver
+
+import android.view.KeyEvent
+
+/**
+ * 外置超高频RFID读卡器专用KeyEvent解析器
+ * 与ScanKeyEventHelper类似,但:
+ * 1. 收到ENTER时仅回调内容,不传递enter给视图
+ * 2. 不设置超时自动提交(超高频RFID读卡器是快速连续输入+enter结尾)
+ */
+class UhfRfidKeyEventHelper(private val callback: ((content: String) -> Unit)? = null) {
+
+    private var mCaps = false
+    private val mKeyContent = StringBuilder()
+
+    fun analysisKeyEvent(event: KeyEvent): Boolean {
+        val keyCode = event.keyCode
+        if (KeyEvent.KEYCODE_SHIFT_RIGHT == keyCode || KeyEvent.KEYCODE_SHIFT_LEFT == keyCode) {
+            mCaps = KeyEvent.ACTION_DOWN == event.action
+            return true
+        }
+
+        if (KeyEvent.ACTION_DOWN != event.action) return true
+
+        if (KeyEvent.KEYCODE_ENTER == keyCode || KeyEvent.KEYCODE_NUMPAD_ENTER == keyCode) {
+            if (mKeyContent.isNotEmpty()) {
+                callback?.invoke(mKeyContent.toString())
+            }
+            mKeyContent.clear()
+            return true // 消费掉enter,不传递给视图
+        } else {
+            decodeKeyCode(keyCode, event)?.let { keyChar ->
+                mKeyContent.append(keyChar)
+            }
+            return true
+        }
+    }
+
+    fun clear() {
+        mKeyContent.clear()
+    }
+
+    private fun decodeKeyCode(keyCode: Int, event: KeyEvent): Char? {
+        val isShiftPressed = event.isShiftPressed
+        if (keyCode in KeyEvent.KEYCODE_0..KeyEvent.KEYCODE_9) {
+            return (keyCode - KeyEvent.KEYCODE_0 + 0x30).toChar()
+        } else if (keyCode in KeyEvent.KEYCODE_A..KeyEvent.KEYCODE_Z) {
+            return (keyCode - KeyEvent.KEYCODE_A + if (isShiftPressed) 0x41 else 0x61).toChar()
+        } else if (keyCode == KeyEvent.KEYCODE_PERIOD) {
+            return '.'
+        } else if (keyCode == KeyEvent.KEYCODE_MINUS) {
+            return if (isShiftPressed) '_' else '-'
+        } else if (keyCode == KeyEvent.KEYCODE_SLASH) {
+            return '/'
+        } else if (keyCode == KeyEvent.KEYCODE_BACKSLASH) {
+            return if (isShiftPressed) '|' else '\\'
+        } else if (keyCode == KeyEvent.KEYCODE_EQUALS) {
+            return '='
+        }
+        return null
+    }
+}

+ 127 - 0
app/src/main/java/xn/hxp/receiver/UhfRfidManager.kt

@@ -0,0 +1,127 @@
+package xn.hxp.receiver
+
+import android.content.Context
+import android.content.SharedPreferences
+import android.view.InputDevice
+import android.view.KeyEvent
+import com.blankj.utilcode.util.LogUtils
+
+/**
+ * 外置超高频RFID读卡器管理器(单例)
+ * 负责:设备学习、开关管理、白名单管理、设备识别
+ */
+object UhfRfidManager {
+
+    private const val PREF_NAME = "uhf_rfid_config"
+    private const val KEY_ENABLED = "uhf_enabled"
+    private const val KEY_DEVICE_VENDOR_ID = "uhf_vendor_id"
+    private const val KEY_DEVICE_PRODUCT_ID = "uhf_product_id"
+    private const val KEY_DEVICE_NAME = "uhf_device_name"
+    private const val KEY_WHITELIST = "uhf_whitelist"
+
+    // 白名单业务标识
+    const val PAGE_STORAGE_RFID = "storage_rfid"       // 存储模块RFID绑定
+    const val PAGE_LABEL_RFID = "label_rfid"           // 标签管理RFID绑定/更换
+    const val PAGE_INQUIRY = "inquiry"                  // 查询模块
+
+    // 学习模式
+    var isLearning = false
+    var learningCallback: ((deviceName: String) -> Unit)? = null
+
+    private fun getPrefs(context: Context): SharedPreferences {
+        return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
+    }
+
+    fun isEnabled(context: Context): Boolean {
+        return getPrefs(context).getBoolean(KEY_ENABLED, false)
+    }
+
+    fun setEnabled(context: Context, enabled: Boolean) {
+        getPrefs(context).edit().putBoolean(KEY_ENABLED, enabled).apply()
+    }
+
+    fun getDeviceVendorId(context: Context): Int {
+        return getPrefs(context).getInt(KEY_DEVICE_VENDOR_ID, -1)
+    }
+
+    fun getDeviceProductId(context: Context): Int {
+        return getPrefs(context).getInt(KEY_DEVICE_PRODUCT_ID, -1)
+    }
+
+    fun getDeviceName(context: Context): String? {
+        return getPrefs(context).getString(KEY_DEVICE_NAME, null)
+    }
+
+    fun saveDeviceInfo(context: Context, vendorId: Int, productId: Int, deviceName: String) {
+        getPrefs(context).edit()
+            .putInt(KEY_DEVICE_VENDOR_ID, vendorId)
+            .putInt(KEY_DEVICE_PRODUCT_ID, productId)
+            .putString(KEY_DEVICE_NAME, deviceName)
+            .apply()
+        LogUtils.i("UhfRfidManager: 学习设备成功 vendorId=$vendorId productId=$productId name=$deviceName")
+    }
+
+    fun hasLearnedDevice(context: Context): Boolean {
+        return getDeviceVendorId(context) != -1 && getDeviceProductId(context) != -1
+    }
+
+    /**
+     * 获取白名单集合
+     */
+    fun getWhitelist(context: Context): Set<String> {
+        val str = getPrefs(context).getString(KEY_WHITELIST, "") ?: ""
+        if (str.isEmpty()) return emptySet()
+        return str.split(",").toSet()
+    }
+
+    fun saveWhitelist(context: Context, whitelist: Set<String>) {
+        getPrefs(context).edit().putString(KEY_WHITELIST, whitelist.joinToString(",")).apply()
+    }
+
+    /**
+     * 开始学习模式,等待外置读卡器刷卡
+     */
+    fun startLearning(callback: (deviceName: String) -> Unit) {
+        isLearning = true
+        learningCallback = callback
+    }
+
+    fun isPageWhitelisted(context: Context, pageTag: String): Boolean {
+        return getWhitelist(context).contains(pageTag)
+    }
+
+    /**
+     * 判断KeyEvent是否来自已学习的外置超高频RFID读卡器
+     */
+    fun isUhfRfidEvent(context: Context, event: KeyEvent): Boolean {
+        if (!isEnabled(context)) return false
+        if (!hasLearnedDevice(context)) return false
+        val device = event.device ?: return false
+        val vendorId = getDeviceVendorId(context)
+        val productId = getDeviceProductId(context)
+        return device.vendorId == vendorId && device.productId == productId
+    }
+
+    /**
+     * 学习模式下处理KeyEvent,记录设备信息
+     * 返回true表示已消费该事件
+     */
+    fun handleLearningEvent(context: Context, event: KeyEvent): Boolean {
+        if (!isLearning) return false
+        val device = event.device ?: return false
+        // 只在ACTION_DOWN时处理,避免重复
+        if (event.action != KeyEvent.ACTION_DOWN) return true
+        // 忽略内置虚拟键盘设备
+        if (!device.isExternal) return false
+
+        val vendorId = device.vendorId
+        val productId = device.productId
+        val deviceName = device.name ?: "Unknown"
+
+        saveDeviceInfo(context, vendorId, productId, deviceName)
+        isLearning = false
+        learningCallback?.invoke(deviceName)
+        learningCallback = null
+        return true
+    }
+}

+ 5 - 0
app/src/main/java/xn/hxp/ui/MainActivity.java

@@ -59,6 +59,7 @@ import xn.hxp.R;
 import xn.hxp.app.ChemicalApp;
 import xn.hxp.databinding.ActivityMainBinding;
 import xn.hxp.receiver.TimeTickReceiver;
+import xn.hxp.receiver.UhfRfidManager;
 import xn.hxp.ui.adapter.CabinetBannerAdapter;
 import xn.hxp.ui.discard.LedgerActivity;
 import xn.hxp.ui.discard.WasteChemicalsActivity;
@@ -219,6 +220,10 @@ public class MainActivity extends BaseActivity {
 
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
+        // 首页不在白名单中,消费掉外置RFID读卡器的输入,避免引起页面异常
+        if (UhfRfidManager.INSTANCE.isEnabled(this) && UhfRfidManager.INSTANCE.isUhfRfidEvent(this, event)) {
+            return true;
+        }
         return super.dispatchKeyEvent(event);
     }
 

+ 88 - 0
app/src/main/java/xn/hxp/ui/SettingActivity.java

@@ -3,6 +3,10 @@ package xn.hxp.ui;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
 
 import androidx.viewbinding.ViewBinding;
 
@@ -15,7 +19,11 @@ import com.kongzue.dialogx.dialogs.PopTip;
 import com.kongzue.dialogx.dialogs.WaitDialog;
 import com.rc.core.ui.activity.BaseActivity;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import xn.hxp.databinding.ActivitySettingBinding;
+import xn.hxp.receiver.UhfRfidManager;
 import xn.hxp.utils.SharedPreferencesHelper;
 import xn.hxp.utils.Tool;
 import xn.hxp.utils.bluetooth.SppTool;
@@ -88,6 +96,86 @@ public class SettingActivity extends BaseActivity {
         // 保存
         binding.save.setOnClickListener(v -> save());
 
+        // 外置超高频RFID读卡器配置
+        initUhfRfidConfig();
+    }
+
+    // ========== 外置超高频RFID读卡器配置 ==========
+    private void initUhfRfidConfig() {
+        boolean uhfEnabled = UhfRfidManager.INSTANCE.isEnabled(this);
+        binding.uhfRfidSwitch.setChecked(uhfEnabled);
+        binding.uhfRfidDetailLayout.setVisibility(uhfEnabled ? View.VISIBLE : View.GONE);
+
+        // 开关监听
+        binding.uhfRfidSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
+            UhfRfidManager.INSTANCE.setEnabled(SettingActivity.this, isChecked);
+            binding.uhfRfidDetailLayout.setVisibility(isChecked ? View.VISIBLE : View.GONE);
+        });
+
+        // 已学习设备信息
+        updateUhfDeviceInfo();
+
+        // 重新学习按钮
+        binding.uhfLearnBT.setOnClickListener(v -> {
+            UhfRfidManager.INSTANCE.startLearning(deviceName -> {
+                runOnUiThread(() -> {
+                    updateUhfDeviceInfo();
+                    showToast("设备学习成功: " + deviceName);
+                });
+                return null;
+            });
+            showToast("请在外置读卡器上刷一次卡...");
+        });
+
+        // 清除配置按钮
+        binding.uhfClearBT.setOnClickListener(v -> {
+            UhfRfidManager.INSTANCE.saveDeviceInfo(SettingActivity.this, -1, -1, "");
+            UhfRfidManager.INSTANCE.setEnabled(SettingActivity.this, false);
+            binding.uhfRfidSwitch.setChecked(false);
+            updateUhfDeviceInfo();
+            showToast("已清除外置读卡器配置");
+        });
+
+        // 白名单复选框
+        Set<String> whitelist = UhfRfidManager.INSTANCE.getWhitelist(this);
+        binding.uhfWlStorageCB.setChecked(whitelist.contains(UhfRfidManager.PAGE_STORAGE_RFID));
+        binding.uhfWlLabelCB.setChecked(whitelist.contains(UhfRfidManager.PAGE_LABEL_RFID));
+        binding.uhfWlInquiryCB.setChecked(whitelist.contains(UhfRfidManager.PAGE_INQUIRY));
+
+        CompoundButton.OnCheckedChangeListener wlListener = (buttonView, isChecked) -> saveUhfWhitelist();
+        binding.uhfWlStorageCB.setOnCheckedChangeListener(wlListener);
+        binding.uhfWlLabelCB.setOnCheckedChangeListener(wlListener);
+        binding.uhfWlInquiryCB.setOnCheckedChangeListener(wlListener);
+    }
+
+    private void updateUhfDeviceInfo() {
+        if (UhfRfidManager.INSTANCE.hasLearnedDevice(this)) {
+            String name = UhfRfidManager.INSTANCE.getDeviceName(this);
+            int vid = UhfRfidManager.INSTANCE.getDeviceVendorId(this);
+            int pid = UhfRfidManager.INSTANCE.getDeviceProductId(this);
+            binding.uhfDeviceNameTV.setText((name != null ? name : "未知") + " (VID:" + vid + " PID:" + pid + ")");
+        } else {
+            binding.uhfDeviceNameTV.setText("未学习");
+        }
+    }
+
+    private void saveUhfWhitelist() {
+        Set<String> wl = new HashSet<>();
+        if (binding.uhfWlStorageCB.isChecked()) wl.add(UhfRfidManager.PAGE_STORAGE_RFID);
+        if (binding.uhfWlLabelCB.isChecked()) wl.add(UhfRfidManager.PAGE_LABEL_RFID);
+        if (binding.uhfWlInquiryCB.isChecked()) wl.add(UhfRfidManager.PAGE_INQUIRY);
+        UhfRfidManager.INSTANCE.saveWhitelist(this, wl);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        // 学习模式下拦截外部设备的KeyEvent
+        if (UhfRfidManager.INSTANCE.isLearning()) {
+            if (UhfRfidManager.INSTANCE.handleLearningEvent(this, event)) {
+                return true;
+            }
+        }
+        return super.dispatchKeyEvent(event);
     }
 
     @Override

+ 36 - 3
app/src/main/java/xn/hxp/ui/StartActivity.java

@@ -1,8 +1,10 @@
 package xn.hxp.ui;
 
+import android.app.AlertDialog;
 import android.os.CountDownTimer;
 import android.text.TextUtils;
 import android.view.View;
+import android.widget.EditText;
 
 import androidx.viewbinding.ViewBinding;
 
@@ -54,12 +56,11 @@ public class StartActivity extends BaseActivity {
 
     @Override
     protected void onInit() {
-        // 进去设置页面
+        // 进去设置页面(需要密码验证)
         binding.logo.setOnLongClickListener(new View.OnLongClickListener() {
             @Override
             public boolean onLongClick(View v) {
-                ActivityUtils.startActivity(SettingActivity.class);
-                finish();
+                showPasswordDialog();
                 return true;
             }
         });
@@ -174,4 +175,36 @@ public class StartActivity extends BaseActivity {
         super.onDestroy();
         ThreadUtils.cancel(checkTask);
     }
+
+    private void showPasswordDialog() {
+        EditText editText = new EditText(this);
+        AlertDialog dialog = new AlertDialog.Builder(this)
+                .setTitle("请输入管理员密码")
+                .setView(editText)
+                .setPositiveButton("确定", (dialog1, which) -> {
+                    String input = editText.getText().toString();
+                    if (input.isEmpty()) return;
+                    String defaultPwd = "admin@098&";
+                    try {
+                        SettingsBean settingsBean = SharedPreferencesHelper.INSTANCE.getUrlBase(StartActivity.this);
+                        String savedPwd = (settingsBean != null && settingsBean.getPwd() != null) ? settingsBean.getPwd() : defaultPwd;
+                        if (input.equals(savedPwd) || input.equals(defaultPwd)) {
+                            ActivityUtils.startActivity(SettingActivity.class);
+                            finish();
+                        } else {
+                            PopTip.show("密码错误");
+                        }
+                    } catch (Exception e) {
+                        if (input.equals(defaultPwd)) {
+                            ActivityUtils.startActivity(SettingActivity.class);
+                            finish();
+                        } else {
+                            PopTip.show("密码错误");
+                        }
+                    }
+                })
+                .setNegativeButton("取消", null)
+                .create();
+        dialog.show();
+    }
 }

+ 5 - 0
app/src/main/java/xn/hxp/ui/discard/WasteChemicalsActivity.kt

@@ -30,6 +30,7 @@ import xn.hxp.comm.Constants
 import xn.hxp.databinding.ActivityWasteChemicalsBinding
 import xn.hxp.receiver.OnSerialScanListener
 import xn.hxp.receiver.PortScanHelper
+import xn.hxp.receiver.UhfRfidManager
 import xn.hxp.receiver.UsbReceiver
 import xn.hxp.ui.adapter.WasteChemicalsAdapter
 import xn.hxp.ui.verify.TwoVerificationActivity
@@ -1186,6 +1187,10 @@ class WasteChemicalsActivity : BaseActivity() {
 
     //获取刷卡信息
     override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        // 消费掉外置RFID读卡器的输入,此页面不在白名单中
+        if (UhfRfidManager.isEnabled(this) && UhfRfidManager.isUhfRfidEvent(this, event)) {
+            return true
+        }
         mPortScanHelper.dispatchKeyEvent(event)
         return super.dispatchKeyEvent(event)
     }

+ 18 - 0
app/src/main/java/xn/hxp/ui/inquiry/InquiryActivity.java

@@ -44,6 +44,8 @@ import xn.hxp.app.ChemicalApp;
 import xn.hxp.databinding.ActivityInquiryBinding;
 import xn.hxp.receiver.OnSerialScanListener;
 import xn.hxp.receiver.PortScanHelper;
+import xn.hxp.receiver.UhfRfidKeyEventHelper;
+import xn.hxp.receiver.UhfRfidManager;
 import xn.hxp.receiver.UsbReceiver;
 import xn.hxp.ui.DoubleDialogBean;
 import xn.hxp.ui.adapter.CabinetDoorAdapter;
@@ -136,6 +138,15 @@ public class InquiryActivity extends BaseActivity {
         }
     });
 
+    // 外置超高频RFID读卡器解析器
+    private final UhfRfidKeyEventHelper mUhfRfidHelper = new UhfRfidKeyEventHelper(content -> {
+        if (!mHandleScanEvent && content != null && !content.isEmpty()) {
+            mHandleScanEvent = true;
+            handleScanEvent(content);
+        }
+        return null;
+    });
+
     private void initData() {
         logIn = getIntent().getIntExtra("logIn", 0);
         String stringExtra = getIntent().getStringExtra("cabinetId");
@@ -440,6 +451,13 @@ public class InquiryActivity extends BaseActivity {
 
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
+        // 外置超高频RFID读卡器输入 - 仅在白名单中处理
+        if (UhfRfidManager.INSTANCE.isEnabled(this) && UhfRfidManager.INSTANCE.isUhfRfidEvent(this, event)) {
+            if (UhfRfidManager.INSTANCE.isPageWhitelisted(this, UhfRfidManager.PAGE_INQUIRY)) {
+                mUhfRfidHelper.analysisKeyEvent(event);
+            }
+            return true; // 无论是否在白名单,都消费掉外置读卡器事件
+        }
         mPortScanHelper.dispatchKeyEvent(event);
         return super.dispatchKeyEvent(event);
     }

+ 5 - 0
app/src/main/java/xn/hxp/ui/login/FacialCardActivity.kt

@@ -19,6 +19,7 @@ import xn.hxp.comm.Constants
 import xn.hxp.databinding.ActivityFacialCardBinding
 import xn.hxp.receiver.OnSerialScanListener
 import xn.hxp.receiver.PortScanHelper
+import xn.hxp.receiver.UhfRfidManager
 import xn.hxp.receiver.UsbReceiver
 import xn.hxp.weidith.AuthenticationDialog
 import xn.hxp.weidith.CustomDialog
@@ -308,6 +309,10 @@ class FacialCardActivity : BaseActivity() {
 
     //获取刷卡信息
     override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        // 消费掉外置RFID读卡器的输入
+        if (UhfRfidManager.isEnabled(this) && UhfRfidManager.isUhfRfidEvent(this, event)) {
+            return true
+        }
         mPortScanHelper.dispatchKeyEvent(event)
         return super.dispatchKeyEvent(event)
     }

+ 5 - 0
app/src/main/java/xn/hxp/ui/login/SwipeActivity.kt

@@ -31,6 +31,7 @@ import xn.hxp.app.ChemicalApp
 import xn.hxp.databinding.ActivitySwipeBinding
 import xn.hxp.receiver.OnSerialScanListener
 import xn.hxp.receiver.PortScanHelper
+import xn.hxp.receiver.UhfRfidManager
 import xn.hxp.receiver.UsbReceiver
 import xn.hxp.ui.MainActivity
 import xn.hxp.utils.AudioPlayer
@@ -216,6 +217,10 @@ class SwipeActivity : BaseActivity() {
 
     //获取刷卡信息
     override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        // 消费掉外置RFID读卡器的输入
+        if (UhfRfidManager.isEnabled(this) && UhfRfidManager.isUhfRfidEvent(this, event)) {
+            return true
+        }
         mPortScanHelper.dispatchKeyEvent(event)
         return super.dispatchKeyEvent(event)
     }

+ 4 - 0
app/src/main/java/xn/hxp/ui/plan/PlanAddActivity.java

@@ -306,6 +306,10 @@ public class PlanAddActivity extends BaseActivity {
 
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
+        // 消费掉外置RFID读卡器的输入,此页面不在白名单中
+        if (xn.hxp.receiver.UhfRfidManager.INSTANCE.isEnabled(this) && xn.hxp.receiver.UhfRfidManager.INSTANCE.isUhfRfidEvent(this, event)) {
+            return true;
+        }
         // https://labcontrol.nwafu.edu.cn/api/?code=5020641&type=9
         if (null != portScanHelper) {
             portScanHelper.dispatchKeyEvent(event);

+ 5 - 25
app/src/main/java/xn/hxp/ui/still/ChemicalsAlsoActivity.kt

@@ -43,6 +43,7 @@ import xn.hxp.comm.Constants
 import xn.hxp.databinding.ActivityChemicalsAlsoBinding
 import xn.hxp.receiver.OnSerialScanListener
 import xn.hxp.receiver.PortScanHelper
+import xn.hxp.receiver.UhfRfidManager
 import xn.hxp.receiver.UsbReceiver
 import xn.hxp.ui.PrintBean
 import xn.hxp.ui.adapter.ReturningChemicalsAdapter
@@ -376,31 +377,6 @@ class ChemicalsAlsoActivity : BaseActivity() {
             dismissLoading()
             customDialogView(1, "更换成功")
             mHandleScanEvent = false
-            //补打标签
-            val print = PrintBean()
-            print.tag = mDataBean.tagCode  //化学品编码
-            print.wxCode = mDataBean.wxCode!!
-            print.name = mDataBean.chemicalName!! //化学品名称
-            if (mDataBean.casNum != null) {
-                print.casNo = mDataBean.casNum!!  //cas号
-            } else {
-                print.casNo = ""
-            }
-//            if (mDataBean.topicGroup) {
-//                print.person = mDataBean.topicGroupName //归属人
-//            } else {
-//                print.person = mDataBean.applyUserName //归属人
-//            }
-            print.person = mDataBean.belongName
-            //管控 1     非管控  2
-            if (mDataBean.chemicalLevel == 1) {
-                print.level = "管控"
-            } else {
-                print.level = "非管控"
-            }
-            //
-            print.types = "${mDataBean.chemicalCategoryName}"
-            PrintTool.INSTANCE.print(mDataBean.isGr, mDataBean.belongType == 2, print)
         }, { throwable ->
             dismissLoading()
             showNetError(throwable)
@@ -1441,6 +1417,10 @@ class ChemicalsAlsoActivity : BaseActivity() {
 
     //获取刷卡信息
     override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        // 消费掉外置RFID读卡器的输入,此页面不在白名单中
+        if (UhfRfidManager.isEnabled(this) && UhfRfidManager.isUhfRfidEvent(this, event)) {
+            return true
+        }
         mPortScanHelper.dispatchKeyEvent(event)
         return super.dispatchKeyEvent(event)
     }

+ 4 - 0
app/src/main/java/xn/hxp/ui/verify/DoubleVerifyActivity.java

@@ -102,6 +102,10 @@ public class DoubleVerifyActivity extends BaseActivity {
 
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
+        // 消费掉外置RFID读卡器的输入
+        if (xn.hxp.receiver.UhfRfidManager.INSTANCE.isEnabled(this) && xn.hxp.receiver.UhfRfidManager.INSTANCE.isUhfRfidEvent(this, event)) {
+            return true;
+        }
         if (detectType == DetectType.CARD_DETECT) {
             portScanHelper.dispatchKeyEvent(event);
         }

+ 5 - 0
app/src/main/java/xn/hxp/ui/verify/SwipeCodeTwoActivity.kt

@@ -28,6 +28,7 @@ import xn.hxp.comm.Constants
 import xn.hxp.databinding.ActivitySwipeCodeTwoBinding
 import xn.hxp.receiver.OnSerialScanListener
 import xn.hxp.receiver.PortScanHelper
+import xn.hxp.receiver.UhfRfidManager
 import xn.hxp.receiver.UsbReceiver
 import xn.hxp.ui.DoubleDialogBean
 import xn.hxp.utils.AudioPlayer
@@ -503,6 +504,10 @@ class SwipeCodeTwoActivity : BaseActivity() {
 
     //获取刷卡信息
     override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        // 消费掉外置RFID读卡器的输入
+        if (UhfRfidManager.isEnabled(this) && UhfRfidManager.isUhfRfidEvent(this, event)) {
+            return true
+        }
         mPortScanHelper.dispatchKeyEvent(event)
         return super.dispatchKeyEvent(event)
     }

+ 5 - 0
app/src/main/java/xn/hxp/ui/verify/TwoVerificationActivity.kt

@@ -22,6 +22,7 @@ import xn.hxp.comm.Constants
 import xn.hxp.databinding.ActivityTwoVerificationBinding
 import xn.hxp.receiver.OnSerialScanListener
 import xn.hxp.receiver.PortScanHelper
+import xn.hxp.receiver.UhfRfidManager
 import xn.hxp.receiver.UsbReceiver
 import xn.hxp.ui.DoubleDialogBean
 import xn.hxp.utils.*
@@ -1558,6 +1559,10 @@ class TwoVerificationActivity : BaseActivity() {
 
     //获取刷卡信息
     override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        // 消费掉外置RFID读卡器的输入
+        if (UhfRfidManager.isEnabled(this) && UhfRfidManager.isUhfRfidEvent(this, event)) {
+            return true
+        }
         mPortScanHelper.dispatchKeyEvent(event)
         return super.dispatchKeyEvent(event)
     }

+ 11 - 26
app/src/main/java/xn/hxp/ui/warehousing/ChemicalLabelingActivity.kt

@@ -3,6 +3,7 @@ package xn.hxp.ui.warehousing
 import android.os.CountDownTimer
 import android.os.Handler
 import android.os.Looper
+import android.view.KeyEvent
 import android.view.View
 import android.widget.AdapterView
 import androidx.core.content.ContextCompat
@@ -23,6 +24,7 @@ import xn.hxp.R
 import xn.hxp.app.ChemicalApp
 import xn.hxp.comm.Constants
 import xn.hxp.databinding.ActivityChemicalLabelingBinding
+import xn.hxp.receiver.UhfRfidManager
 import xn.hxp.ui.PrintBean
 import xn.hxp.ui.adapter.ChemicalLabelingAdapter
 import xn.hxp.ui.adapter.CustomSpinnerTwoAdapter
@@ -339,6 +341,14 @@ class ChemicalLabelingActivity : BaseActivity() {
         finish()
     }
 
+    // 标签管理页面:消费掉外置RFID读卡器事件,仅在弹窗中处理
+    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        if (UhfRfidManager.isEnabled(this) && UhfRfidManager.isUhfRfidEvent(this, event)) {
+            return true
+        }
+        return super.dispatchKeyEvent(event)
+    }
+
     override fun cdTime(cd: Int) {
         viewBinding.tvReturn.text = "返回${cd}s"
     }
@@ -441,32 +451,6 @@ class ChemicalLabelingActivity : BaseActivity() {
         val disposable = ApiRepository.updateRfid(ids, rfid).subscribe({ data ->
             dismissLoading()
             customDialogView(1, "更换成功")
-            //补打标签
-            val print = PrintBean()
-            print.tag = mData.tagCode  //化学品编码
-            print.wxCode = mData.wxCode!!  //化学品编码
-            print.name = mData.chemicalName!! //化学品名称
-            if (mData.casNum != null) {
-                print.casNo = mData.casNum!!  //cas号
-            } else {
-                print.casNo = ""
-            }
-
-//            if (mDataBean.topicGroup) {
-//                print.person = mDataBean.topicGroupName //归属人
-//            } else {
-//                print.person = mDataBean.applyUserName //归属人
-//            }
-            print.person = mData.belongName
-            //管控 1     非管控  2
-            if (mData.chemicalLevel == 1) {
-                print.level = "管控"
-            } else {
-                print.level = "非管控"
-            }
-            //
-            print.types = "${mData.chemicalCategoryName}"
-            PrintTool.INSTANCE.print(mData.isGr, mData.belongType == 2, print)
             mAdapter.data[mAdIndex].rfidCode = rfid
             mAdapter.notifyItemChanged(mAdIndex)
         }, { throwable ->
@@ -880,6 +864,7 @@ class ChemicalLabelingActivity : BaseActivity() {
         }
         viewBinding.cabinet.text = "${data.cabinetName}-${data.doorName}-${data.layers}层"
         mData = data
+        viewBinding.replaceLabel.visibility = View.VISIBLE
         if (mData.rfidCode == null) {
             viewBinding.replaceLabel.text = "绑定RFID"
         } else {

+ 20 - 21
app/src/main/java/xn/hxp/weidith/AirBottleDialog.kt

@@ -5,15 +5,14 @@ import android.content.Context
 import android.graphics.Color
 import android.graphics.drawable.ColorDrawable
 import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
+import android.text.InputFilter
 import android.view.Gravity
+import android.view.KeyEvent
 import android.view.Window
 import android.view.WindowManager
 import android.widget.Button
 import android.widget.EditText
 import xn.hxp.R
-import java.lang.ref.WeakReference
 
 //化学品标签--气瓶标签提示
 class AirBottleDialog(private val ct: Context, private val lintDate: ILintDate) : Dialog(ct) {
@@ -27,14 +26,20 @@ class AirBottleDialog(private val ct: Context, private val lintDate: ILintDate)
             WindowManager.LayoutParams.MATCH_PARENT,
             WindowManager.LayoutParams.WRAP_CONTENT
         )
-
+        setCanceledOnTouchOutside(false)
+        setCancelable(false)
     }
 
-    private var mHandler: Handler = Handler(Looper.getMainLooper())
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
+        // 禁止EditText中输入换行符
+        val editText = findViewById<EditText>(R.id.cont)
+        editText?.filters = arrayOf(InputFilter { source, _, _, _, _, _ ->
+            if (source.contains("\n") || source.contains("\r")) source.replace(Regex("[\n\r]"), "") else null
+        })
+        editText?.setSingleLine(true)
+
         findViewById<Button>(R.id.butClos).setOnClickListener {
             dismiss()
         }
@@ -48,24 +53,18 @@ class AirBottleDialog(private val ct: Context, private val lintDate: ILintDate)
                 dismiss()
             }
         }
-
-//        Handler().postDelayed({
-//            dismiss()
-//        }, 1000 * 15) // 15秒后关闭对话框
-        mHandler.postDelayed({
-            dismiss()
-        }, 1000 * 15) // 15秒后关闭对话框
-
-    }
-
-    override fun onStop() {
-        super.onStop()
-        // 取消 Handler 的任务,避免潜在的内存泄漏
-        mHandler.removeCallbacksAndMessages(null)
     }
 
     interface ILintDate {
         fun onLintDate(cont: String)
     }
 
-}
+    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        // 只拦截外部设备的ENTER键,其他字符正常传入EditText
+        if (event.device != null && event.device.isExternal
+            && (event.keyCode == KeyEvent.KEYCODE_ENTER || event.keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER)) {
+            return true
+        }
+        return super.dispatchKeyEvent(event)
+    }
+}

+ 21 - 14
app/src/main/java/xn/hxp/weidith/AirBottleNewDialog.kt

@@ -5,19 +5,18 @@ import android.content.Context
 import android.graphics.Color
 import android.graphics.drawable.ColorDrawable
 import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
+import android.text.InputFilter
 import android.view.Gravity
+import android.view.KeyEvent
 import android.view.Window
 import android.view.WindowManager
 import android.widget.Button
 import android.widget.EditText
 import android.widget.TextView
 import xn.hxp.R
-import xn.hxp.utils.AudioPlayer
 
 // 更换RFID 标签
-class AirBottleNewDialog(private val ct: Context,private var rfids:String?,private val lintDate: ILintDate) : Dialog(ct) {
+class AirBottleNewDialog(private val ct: Context, private var rfids: String?, private val lintDate: ILintDate) : Dialog(ct) {
 
     init {
         requestWindowFeature(Window.FEATURE_NO_TITLE)
@@ -28,15 +27,23 @@ class AirBottleNewDialog(private val ct: Context,private var rfids:String?,priva
             WindowManager.LayoutParams.MATCH_PARENT,
             WindowManager.LayoutParams.WRAP_CONTENT
         )
+        setCanceledOnTouchOutside(false)
+        setCancelable(false)
     }
-    private var mHandler: Handler = Handler(Looper.getMainLooper())
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
+        val editText = findViewById<EditText>(R.id.cont)
+        editText?.filters = arrayOf(InputFilter { source, _, _, _, _, _ ->
+            if (source.contains("\n") || source.contains("\r")) source.replace(Regex("[\n\r]"), "") else null
+        })
+        editText?.setSingleLine(true)
+
         findViewById<Button>(R.id.butClos).setOnClickListener {
             dismiss()
         }
-        if (rfids!=null){
+        if (rfids != null) {
             findViewById<TextView>(R.id.rfids).text = "$rfids"
         }
         findViewById<Button>(R.id.butDetermine).setOnClickListener {
@@ -48,18 +55,18 @@ class AirBottleNewDialog(private val ct: Context,private var rfids:String?,priva
                 dismiss()
             }
         }
-        mHandler.postDelayed({
-            dismiss()
-        }, 1000 * 15) // 15秒后关闭对话框
-
     }
 
     interface ILintDate {
         fun onLintDate(cont: String)
     }
 
-    override fun onStop() {
-        super.onStop()
-        mHandler.removeCallbacksAndMessages(null)
+    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        // 只拦截外部设备的ENTER键,其他字符正常传入EditText
+        if (event.device != null && event.device.isExternal
+            && (event.keyCode == KeyEvent.KEYCODE_ENTER || event.keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER)) {
+            return true
+        }
+        return super.dispatchKeyEvent(event)
     }
-}
+}

+ 27 - 2
app/src/main/java/xn/hxp/weidith/LabelDialog.kt

@@ -21,6 +21,8 @@ import xn.hxp.R
 import xn.hxp.comm.Constants
 import xn.hxp.receiver.OnSerialScanListener
 import xn.hxp.receiver.PortScanHelper
+import xn.hxp.receiver.UhfRfidKeyEventHelper
+import xn.hxp.receiver.UhfRfidManager
 import xn.hxp.receiver.UsbReceiver
 import xn.hxp.ui.PrintBean
 import xn.hxp.ui.adapter.CustomSpinnerAdapter
@@ -56,6 +58,26 @@ class LabelDialog(
     private var mUsbReceiver: UsbReceiver? = null  // 刷卡广播注册
     private var mHandleScanEvent = false //当前是否已经获取过 usb返回的参数
 
+    // 外置超高频RFID读卡器解析器
+    private val mUhfRfidHelper = UhfRfidKeyEventHelper { content ->
+        mCounter = 0
+        if (!mHandleScanEvent && content.isNotBlank()) {
+            mHandleScanEvent = true
+            var isDuplicate = false
+            mAdapter.data.forEachIndexed { index, stockDetailsModel ->
+                if (stockDetailsModel.rfidCode != null && stockDetailsModel.rfidCode == content) {
+                    showToast("RFID不能重复")
+                    mHandleScanEvent = false
+                    isDuplicate = true
+                    return@forEachIndexed
+                }
+            }
+            if (!isDuplicate) {
+                upViewRfid(content)
+            }
+        }
+    }
+
     @SuppressLint("NewApi")
     private val formatter: DateTimeFormatter =
         DateTimeFormatter.ofPattern("yyMMddHHmmssSSS")
@@ -258,8 +280,11 @@ class LabelDialog(
 
     override fun dispatchKeyEvent(event: KeyEvent): Boolean {
         if (event.keyCode == KeyEvent.KEYCODE_BACK) {
-            // 在Dialog弹出时处理返回键事件
-            // 处理完事件后返回true表示事件已经被消费,不再传递
+            return true
+        }
+        // 外置超高频RFID读卡器输入
+        if (UhfRfidManager.isEnabled(ac) && UhfRfidManager.isUhfRfidEvent(ac, event)) {
+            mUhfRfidHelper.analysisKeyEvent(event)
             return true
         }
         mPortScanHelper.dispatchKeyEvent(event)

+ 5 - 0
app/src/main/java/xn/hxp/weidith/UsageLabelDialog.java

@@ -42,6 +42,7 @@ import xn.hxp.R;
 import xn.hxp.comm.Constants;
 import xn.hxp.receiver.OnSerialScanListener;
 import xn.hxp.receiver.PortScanHelper;
+import xn.hxp.receiver.UhfRfidManager;
 import xn.hxp.receiver.UsbReceiver;
 import xn.hxp.ui.adapter.UsageLabelDialogAdapter;
 import xn.hxp.utils.BigDecimalUtils;
@@ -191,6 +192,10 @@ public class UsageLabelDialog extends Dialog {
         if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
             return true;
         }
+        // 消费掉外置RFID读卡器的输入
+        if (UhfRfidManager.INSTANCE.isEnabled(ac) && UhfRfidManager.INSTANCE.isUhfRfidEvent(ac, event)) {
+            return true;
+        }
         mPortScanHelper.dispatchKeyEvent(event);
         return super.dispatchKeyEvent(event);
     }

+ 119 - 0
app/src/main/res/layout/activity_setting.xml

@@ -359,6 +359,125 @@
                 </LinearLayout>
 
             </androidx.cardview.widget.CardView>
+
+            <androidx.cardview.widget.CardView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="15dp"
+                android:layout_marginTop="10dp">
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="vertical"
+                    android:paddingHorizontal="10dp"
+                    android:paddingVertical="5dp">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="外置超高频RFID读卡器配置"
+                        android:textSize="16sp"
+                        android:textStyle="bold" />
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="45dp"
+                        android:layout_marginTop="5dp"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:text="启用外置RFID读卡器"
+                            android:textSize="14sp" />
+
+                        <androidx.appcompat.widget.SwitchCompat
+                            android:id="@+id/uhf_rfid_switch"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_marginStart="10dp" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:id="@+id/uhf_rfid_detail_layout"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:visibility="gone">
+
+                        <LinearLayout
+                            android:layout_width="match_parent"
+                            android:layout_height="45dp"
+                            android:gravity="center_vertical"
+                            android:orientation="horizontal">
+
+                            <TextView
+                                android:layout_width="wrap_content"
+                                android:layout_height="wrap_content"
+                                android:text="已学习设备:"
+                                android:textSize="14sp" />
+
+                            <TextView
+                                android:id="@+id/uhf_device_name_TV"
+                                android:layout_width="0dp"
+                                android:layout_height="wrap_content"
+                                android:layout_weight="1"
+                                android:ellipsize="end"
+                                android:maxLines="1"
+                                android:text="未学习"
+                                android:textColor="@color/colorAccent"
+                                android:textSize="14sp" />
+
+                            <androidx.appcompat.widget.AppCompatButton
+                                android:id="@+id/uhf_learn_BT"
+                                android:layout_width="wrap_content"
+                                android:layout_height="wrap_content"
+                                android:text="重新学习" />
+
+                            <androidx.appcompat.widget.AppCompatButton
+                                android:id="@+id/uhf_clear_BT"
+                                android:layout_width="wrap_content"
+                                android:layout_height="wrap_content"
+                                android:layout_marginStart="5dp"
+                                android:text="清除配置" />
+                        </LinearLayout>
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_marginTop="5dp"
+                            android:text="业务白名单范围"
+                            android:textSize="14sp"
+                            android:textStyle="bold" />
+
+                        <CheckBox
+                            android:id="@+id/uhf_wl_storage_CB"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:text="存储模块-称重存储后绑定RFID"
+                            android:textSize="13sp" />
+
+                        <CheckBox
+                            android:id="@+id/uhf_wl_label_CB"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:text="标签管理-绑定/更换RFID"
+                            android:textSize="13sp" />
+
+                        <CheckBox
+                            android:id="@+id/uhf_wl_inquiry_CB"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:text="查询模块"
+                            android:textSize="13sp" />
+                    </LinearLayout>
+
+                </LinearLayout>
+
+            </androidx.cardview.widget.CardView>
+
         </LinearLayout>
 
     </androidx.core.widget.NestedScrollView>

+ 1 - 1
app/src/main/res/layout/item_chemical_labeling.xml

@@ -45,7 +45,7 @@
             android:gravity="center"
             android:textColor="@color/black"
             android:textSize="10sp"
-            android:visibility="gone" />
+            android:visibility="visible" />
 
         <TextView
                 android:ellipsize="end"

+ 31 - 0
chinaSafetyReq.md

@@ -0,0 +1,31 @@
+##化学品终端App(基于Andorid壁挂一体机)外置(usb)超高频rfid读卡器业务调整及标签打印需求
+
+### 说明
+
+当前仓库中代码为化学品智能管控终端的android app 源码。
+
+### 需求
+
+- 彻底阅读分析仓库中app源码;
+- 读取仓库中的.claude记忆;
+- 开放源码中注释掉的rfid相关代码,主要在标签管理->更换rfid业务,包括业务事件和列表页的rfid编号字段,存储->称重存储后的绑定rfid弹窗等;
+- 现在在该app运行的壁挂一体机的usb口上需要外接一个超高频rfid的读卡器(HIB),改设备无sdk,也就是说用户在任何时候都可以刷卡,所以需要能够区分该外置读卡器和其他设备的区别,因为这个读卡器有独立的业务,只在独立业务中被监听,其他业务一律忽略掉,避免引起页面clash导致整个app和重启;
+- 在该app的隐藏的管理员页面新增一个外置超高频rfid读卡器的配置功能,该功能可以人工开启和关闭:
+  - 开启后:可执行学习,点击学习设备后,用户在外置读卡器上刷一次卡,记住这个设备的设备信息,以为后续业务白名单做准备,仅在业务白名单中监听处理该读卡器读取的内容,其他页面视图一律丢弃/消费;
+  - 同时需要在这个功能下允许用户配置白名单范围,目前暂定业务白名单为:
+    - 首页 **存储模块**业务中填写完信息后称重存储业务后弹出的绑定rfid业务;
+    - 首页**标签管理**模块中过的绑定/更换rfid业务;
+    - 首页**查询**模块;
+  - 关闭后,不再监听该rfid设备,整个app所有视图都忽略掉这个读卡器传入的数据,避免引起app crash。
+- 在白名单业务中读取该外置超高频rfid读卡器(HIB)设备时,忽略掉其传入的字符串最后的enter按键,避免读取后的文本自动换行影响业务;
+- 根据源码内容你应该能确认,在**标签管理**->更换rfid标签/绑定rfid标签后系统会触发打印二维码的操作,这个需要调整为在执行更换/绑定rfid标签时仅在用户触发外置读卡器读取标签后,点击确认按钮执行api绑定操作,不再打印二维码标签;
+- 目前的隐藏管理也在用户长按触发进入前需要输入密码,密码为当前隐藏管理页配置的默认密码,后续改动后用隐藏管理页修改后的密码进入;
+- 首页->存储->手动录入化学品->称重存储后弹出页面中请扫描RFID标签时,需支持用户在外置读卡器读取rfid标签,并将rfid标签读取的字符串传入视图,让用户可以看到和删除。
+
+
+
+### 产出要求
+
+- 先阅读源码,产出执行该部分需求的plan以及执行思路
+- 等plan被确认后,再执行coding
+- 最小化范围优化,仅修改需求中提到的需要配合修改的相关文件和代码。

+ 3 - 1
settings.gradle

@@ -14,9 +14,11 @@ pluginManagement {
 dependencyResolutionManagement {
     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
     repositories {
-        maven { url 'https://jitpack.io' }
+        maven { url 'https://maven.aliyun.com/repository/public' }
+        maven { url 'https://maven.aliyun.com/repository/google' }
         google()
         mavenCentral()
+        maven { url 'https://jitpack.io' }
     }
 }