接入开发

接入方式

script 标签、npm 包、React Hook、Vue 3 composable 四种接入写法,以及生命周期与状态处理。

最后更新

四种方式用的是同一套公开 SDK,覆盖同样的流程: 连接 → 授权 → 选打印机 → 上传内容 → 打印或预览 → 离开时断开。

获取 SDK

PrintLink 自己分发浏览器版,页面里加一行即可(全局 PrintLink):

<script src="http://127.0.0.1:17888/sdk/printlink.js"></script>

原生 script

<script src="http://127.0.0.1:17888/sdk/printlink.js"></script>
<script type="module">
  const client = new PrintLink.PrintLinkClient({ appName: '我的网页应用' });
  try {
    await client.connect();           // 连接本机 PrintLink
    await client.ensureAuthorized();  // 首次触发配对,等用户在电脑上确认

    const { queues } = await client.listPrinters();
    const queueId = (queues.find((q) => q.isSystemDefault) ?? queues[0]).queueId;

    const job = await client.compose({ queueId }).addPdf(file).printAndWait();
    console.log('终态:', job.status);
  } catch (err) {
    if (err.code === 'PAIRING_PENDING') {
      // 不是故障:等用户在电脑上点同意后,重试 ensureAuthorized()
    } else {
      console.warn(err.code, err.message, 'retryable =', err.retryable);
    }
  } finally {
    client.close();   // 离开页面务必断开
  }
</script>

React

import { useEffect, useRef, useState } from 'react';
import { PrintLinkClient } from '@printlink/sdk';
import type { PrinterQueueInfo } from '@printlink/types';

type State =
  | { status: 'connecting' }
  | { status: 'ready'; queues: PrinterQueueInfo[] }
  | { status: 'pending' }                   // 等用户在电脑上确认授权
  | { status: 'error'; code: string };

export function usePrintLink() {
  const clientRef = useRef<PrintLinkClient | null>(null);
  const [state, setState] = useState<State>({ status: 'connecting' });

  useEffect(() => {
    const client = new PrintLinkClient({ appName: 'My React App' });
    clientRef.current = client;
    let disposed = false;

    void (async () => {
      try {
        await client.connect();
        await client.ensureAuthorized();
        const { queues } = await client.listPrinters();
        if (!disposed) setState({ status: 'ready', queues });
      } catch (err) {
        const code = (err as { code?: string }).code ?? 'INTERNAL';
        if (!disposed) {
          setState(code === 'PAIRING_PENDING' ? { status: 'pending' } : { status: 'error', code });
        }
      }
    })();

    return () => {
      disposed = true;
      client.close();   // 组件卸载一定断连
    };
  }, []);

  return { client: clientRef, state };
}

打印动作放在事件回调里:

async function onPrint(client: PrintLinkClient, queueId: string, doc: PrintDocument) {
  const job = await client.compose({ queueId }).addDocument(doc).printAndWait();
  return job.status;   // 'completed' | 'failed' | 'canceled'
}

Vue 3

import { onMounted, onUnmounted, ref } from 'vue';
import { PrintLinkClient } from '@printlink/sdk';
import type { PrinterQueueInfo } from '@printlink/types';

export function usePrintLink() {
  const status = ref<'connecting' | 'ready' | 'pending' | 'error'>('connecting');
  const queues = ref<PrinterQueueInfo[]>([]);
  let client: PrintLinkClient | null = null;

  onMounted(async () => {
    client = new PrintLinkClient({ appName: 'My Vue App' });
    try {
      await client.connect();
      await client.ensureAuthorized();
      queues.value = (await client.listPrinters()).queues;
      status.value = 'ready';
    } catch (err) {
      status.value = (err as { code?: string }).code === 'PAIRING_PENDING' ? 'pending' : 'error';
    }
  });

  onUnmounted(() => client?.close());

  return { status, queues, client: () => client };
}

客户端参数

const client = new PrintLinkClient({
  appName: '我的业务系统',   // 显示在配对确认与站点列表里
  channel: 'erp',            // 可选:区分同一台机器上的不同业务程序
  endpoint: 'ws://127.0.0.1:17888/ws',  // 可选,默认即此
  requestTimeoutMs: 30_000,  // 可选,单次请求超时
});

channel 是给你自己看的标签,用来在任务列表和报表里区分「哪个程序打的」 (比如 erp / wms / cashier)。只能是小写字母开头、由小写字母/数字/_/- 组成、不超过 64 字符。它不参与权限判断,非法值会直接报错而不是被忽略。

必须处理的四件事

  1. 没安装或没启动:先用 PrintLink.detect() 探测,installed === false 时 引导安装,而不是直接 connect() 然后报错。
  2. 等待授权:PAIRING_PENDING 是正常的中间状态,提示用户去电脑上点同意, 然后重试 ensureAuthorized()。
  3. 离开时断开:close() 释放连接与订阅。单页应用切路由、组件卸载都要调用。
  4. 按 code 处理错误:所有失败都是 code + message + retryable 的结构化错误, 请按 code 分支,不要解析 message 文本。

端口被改过怎么办

用户在控制台改了端口后,已连接的页面会收到 system.serviceMigrated 事件。 收到后应停止发起新请求,并引导用户用新地址重新进入,不要在旧地址上默默重试:

client.onServiceMigrated((event) => {
  showReconnectPrompt(event.endpoint);
});

下一步

本页目录