| | |
| | | } |
| | | |
| | | /** |
| | | * 掃描服務抽象介面 (IScanService) |
| | | * 掃描服務抽象介面 (IOCXService) |
| | | * UI 層僅與此介面溝通,不直接操作底層實作 |
| | | */ |
| | | export interface IScanService { |
| | | export interface IOCXService { |
| | | initialize(config: ScanConfig): Promise<void>; |
| | | startScan(): Promise<boolean>; |
| | | uploadFiles(): Promise<boolean>; |
| | |
| | | * 實作 A: ActiveX 適配器 (Legacy Adapter) |
| | | * 用於目前環境:UI (TS) -> Delphi Browser -> ActiveX (OCX) |
| | | */ |
| | | export class ActiveXScanAdapter implements IScanService { |
| | | export class ActiveXScanAdapter implements IOCXService { |
| | | private ocx: any; |
| | | |
| | | constructor() { |
| | |
| | | * 實作 B: Backend Server 適配器 (Future Adapter) |
| | | * 用於未來環境:UI (TS) -> REST API / WebSocket -> Rust/Go Backend |
| | | */ |
| | | export class BackendServerAdapter implements IScanService { |
| | | export class BackendServerAdapter implements IOCXService { |
| | | private apiUrl = "http://localhost:8080/api/scanner"; |
| | | |
| | | async initialize(config: ScanConfig): Promise<void> { |
| | |
| | | * 根據環境自動切換實作 |
| | | */ |
| | | export class ScannerFactory { |
| | | static getService(): IScanService { |
| | | static getService(): IOCXService { |
| | | if ((window as any).OCX_INSTANCE) { |
| | | console.log("偵測到 ActiveX 環境,啟用 ActiveX 適配器"); |
| | | return new ActiveXScanAdapter(); |
| | |
| | | |
| | | ActiveX 的方法通常是同步阻塞的,而後端 API 是非同步的。 |
| | | |
| | | - **建議**:在抽象介面(IScanService)中,所有方法都回傳 Promise。 |
| | | - **建議**:在抽象介面(IOCXService)中,所有方法都回傳 Promise。 |
| | | - **原因**:這樣當你未來切換到後端伺服器(fetch API)時,UI 的調用邏輯(await service.startScan())不需要做任何修改。 |
| | | |
| | | ### **3. 實作「心跳」或「狀態輪詢」** |
| | | |
| | | 原本 GetSetInf1~7 主要是靠宿主程式主動去「問」OCX。 |
| | | |
| | | - **抽象層建議**:在 IScanService 中實作一個 subscribeStatus(callback) 的觀察者模式。 |
| | | - **抽象層建議**:在 IOCXService 中實作一個 subscribeStatus(callback) 的觀察者模式。 |
| | | - **ActiveX 模式下**:在適配器內部啟動一個 setInterval 去輪詢 GetSetInf。 |
| | | - **未來後端模式下**:適配器改用 **WebSocket** 接收後端主動推播的掃描事件。 |
| | | - **UI 層感受**:UI 只需要處理 onStatusUpdate 事件,根本不用管底層是用輪詢還是 WebSocket。 |