+
+
+
+
+
-
diff --git a/pages/index.vue b/pages/index.vue
index 03bb084..41cb992 100644
--- a/pages/index.vue
+++ b/pages/index.vue
@@ -56,16 +56,36 @@
>
+
+
+ Label Drucken
+
+
diff --git a/stores/labelPrinter.ts b/stores/labelPrinter.ts
new file mode 100644
index 0000000..60a96a9
--- /dev/null
+++ b/stores/labelPrinter.ts
@@ -0,0 +1,190 @@
+import { defineStore } from "pinia"
+import {
+ Utils,
+ RequestCommandId,
+ ResponseCommandId,
+ NiimbotBluetoothClient,
+ NiimbotSerialClient
+} from "@mmote/niimbluelib"
+import { useToast } from "#imports"
+
+export const useLabelPrinterStore = defineStore("labelPrinter", {
+ state: () => ({
+ client: null as NiimbotBluetoothClient | NiimbotSerialClient | null,
+ connected: false,
+ connectLoading: false,
+ transportLastUsed: "",
+ printProgress: 0,
+ info: {} as any
+ }),
+
+ actions: {
+
+ /** Logging Helper */
+ logger(...args: any[]) {
+ console.debug("[Printer]", ...args)
+ },
+
+ /** --- Client erzeugen --- */
+ newClient(transport: "ble" | "serial" = "serial") {
+ const toast = useToast()
+
+ // alten Client trennen
+ if (this.client) {
+ try { this.client.disconnect() } catch {}
+ }
+
+ // neuen Client erzeugen
+ this.client =
+ transport === "ble"
+ ? new NiimbotBluetoothClient()
+ : new NiimbotSerialClient()
+
+ /** Events registrieren */
+
+ this.client.on("printerinfofetched", (e) => {
+ console.log("printerInfoFetched")
+ console.log(e.info)
+ this.info = e.info
+ })
+
+ this.client.on("connect", () => {
+ this.connected = true
+ toast.add({ title: "Drucker verbunden" })
+ this.logger("connected")
+ })
+
+ this.client.on("disconnect", () => {
+ this.connected = false
+ toast.add({ title: "Drucker getrennt" })
+ this.logger("disconnected")
+ })
+
+ this.client.on("printprogress", (e) => {
+ if (e.pagePrintProgress) this.printProgress = e.pagePrintProgress
+ this.logger(
+ `Page ${e.page}/${e.pagesTotal}, Page print ${e.pagePrintProgress}%, Page feed ${e.pageFeedProgress}%`
+ )
+ })
+
+ return this.client
+ },
+
+ /** --- Verbinden --- */
+ async connect(transport: "ble" | "serial" = "serial") {
+ const toast = useToast()
+
+ this.connectLoading = true
+
+ this.newClient(transport)
+
+ try {
+ await this.client!.connect()
+ this.transportLastUsed = transport
+ this.connectLoading = false
+ } catch (err) {
+ console.error("[Printer] Connect failed:", err)
+ toast.add({ title: "Verbindung fehlgeschlagen", color: "red" })
+ this.connectLoading = false
+ }
+ },
+
+ /** --- Trennen --- */
+ async disconnect({ forget = false } = {}) {
+ const toast = useToast()
+ this.logger("Disconnect requested…")
+
+ if (!this.client) return
+
+ try {
+ // Timer stoppen
+ try {
+ if (this.client.heartbeatTimer) {
+ clearInterval(this.client.heartbeatTimer)
+ this.client.heartbeatTimer = null
+ }
+ if (this.client.abstraction?.statusPollTimer) {
+ clearInterval(this.client.abstraction.statusPollTimer)
+ this.client.abstraction.statusPollTimer = null
+ }
+ } catch {}
+
+ await this.client.disconnect?.()
+
+ // Serial-Port schließen
+ const port = (this.client as any).port
+ if (port) {
+ try {
+ if (port.readable) port.readable.cancel?.()
+ if (port.writable) await port.writable.abort?.()
+ await port.close?.()
+
+ if (forget && navigator.serial?.forgetPort) {
+ await navigator.serial.forgetPort(port)
+ }
+ } catch (err) {
+ this.logger("Error closing port:", err)
+ }
+ }
+
+ // BLE GATT
+ if (
+ this.client instanceof NiimbotBluetoothClient &&
+ this.client.device?.gatt?.connected
+ ) {
+ try {
+ this.client.device.gatt.disconnect()
+ } catch {}
+ }
+
+ this.connected = false
+ this.client = null
+ toast.add({ title: "Drucker getrennt" })
+ } catch (err) {
+ console.error("[Printer] Disconnect error", err)
+ toast.add({ title: "Fehler beim Trennen", color: "red" })
+ }
+ },
+
+ /** Hilfsfunktion: EncodedImage reparieren */
+ reviveEncodedImage(encoded: any) {
+ if (!encoded?.rowsData) return encoded
+ for (const row of encoded.rowsData) {
+ if (row.rowData && !(row.rowData instanceof Uint8Array)) {
+ row.rowData = new Uint8Array(Object.values(row.rowData))
+ }
+ }
+ return encoded
+ },
+
+ /** --- Drucken --- */
+ async print(encoded: any, options?: { density?: number; pages?: number }) {
+ const toast = useToast()
+
+ if (!this.client) throw new Error("Kein Drucker verbunden")
+
+ const fixed = this.reviveEncodedImage(encoded)
+ const taskName = this.client.getPrintTaskType() ?? "B1"
+
+ const task = this.client.abstraction.newPrintTask(taskName, {
+ totalPages: options?.pages ?? 1,
+ statusPollIntervalMs: 100,
+ statusTimeoutMs: 8000,
+ density: options?.density ?? 5
+ })
+
+ try {
+ this.printProgress = 0
+ await task.printInit()
+ await task.printPage(fixed, options?.pages ?? 1)
+ await task.waitForFinished()
+ toast.add({ title: "Druck abgeschlossen" })
+ } catch (e) {
+ console.error("[Printer] print error", e)
+ toast.add({ title: "Druckfehler", color: "red" })
+ } finally {
+ await task.printEnd()
+ }
+ }
+ }
+})