一個Blazor+WinForm+MAUI+PDA實現的條碼比對系統

2023-11-27 21:00:37

條碼比對系統是由單機版桌面軟體和Android版的PDA掃碼軟體組成,桌面軟體採用Blazor與WinForm進行混合開發,PDA掃碼軟體採用MAUI進行開發,這個專案都是基於.NET技術進行構建,這也是將近期學習Blazor和MAUI這兩門技術應用到實踐當中。

1. 專案背景

  • 朋友公司外倉發貨時把客戶標籤貼錯了,導致客戶掃碼入庫異常,被客戶投訴,為此損失百萬訂單
  • 為防止後續再次出現上述問題,因此開發一套條碼比對系統來預防此類問題出現

2. 專案需求

  • 客戶下單後,將通知外倉備貨,列印客戶條碼標籤貼到紙箱上
  • 外倉現場距離辦公室遠,無網路
  • 根據客戶訂單明細和裝箱設定自動生成總箱數(要考慮尾箱)
  • 每箱出貨碼及數量必須與客戶碼及數量一致
  • 總箱數和每箱條碼比對一致,才能列印出貨單,由司機簽字裝貨

3. 技術方案

根據上述需求,系統分為PC單機版軟體 + PDA掃碼軟體 + 資料傳輸介面三部分組成

  • PC單機版軟體:採用Blazor+WinForm進行混合開發
  • PDA掃碼軟體:採用MAUI開發原生Android應用
  • 資料傳輸介面:採用WebApi進行資料互動(用於PDA掃碼完成後拿到辦公室上載掃碼資料)

4. 功能設計

1)PC單機版軟體

  • 主介面

  • 裝箱設定:設定料號與每箱數量關係,用於比對時自動根據出貨清單的數量計算出貨箱數。

  • 條碼比對:點選【新增】按鈕進入比對頁面新增一條比對記錄,可對記錄進行編輯、刪除和列印交貨單;交貨完成可點選【歸檔】按鈕將記錄歸入歷史記錄中。

    點選【新增】按鈕進入比對操作頁面,在「掃碼清單「下拉選擇由掃描槍上載的掃碼記錄;點選【匯入出貨清單】將出貨清單Excel匯入系統;點選【比對】按鈕將匯入的出貨清單與選擇的掃碼記錄進行比對,比對結果顯示在「單貨比對結果」中,明細結果全部一致且總箱數一致,比對結果才一致;比對結果一致方可列印交貨單放行。

  • 掃碼記錄:用於查詢由掃碼槍PDA軟體上載的掃碼記錄,點選名稱連線檢視該批掃碼明細記錄。

  • 歷史記錄:用於查詢歷史比對記錄,點選【取消歸檔】可取消歸檔該記錄。

2)PDA掃碼軟體

  • 掃碼主頁

開啟條碼比對PDA軟體預設顯示掃碼主頁,在文字方塊輸入備註資訊,再點選【開始掃碼】按鈕進入掃碼比對頁面,對逐個裝箱條碼進行掃碼比對,全部掃碼比對完成後點選【上載資料】按鈕,將該批比對資料上載到電腦端比對管理系統與出貨清單進行比對。

點選【開始掃碼】後,顯示掃碼比對頁面,按下PDA掃描槍按鍵,自動匹配條碼資訊至出貨碼,客戶碼、數量碼,自動比對出貨碼與客戶碼是否一致,一致顯示OK,否則顯示FAIL;點選【確認繼續】按鈕繼續掃描下一個裝箱,如果條碼不允許重複,可勾選「禁止提交重複條碼選項」,全部掃完點選【全部完成】按鈕返回掃碼主頁。

  • 掃碼記錄

點選底部【記錄】Tab選單進入掃碼記錄頁面,該功能主要是用於查詢歷史掃描的記錄資訊。

  • 軟體設定

點選底部【設定】Tab選單進入軟體設定頁面,該功能主要是設定電腦端伺服器主機地址,用於上載掃碼記錄,點選【測試連線】按鈕測試與伺服器鏈路是否通暢。

5. 遇到的問題

最初掃碼時遊標需要定位到一個文字方塊才能掃碼,每次掃碼需要點選文字方塊,使用者體驗很差,最終是通過PDA的廣播功能解決這個問題,關鍵程式碼如下:

//定義掃碼廣播接收者
[BroadcastReceiver(Enabled = true, Exported = true)]
[IntentFilter(new[] { MainActivity.IntentAction })]
class ScanBroadcastReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        var value = intent.GetStringExtra("value");//掃碼接收到的條碼字元
        AppSetting.OnScan?.Invoke(value);          //呼叫掃碼處理委託
    }
}

//在Android入口註冊和解除安裝掃碼廣播接收者
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity
{
    internal const string IntentAction = "android.intent.action.SCANRESULT";
    private ScanBroadcastReceiver scanReceiver;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        scanReceiver = new ScanBroadcastReceiver();//建立接收者
    }

    protected override void OnResume()
    {
        base.OnResume();
        //註冊接收者
        RegisterReceiver(scanReceiver, new Android.Content.IntentFilter(IntentAction));
    }

    protected override void OnPause()
    {
        UnregisterReceiver(scanReceiver);//解除安裝接收者
        base.OnPause();
    }
}

//在掃碼頁面使用廣播接收者
public partial class ScanPage : ContentPage
{
    private ScanItem scan = new();

    public ScanPage()
    {
        InitializeComponent();
        BindingContext = scan;
        AppSetting.OnScan = OnCodeChanged;//進入頁面設定掃碼處理委託
    }

    private void OnCodeChanged(string text)
    {
        //text即是PDA掃碼接收到的條碼字串,在此處理條碼資料
    }
}