|
|
@@ -20,6 +20,7 @@ interface ReceiptPrinterClient {
|
|
|
|
printText(params: { text: string; alignment?: Alignment; width?: number; height?: number; bold?: boolean }): Promise<{ success: boolean }>
|
|
|
|
printText(params: { text: string; alignment?: Alignment; width?: number; height?: number; bold?: boolean }): Promise<{ success: boolean }>
|
|
|
|
printQrCode(params: { content: string; size?: number; leftMargin?: number }): Promise<{ success: boolean }>
|
|
|
|
printQrCode(params: { content: string; size?: number; leftMargin?: number }): Promise<{ success: boolean }>
|
|
|
|
feed(params?: { dots?: number }): Promise<{ success: boolean }>
|
|
|
|
feed(params?: { dots?: number }): Promise<{ success: boolean }>
|
|
|
|
|
|
|
|
backFeed(params?: { dots?: number }): Promise<{ success: boolean }>
|
|
|
|
cut(params?: { mode?: 'full' | 'partial' }): Promise<{ success: boolean }>
|
|
|
|
cut(params?: { mode?: 'full' | 'partial' }): Promise<{ success: boolean }>
|
|
|
|
getStatus(): Promise<GetStatusResult>
|
|
|
|
getStatus(): Promise<GetStatusResult>
|
|
|
|
onData(fn: (value: unknown) => void): () => void
|
|
|
|
onData(fn: (value: unknown) => void): () => void
|
|
|
@@ -37,6 +38,7 @@ class MockReceiptPrinter implements ReceiptPrinterClient {
|
|
|
|
async printText() { return this.complete('printText') }
|
|
|
|
async printText() { return this.complete('printText') }
|
|
|
|
async printQrCode() { return this.complete('printQrCode') }
|
|
|
|
async printQrCode() { return this.complete('printQrCode') }
|
|
|
|
async feed() { return this.complete('feed') }
|
|
|
|
async feed() { return this.complete('feed') }
|
|
|
|
|
|
|
|
async backFeed() { return this.complete('backFeed') }
|
|
|
|
async cut() { return this.complete('cut') }
|
|
|
|
async cut() { return this.complete('cut') }
|
|
|
|
async getStatus() { return { code: 0, state: 'ready' as const, ready: true, message: 'Printer is ready.' } }
|
|
|
|
async getStatus() { return { code: 0, state: 'ready' as const, ready: true, message: 'Printer is ready.' } }
|
|
|
|
onData(fn: (v: unknown) => void) { return this.listen('data', fn) }
|
|
|
|
onData(fn: (v: unknown) => void) { return this.listen('data', fn) }
|
|
|
@@ -73,6 +75,7 @@ const qrContent = ref('https://www.cut-os.com')
|
|
|
|
const qrSize = ref(6)
|
|
|
|
const qrSize = ref(6)
|
|
|
|
const qrLeftMargin = ref(0)
|
|
|
|
const qrLeftMargin = ref(0)
|
|
|
|
const feedDots = ref(240)
|
|
|
|
const feedDots = ref(240)
|
|
|
|
|
|
|
|
const backFeedDots = ref(40)
|
|
|
|
const cutMode = ref<'full' | 'partial'>('partial')
|
|
|
|
const cutMode = ref<'full' | 'partial'>('partial')
|
|
|
|
const events = ref<EventItem[]>([])
|
|
|
|
const events = ref<EventItem[]>([])
|
|
|
|
const dataEvents = computed(() => events.value.filter(event => event.kind === 'data'))
|
|
|
|
const dataEvents = computed(() => events.value.filter(event => event.kind === 'data'))
|
|
|
@@ -89,6 +92,7 @@ async function disconnect() { await run('disconnect', async () => { await device
|
|
|
|
async function printText() { await run('printText', async () => { const printed = await device!.printText({ text: text.value, alignment: alignment.value, bold: bold.value, width: width.value, height: height.value }); const fed = await device!.feed({ dots: 240 }); result.value = { printed, fed, feedDots: 240 } }) }
|
|
|
|
async function printText() { await run('printText', async () => { const printed = await device!.printText({ text: text.value, alignment: alignment.value, bold: bold.value, width: width.value, height: height.value }); const fed = await device!.feed({ dots: 240 }); result.value = { printed, fed, feedDots: 240 } }) }
|
|
|
|
async function printQrCode() { await run('printQrCode', async () => { const printed = await device!.printQrCode({ content: qrContent.value, size: qrSize.value, leftMargin: qrLeftMargin.value }); const fed = await device!.feed({ dots: 240 }); result.value = { printed, fed, feedDots: 240 } }) }
|
|
|
|
async function printQrCode() { await run('printQrCode', async () => { const printed = await device!.printQrCode({ content: qrContent.value, size: qrSize.value, leftMargin: qrLeftMargin.value }); const fed = await device!.feed({ dots: 240 }); result.value = { printed, fed, feedDots: 240 } }) }
|
|
|
|
async function feed() { await run('feed', async () => { result.value = await device!.feed({ dots: feedDots.value }) }) }
|
|
|
|
async function feed() { await run('feed', async () => { result.value = await device!.feed({ dots: feedDots.value }) }) }
|
|
|
|
|
|
|
|
async function backFeed() { await run('backFeed', async () => { result.value = await device!.backFeed({ dots: backFeedDots.value }) }) }
|
|
|
|
async function cut() { await run('cut', async () => { result.value = await device!.cut({ mode: cutMode.value }) }) }
|
|
|
|
async function cut() { await run('cut', async () => { result.value = await device!.cut({ mode: cutMode.value }) }) }
|
|
|
|
async function refreshStatus() { await run('getStatus', async () => { printerStatus.value = await device!.getStatus() }) }
|
|
|
|
async function refreshStatus() { await run('getStatus', async () => { printerStatus.value = await device!.getStatus() }) }
|
|
|
|
|
|
|
|
|
|
|
@@ -123,13 +127,13 @@ onUnmounted(() => { unsubscribers.forEach(unsubscribe => unsubscribe()); device?
|
|
|
|
</header>
|
|
|
|
</header>
|
|
|
|
<main>
|
|
|
|
<main>
|
|
|
|
<section v-if="errorText" class="error-banner"><strong>Operation failed</strong><span>{{ errorText }}</span></section>
|
|
|
|
<section v-if="errorText" class="error-banner"><strong>Operation failed</strong><span>{{ errorText }}</span></section>
|
|
|
|
<section class="section-heading"><div><span class="eyebrow">{{ host }}</span><h2>Receipt Printer · MS-MA90</h2></div><div class="dependency-tags"><span class="provider-tag">Capability: <strong>@cutos/device-receipt-printer 4.0.0</strong></span><span class="provider-tag">Provider: <strong>device-receipt-printer-provider-ms-ma90 0.1.0</strong></span></div></section>
|
|
|
|
<section class="section-heading"><div><span class="eyebrow">{{ host }}</span><h2>Receipt Printer · MS-MA90</h2></div><div class="dependency-tags"><span class="provider-tag">Capability: <strong>@cutos/device-receipt-printer 4.1.0</strong></span><span class="provider-tag">Provider: <strong>device-receipt-printer-provider-ms-ma90 0.2.0</strong></span></div></section>
|
|
|
|
<section class="result-grid">
|
|
|
|
<section class="result-grid">
|
|
|
|
<article class="result-card"><div class="result-header method-header"><div><h3>Connection</h3><code>connect() / disconnect()</code></div><span class="state-tag" :class="{ online: connected }">{{ connected ? 'online' : 'offline' }}</span></div><div class="card-body form"><label>Connection<select v-model="connection"><option value="usb">USB</option><option value="serial">Serial</option></select></label><label>{{ connection === 'usb' ? 'USB port (optional)' : 'COM port' }}<input v-model="port" :placeholder="connection === 'usb' ? 'Auto detect' : 'COM1'"></label><label v-if="connection === 'serial'">Baud rate<select v-model="baudRate"><option :value="9600">9600</option><option :value="38400">38400</option><option :value="115200">115200</option></select></label><div class="button-row"><button class="button primary" :disabled="!initialized || !!busy || connected" @click="connect">Connect</button><button class="button secondary" :disabled="!connected || !!busy" @click="disconnect">Disconnect</button></div></div></article>
|
|
|
|
<article class="result-card"><div class="result-header method-header"><div><h3>Connection</h3><code>connect() / disconnect()</code></div><span class="state-tag" :class="{ online: connected }">{{ connected ? 'online' : 'offline' }}</span></div><div class="card-body form"><label>Connection<select v-model="connection"><option value="usb">USB</option><option value="serial">Serial</option></select></label><label>{{ connection === 'usb' ? 'USB port (optional)' : 'COM port' }}<input v-model="port" :placeholder="connection === 'usb' ? 'Auto detect' : 'COM1'"></label><label v-if="connection === 'serial'">Baud rate<select v-model="baudRate"><option :value="9600">9600</option><option :value="38400">38400</option><option :value="115200">115200</option></select></label><div class="button-row"><button class="button primary" :disabled="!initialized || !!busy || connected" @click="connect">Connect</button><button class="button secondary" :disabled="!connected || !!busy" @click="disconnect">Disconnect</button></div></div></article>
|
|
|
|
<article class="result-card"><div class="result-header"><h3>Device information</h3><code>readDeviceInfo()</code></div><pre>{{ format(deviceInfo) }}</pre></article>
|
|
|
|
<article class="result-card"><div class="result-header"><h3>Device information</h3><code>readDeviceInfo()</code></div><pre>{{ format(deviceInfo) }}</pre></article>
|
|
|
|
<article class="result-card"><div class="result-header"><h3>Text</h3><code>printText()</code></div><div class="card-body form"><label>Text<textarea v-model="text" rows="3"></textarea></label><div class="inline-fields"><label>Align<select v-model="alignment"><option>left</option><option>center</option><option>right</option></select></label><label>Width<input v-model.number="width" type="number" min="1" max="8"></label><label>Height<input v-model.number="height" type="number" min="1" max="8"></label></div><label class="check"><input v-model="bold" type="checkbox">Bold</label><button class="button primary" :disabled="!connected || !!busy || !text" @click="printText">Print text</button></div></article>
|
|
|
|
<article class="result-card"><div class="result-header"><h3>Text</h3><code>printText()</code></div><div class="card-body form"><label>Text<textarea v-model="text" rows="3"></textarea></label><div class="inline-fields"><label>Align<select v-model="alignment"><option>left</option><option>center</option><option>right</option></select></label><label>Width<input v-model.number="width" type="number" min="1" max="8"></label><label>Height<input v-model.number="height" type="number" min="1" max="8"></label></div><label class="check"><input v-model="bold" type="checkbox">Bold</label><button class="button primary" :disabled="!connected || !!busy || !text" @click="printText">Print text</button></div></article>
|
|
|
|
<article class="result-card"><div class="result-header"><h3>QR code</h3><code>printQrCode()</code></div><div class="card-body form"><label>Content<input v-model="qrContent"></label><div class="inline-fields"><label>Size<input v-model.number="qrSize" type="number" min="1" max="8"></label><label>Left margin (mm)<input v-model.number="qrLeftMargin" type="number" min="0" max="27"></label></div><button class="button primary" :disabled="!connected || !!busy || !qrContent" @click="printQrCode">Print QR code</button></div></article>
|
|
|
|
<article class="result-card"><div class="result-header"><h3>QR code</h3><code>printQrCode()</code></div><div class="card-body form"><label>Content<input v-model="qrContent"></label><div class="inline-fields"><label>Size<input v-model.number="qrSize" type="number" min="1" max="8"></label><label>Left margin (mm)<input v-model.number="qrLeftMargin" type="number" min="0" max="27"></label></div><button class="button primary" :disabled="!connected || !!busy || !qrContent" @click="printQrCode">Print QR code</button></div></article>
|
|
|
|
<article class="result-card"><div class="result-header"><h3>Paper</h3><code>feed() / cut()</code></div><div class="card-body form"><label>Feed dots<input v-model.number="feedDots" type="number" min="0" max="250"></label><button class="button secondary" :disabled="!connected || !!busy" @click="feed">Feed paper</button><label>Cut mode<select v-model="cutMode"><option value="partial">Partial</option><option value="full">Full</option></select></label><button class="button primary" :disabled="!connected || !!busy" @click="cut">Cut paper</button></div></article>
|
|
|
|
<article class="result-card"><div class="result-header"><h3>Paper</h3><code>feed() / backFeed() / cut()</code></div><div class="card-body form"><label>Feed dots<input v-model.number="feedDots" type="number" min="0" max="250"></label><button class="button secondary" :disabled="!connected || !!busy" @click="feed">Feed paper</button><label>Back feed dots<input v-model.number="backFeedDots" type="number" min="0" max="250"></label><button class="button secondary" :disabled="!connected || !!busy" @click="backFeed">Back feed</button><label>Cut mode<select v-model="cutMode"><option value="partial">Partial</option><option value="full">Full</option></select></label><button class="button primary" :disabled="!connected || !!busy" @click="cut">Cut paper</button></div></article>
|
|
|
|
<article class="result-card"><div class="result-header"><h3>Printer status</h3><code>getStatus()</code></div><div class="card-body"><button class="button secondary" :disabled="!connected || !!busy" @click="refreshStatus">Refresh</button><pre>{{ format(printerStatus) }}</pre></div></article>
|
|
|
|
<article class="result-card"><div class="result-header"><h3>Printer status</h3><code>getStatus()</code></div><div class="card-body"><button class="button secondary" :disabled="!connected || !!busy" @click="refreshStatus">Refresh</button><pre>{{ format(printerStatus) }}</pre></div></article>
|
|
|
|
<article class="result-card event-card"><div class="result-header"><h3>Operations</h3><code>onData()</code></div><div class="event-list"><div v-for="event in dataEvents" :key="event.id" class="event-row"><time>{{ event.time }}</time><pre>{{ format(event.value) }}</pre></div><p v-if="!dataEvents.length" class="empty-state">Waiting for operations…</p></div></article>
|
|
|
|
<article class="result-card event-card"><div class="result-header"><h3>Operations</h3><code>onData()</code></div><div class="event-list"><div v-for="event in dataEvents" :key="event.id" class="event-row"><time>{{ event.time }}</time><pre>{{ format(event.value) }}</pre></div><p v-if="!dataEvents.length" class="empty-state">Waiting for operations…</p></div></article>
|
|
|
|
<article class="result-card event-card"><div class="result-header"><h3>Status / Errors</h3><code>onStatus() / onError()</code></div><div class="event-list"><div v-for="event in [...statusEvents, ...errorEvents]" :key="event.id" class="event-row" :class="{ 'error-event': event.kind === 'error' }"><time>{{ event.time }}</time><pre>{{ format(event.value) }}</pre></div><p v-if="!statusEvents.length && !errorEvents.length" class="empty-state">Waiting for status…</p></div></article>
|
|
|
|
<article class="result-card event-card"><div class="result-header"><h3>Status / Errors</h3><code>onStatus() / onError()</code></div><div class="event-list"><div v-for="event in [...statusEvents, ...errorEvents]" :key="event.id" class="event-row" :class="{ 'error-event': event.kind === 'error' }"><time>{{ event.time }}</time><pre>{{ format(event.value) }}</pre></div><p v-if="!statusEvents.length && !errorEvents.length" class="empty-state">Waiting for status…</p></div></article>
|
|
|
|