材料详情打印条形码
This commit is contained in:
+82
@@ -0,0 +1,82 @@
|
|||||||
|
import { IBleAdapter, JobStartOptions, LPA_AdapterInitOptions, LPA_AuthorizeOptions, LPA_BleDeviceConnectOptions, LPA_BleDiscoveryOptions, LPA_ConnectionStateChangeResult, LPA_Device, LPA_DeviceRequestOptions, LPA_GattCharacteristic, LPA_GattService, LPA_GetCharacteristicsOptions, LPA_GetServicesOptions, LPA_NotifyCharacteristicOptions, LPA_ReadCharacteristicOptions, LPA_ReadResult, LPA_RequestOptions, LPA_Response, LPA_SetMtuOptions, LPA_SetMtuResult, LPA_WriteCharacteristicOptions } from "lpapi-ble";
|
||||||
|
import { IUniInitOptions } from "./UniContext";
|
||||||
|
type CharacteristicValueChangeListener = (result: UniNamespace.OnBLECharacteristicValueChangeSuccess) => void;
|
||||||
|
type BluetoothAdapterStateChangeListener = (result: UniNamespace.OnBluetoothAdapterStateChangeResult) => void;
|
||||||
|
export interface IBleAdapter2 {
|
||||||
|
onBLECharacteristicValueChange?: (callback: CharacteristicValueChangeListener) => void;
|
||||||
|
onBluetoothAdapterStateChange?: (callback: BluetoothAdapterStateChangeListener) => void;
|
||||||
|
}
|
||||||
|
export interface IUniAdapterInitOptions extends IUniInitOptions {
|
||||||
|
bleAdapter?: IBleAdapter2;
|
||||||
|
}
|
||||||
|
export interface Uni_JobStartOptions extends JobStartOptions {
|
||||||
|
canvasId: string;
|
||||||
|
}
|
||||||
|
export interface Uni_Base64SaveResult {
|
||||||
|
target: string;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
size: number;
|
||||||
|
}
|
||||||
|
export interface IConnectionInfo {
|
||||||
|
deviceId: string;
|
||||||
|
connected: boolean;
|
||||||
|
connectStateChange?: (res: LPA_ConnectionStateChangeResult) => void;
|
||||||
|
}
|
||||||
|
export declare class BleAdapter implements IBleAdapter {
|
||||||
|
private static _instance?;
|
||||||
|
private mConnectionMap;
|
||||||
|
private mContext;
|
||||||
|
private mDeviceInfo?;
|
||||||
|
private mSystemInfo?;
|
||||||
|
private mIsAdapterOpened?;
|
||||||
|
private mShowWriteLog?;
|
||||||
|
private mCharacteristicValueChangeMap?;
|
||||||
|
private mCharacteristicMap;
|
||||||
|
/**
|
||||||
|
* 打印机链接状态变化回调函数。
|
||||||
|
*/
|
||||||
|
private mConnectionStateChangeAction?;
|
||||||
|
private mDeviceGetTimer?;
|
||||||
|
/**
|
||||||
|
* 蓝牙适配器状态变化通知回调函数。
|
||||||
|
*/
|
||||||
|
private mAdapterStateChange?;
|
||||||
|
private mAdapterStateChangeAction?;
|
||||||
|
static getInstance(): BleAdapter;
|
||||||
|
constructor(options?: IUniAdapterInitOptions);
|
||||||
|
get isH5(): boolean | undefined;
|
||||||
|
get Context(): IUniAdapterInitOptions;
|
||||||
|
get platform(): string;
|
||||||
|
protected isAndroid(): boolean;
|
||||||
|
protected isHarmonyOS(): boolean;
|
||||||
|
getDeviceInfo(): UniApp.GetDeviceInfoResult | undefined;
|
||||||
|
protected androidAPILevel(): number;
|
||||||
|
protected requestPermissions(): Promise<unknown>;
|
||||||
|
/**
|
||||||
|
* 蓝牙授权认证。
|
||||||
|
*/
|
||||||
|
authorize(options?: LPA_AuthorizeOptions): Promise<LPA_Response<any>>;
|
||||||
|
createAdapterStateChangeAction(): void;
|
||||||
|
openAdapter(options?: LPA_AdapterInitOptions<any>): Promise<LPA_Response<any>>;
|
||||||
|
private resetAllEventListener;
|
||||||
|
closeAdapter(options?: LPA_RequestOptions<any>): Promise<LPA_Response<any>>;
|
||||||
|
resetAdapter(options?: LPA_RequestOptions<any>): Promise<LPA_Response<any>>;
|
||||||
|
startDiscovery(options?: LPA_BleDiscoveryOptions): Promise<LPA_Response<any>>;
|
||||||
|
stopDiscovery(options?: LPA_RequestOptions<any>): Promise<LPA_Response<any>>;
|
||||||
|
getFoundDevices(options?: LPA_RequestOptions<LPA_Device[]>): Promise<LPA_Response<LPA_Device[]>>;
|
||||||
|
createConnectionStateChangeAction(): void;
|
||||||
|
connect(options: LPA_BleDeviceConnectOptions): Promise<LPA_Response<any>>;
|
||||||
|
private resetCharacteristicValueChange;
|
||||||
|
disconnect(options: LPA_DeviceRequestOptions): Promise<LPA_Response<any>>;
|
||||||
|
getConnectedDevices(options?: LPA_RequestOptions<LPA_Device[]>): Promise<LPA_Response<LPA_Device[]>>;
|
||||||
|
setBleMtu(options: LPA_SetMtuOptions): Promise<LPA_SetMtuResult>;
|
||||||
|
getGATTServices(options: LPA_GetServicesOptions): Promise<LPA_GattService[]>;
|
||||||
|
getGATTCharacteristics(options: LPA_GetCharacteristicsOptions): Promise<LPA_GattCharacteristic[]>;
|
||||||
|
onBLECharacteristicValueChange(characterId: string, callback: CharacteristicValueChangeListener): void;
|
||||||
|
offBLECharacteristicValueChange(cid: string): void;
|
||||||
|
read(options: LPA_ReadCharacteristicOptions): Promise<LPA_ReadResult>;
|
||||||
|
notify(options: LPA_NotifyCharacteristicOptions): Promise<LPA_Response<any>>;
|
||||||
|
write(options: LPA_WriteCharacteristicOptions): Promise<LPA_Response<any>>;
|
||||||
|
}
|
||||||
|
export {};
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
import { CreateCanvasOptions, DrawContext, DzImage, ImageLoadOptions, JobStartOptions, JobStartResult, PageEndResult } from "lpapi-ble";
|
||||||
|
export interface IUniInitOptions {
|
||||||
|
isWeiXin?: boolean;
|
||||||
|
isAlipay?: boolean;
|
||||||
|
isDingTalk?: boolean;
|
||||||
|
isH5?: boolean;
|
||||||
|
isAppPlus?: boolean;
|
||||||
|
}
|
||||||
|
export interface IUniCanvasInitOptions extends IUniInitOptions {
|
||||||
|
canvasId?: string;
|
||||||
|
canvas?: HTMLCanvasElement;
|
||||||
|
drawTimeout?: number;
|
||||||
|
componentInstance?: any;
|
||||||
|
}
|
||||||
|
export interface IUniCanvasContext extends CreateCanvasOptions, IUniCanvasInitOptions {
|
||||||
|
canvasId?: string;
|
||||||
|
canvas?: HTMLCanvasElement;
|
||||||
|
drawTimeout?: number;
|
||||||
|
componentInstance?: any;
|
||||||
|
}
|
||||||
|
export interface IUniCanvas {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
getContext(contextId: "2d"): UniNamespace.CanvasContext;
|
||||||
|
}
|
||||||
|
export interface Uni_Base64SaveResult {
|
||||||
|
target: string;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
size: number;
|
||||||
|
}
|
||||||
|
export declare class UniContext extends DrawContext {
|
||||||
|
static createInstance(options: IUniCanvasContext, prevContext?: DrawContext): UniContext | undefined;
|
||||||
|
static isDingTalk(): boolean;
|
||||||
|
private mOptions;
|
||||||
|
private mCanvas?;
|
||||||
|
constructor(context: IUniCanvasContext);
|
||||||
|
init(options: IUniCanvasContext): void;
|
||||||
|
protected createCanvas(): HTMLCanvasElement;
|
||||||
|
/**
|
||||||
|
* 通过 canvas 来创建 Image 对象。
|
||||||
|
*/
|
||||||
|
private createImage;
|
||||||
|
loadImage(options: string | ImageLoadOptions): Promise<HTMLImageElement | DzImage | null>;
|
||||||
|
startJob(options: JobStartOptions): JobStartResult | undefined;
|
||||||
|
protected onCanvasClear(canvas: HTMLCanvasElement, context: CanvasRenderingContext2D): void;
|
||||||
|
commitJob(): Promise<PageEndResult | undefined>;
|
||||||
|
}
|
||||||
Vendored
+33
@@ -0,0 +1,33 @@
|
|||||||
|
import { DrawContext, DrawItemExtOptions, DrawPageItems, LabelAttachOptions, LabelContext, LabelCreateOptions, LPA_InitOptions, LPA_JsonPrintOption, LPA_Response, LPAPI } from "lpapi-ble";
|
||||||
|
import { IUniAdapterInitOptions } from "./adapter/BleAdapter";
|
||||||
|
import { IUniCanvasInitOptions } from "./adapter/UniContext";
|
||||||
|
export interface InitOptions extends IUniCanvasInitOptions, IUniAdapterInitOptions, LPA_InitOptions {
|
||||||
|
}
|
||||||
|
export interface InitUniOptions extends InitOptions {
|
||||||
|
callback: (api: LPAPI, res: LPA_Response<any>) => void;
|
||||||
|
}
|
||||||
|
export declare class LPAPIFactory {
|
||||||
|
private static api?;
|
||||||
|
/**
|
||||||
|
* 获取LPAPI接口实例。
|
||||||
|
*/
|
||||||
|
static getInstance(options?: InitOptions): LPAPI;
|
||||||
|
static initApi(options?: InitUniOptions): Promise<LPAPI>;
|
||||||
|
static resetApi(options?: InitOptions): Promise<LPAPI>;
|
||||||
|
static createInstance(options?: InitOptions): LPAPI;
|
||||||
|
}
|
||||||
|
export interface IUniLabelAttachOptions extends LabelAttachOptions {
|
||||||
|
canvasId?: string;
|
||||||
|
}
|
||||||
|
export declare class UniPreview extends LabelContext {
|
||||||
|
constructor(options: LabelCreateOptions);
|
||||||
|
protected createDrawContext(options: IUniLabelAttachOptions): DrawContext;
|
||||||
|
attachTo(options: IUniLabelAttachOptions): Promise<boolean>;
|
||||||
|
}
|
||||||
|
export type DefineConfigFunc<T> = () => T;
|
||||||
|
export type DefineConfigOptions<T> = T | DefineConfigFunc<T>;
|
||||||
|
export declare function definePrintConfig(options: LPA_JsonPrintOption): LPA_JsonPrintOption;
|
||||||
|
export declare function definePrintConfig(callback: () => LPA_JsonPrintOption): () => LPA_JsonPrintOption;
|
||||||
|
export declare function definePageConfig(page: DrawPageItems): DrawPageItems;
|
||||||
|
export declare function defineDrawConfig(options: DrawItemExtOptions): DrawItemExtOptions;
|
||||||
|
export * from "lpapi-ble";
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,673 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view class="uni-list">
|
||||||
|
<!-- 隐藏画布,用于标签绘制 -->
|
||||||
|
<canvas :id="canvasId" :canvas-id="canvasId" type="2d"
|
||||||
|
:style="{ width: labelWidth + 'px', height: labelHeight + 'px' }"
|
||||||
|
style="position: fixed; left: -999999rpx; top: -999999rpx" />
|
||||||
|
<!-- 打印机列表 -->
|
||||||
|
<view class="uni-list-cell">
|
||||||
|
<view class="uni-list-cell-left">打印机:</view>
|
||||||
|
<view class="uni-list-cell-db">
|
||||||
|
<picker :value="deviceIndex" :range="deviceList" @change="onDeviceChanged" range-key="name">
|
||||||
|
<view class="uni-input">{{ deviceList[deviceIndex].name }}</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 出纸方向 -->
|
||||||
|
<view class="uni-list-cell">
|
||||||
|
<view class="uni-list-cell-left">出纸方向:</view>
|
||||||
|
<view class="uni-list-cell-db">
|
||||||
|
<picker :value="rotationIndex" :range="rotationList" @change="onRotationChanged" range-key="name">
|
||||||
|
<view class="uni-input">{{ rotationList[rotationIndex].name }}</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 标签纸类型 -->
|
||||||
|
<view class="uni-list-cell">
|
||||||
|
<view class="uni-list-cell-left">纸张类型:</view>
|
||||||
|
<view class="uni-list-cell-db">
|
||||||
|
<picker :value="gapIndex" :range="gapList" @change="onGapTypeChanged" range-key="name">
|
||||||
|
<view class="uni-input">{{ gapList[gapIndex].name }}</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 打印浓度 -->
|
||||||
|
<view class="uni-list-cell">
|
||||||
|
<view class="uni-list-cell-left">打印浓度:</view>
|
||||||
|
<view class="uni-list-cell-db">
|
||||||
|
<picker :value="darknessIndex" :range="darknessList" @change="onDarknessChanged" range-key="name">
|
||||||
|
<view class="uni-input">{{ darknessList[darknessIndex].name }}</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 打印速度 -->
|
||||||
|
<view class="uni-list-cell">
|
||||||
|
<view class="uni-list-cell-left">打印速度:</view>
|
||||||
|
<view class="uni-list-cell-db">
|
||||||
|
<picker :value="speedIndex" :range="speedList" @change="onPrintSpeedChanged" range-key="name">
|
||||||
|
<view class="uni-input">{{ speedList[speedIndex].name }}</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 图片处理灰度阈值 -->
|
||||||
|
<view class="uni-list-cell">
|
||||||
|
<view class="uni-list-cell-left">灰度阈值:</view>
|
||||||
|
<view class="uni-list-cell-db">
|
||||||
|
<input class="uni-input" type="number" v-model="threshold" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 打印方式,两种不同的写法 -->
|
||||||
|
<view class="uni-list-cell uni-list-cell-pd">
|
||||||
|
<view class="uni-list-cell-db">JSON配置模式</view>
|
||||||
|
<switch :checked="jsonMode" @change="onPrintModeChanged" style="transform: scale(0.75)" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="button-sp-area">
|
||||||
|
<button class="mini-btn" type="warn" size="mini" plain="true" @click="handleStopDiscovery">停止搜索</button>
|
||||||
|
<button class="mini-btn" type="primary" size="mini" plain="true" @click="handleStartDiscovery">
|
||||||
|
搜索打印机
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
<view class="button-sp-area">
|
||||||
|
<button class="mini-btn" type="warn" size="mini" plain="true" @click="handleClosePrinter">
|
||||||
|
关闭打印机
|
||||||
|
</button>
|
||||||
|
<button class="mini-btn" type="primary" size="mini" plain="true" @click="handleOpenPrinter">
|
||||||
|
打开打印机
|
||||||
|
</button>
|
||||||
|
<button class="mini-btn" type="primary" size="mini" @click="handlePrintLabel">打印</button>
|
||||||
|
</view>
|
||||||
|
<view style="text-align: center; padding: 10px">
|
||||||
|
<view style="margin: 10px; border: solid lightgray 1px">
|
||||||
|
<image v-for="item in previewList" :src="item.value" :key="item.key" class="image" mode="widthFix"
|
||||||
|
style="margin: 10rpx; border: dashed lightgray 1px" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
DrawType,
|
||||||
|
LPAPIFactory,
|
||||||
|
LPAPI
|
||||||
|
} from "../../uni_modules/dothan-lpapi-ble/js_sdk";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
canvasId: "lpapi-ble-uni1",
|
||||||
|
labelWidth: 960,
|
||||||
|
labelHeight: 960,
|
||||||
|
deviceList: [{
|
||||||
|
name: "未检测到打印机",
|
||||||
|
}, ],
|
||||||
|
rotationIndex: 0,
|
||||||
|
rotationList: [{
|
||||||
|
name: "横向打印",
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "右转90度",
|
||||||
|
value: 90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "转转180度",
|
||||||
|
value: 180
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "左转90度",
|
||||||
|
value: 270
|
||||||
|
},
|
||||||
|
],
|
||||||
|
deviceIndex: 0,
|
||||||
|
gapList: [{
|
||||||
|
name: "随打印机设置",
|
||||||
|
value: 255
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "小票纸",
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "不干胶",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "卡纸",
|
||||||
|
value: 3
|
||||||
|
},
|
||||||
|
],
|
||||||
|
gapIndex: 0,
|
||||||
|
darknessList: [{
|
||||||
|
name: "随打印机设置",
|
||||||
|
value: 255
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "6 (正常)",
|
||||||
|
value: 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "7",
|
||||||
|
value: 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "8",
|
||||||
|
value: 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "9",
|
||||||
|
value: 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "10 (较浓)",
|
||||||
|
value: 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "11",
|
||||||
|
value: 11
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "12",
|
||||||
|
value: 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "13",
|
||||||
|
value: 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "14",
|
||||||
|
value: 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "15 (最浓)",
|
||||||
|
value: 15
|
||||||
|
},
|
||||||
|
],
|
||||||
|
darknessIndex: 0,
|
||||||
|
speedList: [{
|
||||||
|
name: "随打印机设置",
|
||||||
|
value: 255
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "最慢",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "较慢",
|
||||||
|
value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "正常",
|
||||||
|
value: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "较快",
|
||||||
|
value: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "最快",
|
||||||
|
value: 5
|
||||||
|
},
|
||||||
|
],
|
||||||
|
speedIndex: 0,
|
||||||
|
isAppPlus: false,
|
||||||
|
isWeiXin: false,
|
||||||
|
isAlipay: false,
|
||||||
|
/**
|
||||||
|
* 图片预览列表
|
||||||
|
* @type {{value: string; key: string;}[]}
|
||||||
|
***/
|
||||||
|
previewList: [],
|
||||||
|
threshold: 128,
|
||||||
|
jsonMode: false,
|
||||||
|
/**
|
||||||
|
* @type {LPAPI}
|
||||||
|
*/
|
||||||
|
lpapi: undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onLoad(options) {
|
||||||
|
console.log("========== onLoad ==========");
|
||||||
|
//option为object类型,会序列化上个页面传递的参数
|
||||||
|
console.log(`---- type = ${options.type}`, options);
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
this.isAppPlus = true;
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
this.isAlipay = true;
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
this.isWeiXin = true;
|
||||||
|
// #endif
|
||||||
|
//
|
||||||
|
this.lpapi = LPAPIFactory.getInstance({
|
||||||
|
// 日志信息显示级别,值为 0 - 4,0表示不显示调试信息,4表示显示所有调试信息
|
||||||
|
showLog: 4,
|
||||||
|
// bleAdapter: bleAdapter,
|
||||||
|
// writeExtendWaits: 3,
|
||||||
|
// dataSendMode: 1,
|
||||||
|
});
|
||||||
|
// 搜索蓝牙设备
|
||||||
|
this.lpapi.startDiscovery({
|
||||||
|
timeout: 0,
|
||||||
|
deviceFound: (devices) => {
|
||||||
|
this.onDeviceFound(devices);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// 微信小程序、支付宝小程序创建绘制上下文的时候,可以不用传递 canvasId,此时会通过离屏Canvas来创建绘制上下文环境。
|
||||||
|
if (this.isWeiXin) {
|
||||||
|
this.context = this.lpapi.createDrawContext();
|
||||||
|
} else {
|
||||||
|
// 备注:支付宝小程序新版本有问题,需要去掉 canvas 中的 type="2d"才可以。
|
||||||
|
this.context = this.lpapi.createDrawContext({
|
||||||
|
// 用于进行标签绘制的画布ID
|
||||||
|
canvasId: this.canvasId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if (this.context) {
|
||||||
|
this.lpapi.setDrawContext(this.context);
|
||||||
|
// 预览标签内容
|
||||||
|
this.handlePreviewLabel();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCanvasReady() {
|
||||||
|
console.log("========== onCanvasReady ==========");
|
||||||
|
console.log(`---- isAlipay: ${this.isAlipay}`);
|
||||||
|
if (this.isAlipay) {
|
||||||
|
// 支付宝小程序中在屏 Canvas的使用的时候,1:配置 type="2d",2:设置 onReady 事件,在onReady中通过 selectorQuery来获取canvas实例。
|
||||||
|
// this.queryCanvas((canvas) => {
|
||||||
|
// this.context = this.lpapi.createDrawContext({
|
||||||
|
// canvas: canvas,
|
||||||
|
// });
|
||||||
|
// if (this.context) {
|
||||||
|
// this.lpapi.setDrawContext(this.context);
|
||||||
|
// }
|
||||||
|
// this.handlePreviewLabel();
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
console.log("========== onShow ==========");
|
||||||
|
// 建议在 onShow的时候,修改下标签的绘制上下文,避免因在context没有更新导致的 canvas不显示的问题。
|
||||||
|
if (this.context) {
|
||||||
|
this.lpapi.setDrawContext(this.context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onUnload() {
|
||||||
|
console.log("========== onUnload ==========");
|
||||||
|
this.handleClosePrinter();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
queryCanvas(callback) {
|
||||||
|
// 微信小程序、支付宝小程序等 最新版本初始化方式
|
||||||
|
// 注意:canvas 中必须配置 type="2d" 才能生效。
|
||||||
|
try {
|
||||||
|
uni.createSelectorQuery()
|
||||||
|
.select(`#${this.canvasId}`)
|
||||||
|
.node()
|
||||||
|
.exec((res) => {
|
||||||
|
console.log(`------- exec.result: --------`);
|
||||||
|
console.log(res);
|
||||||
|
const canvas = res[0]?.node;
|
||||||
|
// this.printCanvas = canvas;
|
||||||
|
callback(canvas);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(`---- 不支持通过该方式获取 Canvas 对象!`);
|
||||||
|
console.warn(e);
|
||||||
|
callback(undefined);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDeviceChanged(e) {
|
||||||
|
console.log(`---------- onDeviceChanged:${e.detail.value} ----------`);
|
||||||
|
this.deviceIndex = e ? e.detail.value : 0;
|
||||||
|
},
|
||||||
|
onRotationChanged(e) {
|
||||||
|
console.log(`---------- onRotationChanged: ${e.detail.value} ----------`);
|
||||||
|
this.rotationIndex = e ? e.detail.value : 0;
|
||||||
|
},
|
||||||
|
onGapTypeChanged(e) {
|
||||||
|
console.log(`---------- onGapTypeChanged:${e.detail.value} ----------`);
|
||||||
|
this.gapIndex = e ? e.detail.value : 0;
|
||||||
|
},
|
||||||
|
onDarknessChanged(e) {
|
||||||
|
console.log(`---------- onDarknessChanged:${e.detail.value} ----------`);
|
||||||
|
this.darknessIndex = e ? e.detail.value : 0;
|
||||||
|
},
|
||||||
|
onPrintSpeedChanged(e) {
|
||||||
|
console.log(`---------- onPrintSpeedChanged:${e.detail.value} ----------`);
|
||||||
|
this.speedIndex = e ? e.detail.value : 0;
|
||||||
|
},
|
||||||
|
onPrintModeChanged(e) {
|
||||||
|
console.log(`---------- onPrintModeChanged: ${e.detail.value} ----------`);
|
||||||
|
this.jsonMode = e.detail.value;
|
||||||
|
this.handlePreviewLabel();
|
||||||
|
},
|
||||||
|
handleStartDiscovery() {
|
||||||
|
uni.showLoading({
|
||||||
|
title: "正在搜索打印机...",
|
||||||
|
});
|
||||||
|
this.lpapi.startDiscovery({
|
||||||
|
timeout: 5000,
|
||||||
|
deviceFound: (devices) => {
|
||||||
|
this.onDeviceFound(devices);
|
||||||
|
},
|
||||||
|
adapterStateChange: (result) => {
|
||||||
|
if (!result.discovering) {
|
||||||
|
uni.hideLoading();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleStopDiscovery() {
|
||||||
|
this.lpapi.stopDiscovery();
|
||||||
|
},
|
||||||
|
handleOpenPrinter() {
|
||||||
|
const currDevice = this.getDevice();
|
||||||
|
const isAlipay = this.isAlipay;
|
||||||
|
if (currDevice && currDevice.deviceId) {
|
||||||
|
//
|
||||||
|
uni.showLoading({
|
||||||
|
title: "正在链接打印机...",
|
||||||
|
});
|
||||||
|
return this.lpapi
|
||||||
|
.openPrinter({
|
||||||
|
name: currDevice.name,
|
||||||
|
deviceId: currDevice.deviceId,
|
||||||
|
// 如果打印机链接失败的话,可以尝试连续进行多次链接。
|
||||||
|
tryTimes: isAlipay ? 1 : 5,
|
||||||
|
success: (resp) => {
|
||||||
|
console.log(`---- 【打印机链接成功】`);
|
||||||
|
console.log(resp.resultInfo);
|
||||||
|
uni.hideLoading();
|
||||||
|
//
|
||||||
|
uni.showToast({
|
||||||
|
title: "打印机链接成功!",
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fail: (resp) => {
|
||||||
|
console.warn(`---- 【打印机链接失败】:`);
|
||||||
|
console.warn(JSON.stringify(resp));
|
||||||
|
//
|
||||||
|
uni.hideLoading();
|
||||||
|
//
|
||||||
|
uni.showToast({
|
||||||
|
title: "打印机链接失败!",
|
||||||
|
icon: "fail",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
return res.statusCode === 0;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.warn("---- 未检测到打印机!");
|
||||||
|
uni.showToast({
|
||||||
|
title: "未检测到打印机",
|
||||||
|
icon: "fail",
|
||||||
|
});
|
||||||
|
if (typeof callback === "function") {
|
||||||
|
callback(false);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleClosePrinter() {
|
||||||
|
console.log(`---- 关闭打印机!`);
|
||||||
|
this.lpapi.closePrinter();
|
||||||
|
},
|
||||||
|
onDeviceFound(devices) {
|
||||||
|
console.log(`---- 检测到打印机:`);
|
||||||
|
console.log(devices);
|
||||||
|
if (devices && devices.length > 0) {
|
||||||
|
this.deviceList.splice(0);
|
||||||
|
for (let item of devices) {
|
||||||
|
this.deviceList.push(item);
|
||||||
|
//
|
||||||
|
// const advertisData = item.advertisData ? new Uint8Array(item.advertisData) : undefined;
|
||||||
|
// const advDataStr = advertisData ? LPAUtils.arrayBufferToHex16(advertisData) : "-";
|
||||||
|
// console.log(`---- advertisData [${item.name}] : [${advDataStr}]`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getDevice() {
|
||||||
|
return this.deviceList[this.deviceIndex];
|
||||||
|
},
|
||||||
|
getOrientation() {
|
||||||
|
return this.rotationList[this.rotationIndex].value;
|
||||||
|
},
|
||||||
|
getGapType() {
|
||||||
|
return this.gapList[this.gapIndex].value;
|
||||||
|
},
|
||||||
|
getPrintDarkness() {
|
||||||
|
return this.darknessList[this.darknessIndex].value;
|
||||||
|
},
|
||||||
|
getPrintSpeed() {
|
||||||
|
return this.speedList[this.speedIndex].value;
|
||||||
|
},
|
||||||
|
getThreshold() {
|
||||||
|
return Number(this.threshold);
|
||||||
|
},
|
||||||
|
updateCanvas(jobInfo) {
|
||||||
|
// 如果通过 createSelectorQuery 获取到了 Canvas 实例,则不需要延迟处理;
|
||||||
|
// 在微信小程序、支付宝小程序中是支持该功能的;
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// 更新canvas大小;
|
||||||
|
if (jobInfo.canvas) {
|
||||||
|
this.labelWidth = jobInfo.canvas.width;
|
||||||
|
this.labelHeight = jobInfo.canvas.height;
|
||||||
|
// 等 Canvas 大小更新后在执行后续绘制操作;
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve(true);
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handlePreviewLabel() {
|
||||||
|
// 1. 先清空当前的图片列表
|
||||||
|
this.previewList.splice(0);
|
||||||
|
// 2. 创建并绘制标签内容
|
||||||
|
this.printLabel(true).then((res) => {
|
||||||
|
console.warn(`----- previewLabel.result: ${res.statusCode}`, res.errMsg);
|
||||||
|
// 3. 标签绘制完毕后,预览标签内容
|
||||||
|
if (res.statusCode === 0) {
|
||||||
|
console.warn(`---- 所有页面全部生成完毕!`);
|
||||||
|
res.previewData.forEach((value) => {
|
||||||
|
this.previewList.push({
|
||||||
|
value: value,
|
||||||
|
// 为了保证 v-for循环的唯一性,随便生成一个随机ID
|
||||||
|
key: `${new Date().getTime()}-${Math.random() * 1000}`,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.warn(`---- 标签预览失败!`, res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async handlePrintLabel() {
|
||||||
|
// 1. 连接打印机
|
||||||
|
const openResult = await this.handleOpenPrinter();
|
||||||
|
if (!openResult) {
|
||||||
|
uni.showToast({
|
||||||
|
title: "打印机连接失败!",
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 2. 创建标签后直接打印
|
||||||
|
this.printLabel(false).then((res) => {
|
||||||
|
if (res.statusCode === 0) {
|
||||||
|
uni.showToast({
|
||||||
|
title: "打印成功!",
|
||||||
|
icon: "success",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.warn(`---- 打印失败!`);
|
||||||
|
if (res.errMsg) {
|
||||||
|
uni.showToast({
|
||||||
|
title: res.errMsg,
|
||||||
|
icon: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
printLabel(isPreview) {
|
||||||
|
if (this.jsonMode) {
|
||||||
|
return this.printLabelWithJsonMode(isPreview);
|
||||||
|
} else {
|
||||||
|
return this.printLabelWithDrawMode(isPreview);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 通过 draw 的方式绘制标签内容。
|
||||||
|
*/
|
||||||
|
async printLabelWithDrawMode(isPreview) {
|
||||||
|
console.log(`---- qrcodePrintWithDrawMode:`);
|
||||||
|
const api = this.lpapi;
|
||||||
|
//
|
||||||
|
const labelWidth = 40;
|
||||||
|
const labelHeight = 30;
|
||||||
|
const margin = 2;
|
||||||
|
//
|
||||||
|
const jobInfo = api.startJob({
|
||||||
|
context: this.context,
|
||||||
|
width: labelWidth,
|
||||||
|
height: labelHeight,
|
||||||
|
orientation: this.getOrientation(),
|
||||||
|
isPreview: isPreview,
|
||||||
|
});
|
||||||
|
//
|
||||||
|
await this.updateCanvas(jobInfo);
|
||||||
|
// 绘制外边框
|
||||||
|
api.drawRectangle({
|
||||||
|
width: labelWidth,
|
||||||
|
height: labelHeight,
|
||||||
|
});
|
||||||
|
api.draw1DBarcode({
|
||||||
|
text: "12345678",
|
||||||
|
x: margin,
|
||||||
|
y: margin,
|
||||||
|
width: labelWidth - margin * 2,
|
||||||
|
height: labelHeight - margin * 2,
|
||||||
|
textHeight: 5,
|
||||||
|
barcodeType: 22,
|
||||||
|
});
|
||||||
|
//
|
||||||
|
return api.commitJob({
|
||||||
|
gapType: this.getGapType(),
|
||||||
|
printDarkness: this.getPrintDarkness(),
|
||||||
|
printSpeed: this.getPrintSpeed(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 通过 JSON 方式绘制标签内容。
|
||||||
|
*/
|
||||||
|
printLabelWithJsonMode(isPreview) {
|
||||||
|
console.log(`---- qrcodePrintWithJsonMode:`);
|
||||||
|
const device = this.getDevice();
|
||||||
|
const labelWidth = 40;
|
||||||
|
const labelHeight = 30;
|
||||||
|
const margin = 2;
|
||||||
|
//
|
||||||
|
return this.lpapi.print({
|
||||||
|
// 配置标签信息
|
||||||
|
jobInfo: {
|
||||||
|
jobWidth: labelWidth,
|
||||||
|
jobHeight: labelHeight,
|
||||||
|
orientation: this.getOrientation(),
|
||||||
|
isPreview: isPreview, // 当前任务是否是预览任务
|
||||||
|
},
|
||||||
|
// 配置打印机信息
|
||||||
|
printerInfo: {
|
||||||
|
name: device?.name,
|
||||||
|
deviceId: device?.deviceId,
|
||||||
|
},
|
||||||
|
jobPage: [{
|
||||||
|
type: DrawType.rect,
|
||||||
|
width: labelWidth,
|
||||||
|
height: labelHeight,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: DrawType.barcode,
|
||||||
|
text: "12345678",
|
||||||
|
x: margin,
|
||||||
|
y: margin,
|
||||||
|
width: labelWidth - margin * 2,
|
||||||
|
height: labelHeight - margin * 2,
|
||||||
|
textHeight: 5,
|
||||||
|
barcodeType: 22,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onJobCreated: (jobInfo) => {
|
||||||
|
// 通过双向绑定方式更新画布大小
|
||||||
|
return this.updateCanvas(jobInfo);
|
||||||
|
},
|
||||||
|
onPageComplete(res) {
|
||||||
|
// 标签页面渲染完毕时的回调函数,预览模式下可展示标签打印效果。
|
||||||
|
},
|
||||||
|
onPagePrintComplete(res) {
|
||||||
|
// 标签页面打印完毕时的回调函数。
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
button {
|
||||||
|
margin-top: 15upx;
|
||||||
|
margin-bottom: 15upx;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 200rpx;
|
||||||
|
width: 200rpx;
|
||||||
|
margin: 200rpx auto 50rpx auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-area {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 36rpx;
|
||||||
|
color: #8f8f94;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-sp-area {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 90%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-btn {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,3 +1,25 @@
|
|||||||
|
// atob polyfill for WeChat mini programs (required by bwip-js for font/base64 decoding)
|
||||||
|
(function() {
|
||||||
|
var _chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
|
||||||
|
var _atob = function(input) {
|
||||||
|
var str = String(input).replace(/[=]+$/, '')
|
||||||
|
var output = ''
|
||||||
|
var bc = 0, bs, buffer = 0, i = 0
|
||||||
|
for (; str.charAt(i | 0); i++) {
|
||||||
|
bs = _chars.indexOf(str.charAt(i))
|
||||||
|
buffer = (buffer << 6) | bs
|
||||||
|
bc += 6
|
||||||
|
if (bc >= 8) {
|
||||||
|
bc -= 8
|
||||||
|
output += String.fromCharCode((buffer >>> bc) & 255)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
try { globalThis.atob = globalThis.atob || _atob } catch(e) {}
|
||||||
|
try { global.atob = global.atob || _atob } catch(e) {}
|
||||||
|
})()
|
||||||
|
|
||||||
import App from './App'
|
import App from './App'
|
||||||
|
|
||||||
// #ifndef VUE3
|
// #ifndef VUE3
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "SHJ_APP - 副本",
|
"name": "SHJ_APP",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
|||||||
@@ -11,8 +11,5 @@
|
|||||||
"uview-pro": "^0.6.2",
|
"uview-pro": "^0.6.2",
|
||||||
"vite": "^8.0.16",
|
"vite": "^8.0.16",
|
||||||
"vue": "^3.5.38"
|
"vue": "^3.5.38"
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"sharp": "^0.35.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"easycom": {
|
"easycom": {
|
||||||
"autoscan": true,
|
"autoscan": true,
|
||||||
"custom": {
|
"custom": {
|
||||||
|
"^nbd-print-prop$": "@/scanpages/components/nbd-print-prop.vue",
|
||||||
"^u-(.*)": "uview-pro/components/u-$1/u-$1.vue",
|
"^u-(.*)": "uview-pro/components/u-$1/u-$1.vue",
|
||||||
"^nbd-(.*)": "@/components/nbd-$1.vue"
|
"^nbd-(.*)": "@/components/nbd-$1.vue"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
-323
@@ -41,10 +41,6 @@ importers:
|
|||||||
vue:
|
vue:
|
||||||
specifier: ^3.5.38
|
specifier: ^3.5.38
|
||||||
version: 3.5.38
|
version: 3.5.38
|
||||||
devDependencies:
|
|
||||||
sharp:
|
|
||||||
specifier: ^0.35.1
|
|
||||||
version: 0.35.1
|
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -102,174 +98,9 @@ packages:
|
|||||||
'@emnapi/runtime@1.10.0':
|
'@emnapi/runtime@1.10.0':
|
||||||
resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
|
resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
|
||||||
|
|
||||||
'@emnapi/runtime@1.11.1':
|
|
||||||
resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==}
|
|
||||||
|
|
||||||
'@emnapi/wasi-threads@1.2.1':
|
'@emnapi/wasi-threads@1.2.1':
|
||||||
resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
|
resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
|
||||||
|
|
||||||
'@img/colour@1.1.0':
|
|
||||||
resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
|
|
||||||
'@img/sharp-darwin-arm64@0.35.1':
|
|
||||||
resolution: {integrity: sha512-T15JRWOubQ3f5+GxnWeIvo47u5qV0M9HBgJhT+f2gE1e9e6OhR6K73Re52Hm80qWcu1DNb3GweKmpr/MnuP2Ow==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [darwin]
|
|
||||||
|
|
||||||
'@img/sharp-darwin-x64@0.35.1':
|
|
||||||
resolution: {integrity: sha512-t1CPD0cr7XCHjwUj6tQ5MC0pCi866I+gUW6zbUX4aFPnKd1DFBtk0M+gWcjX8VeEzgfCNiSiNTVFZ6b7kvdbnQ==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [darwin]
|
|
||||||
|
|
||||||
'@img/sharp-freebsd-wasm32@0.35.1':
|
|
||||||
resolution: {integrity: sha512-MBSQXqNPThW9EcZ905H6N4sEdX5EwZEYzGx5EBq9ncDCGJALMiY1xPFJxNdzuB1iBjLOpIfxajM6YxdvwmQSLA==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
os: [freebsd]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-darwin-arm64@1.3.0':
|
|
||||||
resolution: {integrity: sha512-EKbmBKtyTH+GPFDRw2TgK2oV6hyxxlJVIar4hoTYSNmIwipgMFdxPQqR392GmfdsPGWga0mCFN1cCKjRb9cljw==}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [darwin]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-darwin-x64@1.3.0':
|
|
||||||
resolution: {integrity: sha512-Pl2OmOvrJ42adUllESxBsG54PfXLo1OYg9i3c5/5Ln/qJ0gZuTM9YMhQJPIbXqwidLRc/c2zuHt4RsrymmNv7A==}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [darwin]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-arm64@1.3.0':
|
|
||||||
resolution: {integrity: sha512-C0SqjoFKnszqa44EQ7xoaT48nnO0lOyXEULfXMWi8krrjOPGYkeK30Okzla6ATbBYsyZ0ySinK0FVkpv3DwzfQ==}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [linux]
|
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-arm@1.3.0':
|
|
||||||
resolution: {integrity: sha512-A8UpHoUDW4DwnXoV6+q3C1s7QLRAHtPDEjWuNZjwHMyoCNZnm0GeNN8ls9f/bsEYTRQRW96C/n34XJQHJ2fT7A==}
|
|
||||||
cpu: [arm]
|
|
||||||
os: [linux]
|
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-ppc64@1.3.0':
|
|
||||||
resolution: {integrity: sha512-WOpkVxAjFd369iaIzEgNRreFD+gWdUMIGD5zplhNKNeqS6mm5dac3q2AFyCBmzYoAdouzZvRBgxy4z8QHZb4/A==}
|
|
||||||
cpu: [ppc64]
|
|
||||||
os: [linux]
|
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-riscv64@1.3.0':
|
|
||||||
resolution: {integrity: sha512-DRWw0mOHusrCCuw2rqP87oLg6PGlkomVDFqw2hIwsSfwWpu4k3XLcBPaKKl6ct/GtL/cwNkgwjV/tc0Mqht3VA==}
|
|
||||||
cpu: [riscv64]
|
|
||||||
os: [linux]
|
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-s390x@1.3.0':
|
|
||||||
resolution: {integrity: sha512-9APy+nFWhHS+kzLgWZfLcyrUd7YqnAQVa4BPOo4xkoHpdoktOAPG4cEr9+Jpl0TtqfVmcMJimNL5qNTyyOHZNA==}
|
|
||||||
cpu: [s390x]
|
|
||||||
os: [linux]
|
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-x64@1.3.0':
|
|
||||||
resolution: {integrity: sha512-y9RNUYDe2A1UAdhLyfeOodGRszQdaEoe4nfOpp/sNVPl2CWIcUyFaDoCh4vPLPxu19803j2naLqZup2WxDXCLA==}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [linux]
|
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linuxmusl-arm64@1.3.0':
|
|
||||||
resolution: {integrity: sha512-cC1wkC0Mlucd0KSiGrLkJnB/ZqPvZCntc/Lk7ZnYO5ZSbF2euNek4Xvxafojq+wN1q/W0eprdpUIjUr/EV2PBg==}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [linux]
|
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linuxmusl-x64@1.3.0':
|
|
||||||
resolution: {integrity: sha512-LiYMhUZicB1QG//+RvmYZpXJO8fYRENfp+MZUCnG9aw+AKvGAy9gPaCnuwsPcBFs8EV66M0NNxj9VHcNklE8zw==}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [linux]
|
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@img/sharp-linux-arm64@0.35.1':
|
|
||||||
resolution: {integrity: sha512-ErCRyGU7LeoaFBZ0xW8hhLlXzhAg80sc4vxePB86qvtEvW1jEhhmbiNBP4oEzZfPMnu6HwHXfzD2W2kBU+RnCw==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [linux]
|
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linux-arm@0.35.1':
|
|
||||||
resolution: {integrity: sha512-jygmR02PpCYypt7xB7nst1vqjZp/BpRA/Kf9nK7qRponJ/KrLPaZWEG4G15z1d2FZ6XqI+T0350ha3RSnKx24A==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [arm]
|
|
||||||
os: [linux]
|
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linux-ppc64@0.35.1':
|
|
||||||
resolution: {integrity: sha512-LUWZ2+r2UoLCd8j0RLCwQ4gL6w47+Y7igxtVnPIDXOOEjV86LpBkAHq5VpJeg+GHbw0KN/JWlPJOdZjyZnFqFQ==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [ppc64]
|
|
||||||
os: [linux]
|
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linux-riscv64@0.35.1':
|
|
||||||
resolution: {integrity: sha512-i7x6J3mwF4JgT0sM4V4WlAWdJ0bucPtA9rzO1bTji1n5qgBq/W5nn87RvOQPleuuxahNoLdTngByD8/vDDLArw==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [riscv64]
|
|
||||||
os: [linux]
|
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linux-s390x@0.35.1':
|
|
||||||
resolution: {integrity: sha512-0zSaTUjTF0kIWTSYxD4EG/nvCU4jez53+3RdURtoY3HvbXtIQ98W90JnrGz/oLRFuEnfIy9+7xeq883euc0ZWw==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [s390x]
|
|
||||||
os: [linux]
|
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linux-x64@0.35.1':
|
|
||||||
resolution: {integrity: sha512-NbJD4mWdeyrNQKluO/tR/wBDOelcowSVGNBWxI0e3ZtlXc6F/UOVKDj1MLD4zl3oHTuvKW3s+MA9N54YTldAYw==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [linux]
|
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linuxmusl-arm64@0.35.1':
|
|
||||||
resolution: {integrity: sha512-VoW2sQCWI+0YIKQEmWJ8vzaQjTg9wIyfkFpvEfAS2h43X6iHu7GTk1hhOgB4IpSzCHe8UwQZIcx7b81VTaOrJA==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [linux]
|
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@img/sharp-linuxmusl-x64@0.35.1':
|
|
||||||
resolution: {integrity: sha512-LjBoSd/c5JU0/K5MwzDMlgsSRP2bPn98JQGFFQAOLQ0bU/1z4ekxUdSKY9BmlwSh/cA+OrvpgsWqfZyYfVHBRw==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [linux]
|
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@img/sharp-wasm32@0.35.1':
|
|
||||||
resolution: {integrity: sha512-PCQUoQdZyE8tp3HpbevuihfUmgSP4qWI0FGEPWoeXqaS+cUrFfemabHQiebUmUmlUhCuNnQMxGrQ+CPqK4hnxg==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
|
|
||||||
'@img/sharp-webcontainers-wasm32@0.35.1':
|
|
||||||
resolution: {integrity: sha512-xU2ml2bU2OPxYVvW2A6ae4M1g5QKyhKG06P4FAt+YEaFQQO0919Qx+XxIZEUuWTMoDViLpMws2/dQwoe/VcA6A==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [wasm32]
|
|
||||||
|
|
||||||
'@img/sharp-win32-arm64@0.35.1':
|
|
||||||
resolution: {integrity: sha512-IkmHwuFhYpd3bTsN5SAahjwhiAcyXPooBt8vEUgxY3T0IP70sSJ0nU1xiPzZY8AH/OB1XpV3j8aZSVSOSfTbdA==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [win32]
|
|
||||||
|
|
||||||
'@img/sharp-win32-ia32@0.35.1':
|
|
||||||
resolution: {integrity: sha512-wQahqCi9MD8Yxzg4gVM4fNrZxh+r6vD55PyIg+WJPaM5ZRUyF35iQpwJCuma3r6viU9/8Pxlc+XHV+woVa6nCQ==}
|
|
||||||
engines: {node: ^20.9.0}
|
|
||||||
cpu: [ia32]
|
|
||||||
os: [win32]
|
|
||||||
|
|
||||||
'@img/sharp-win32-x64@0.35.1':
|
|
||||||
resolution: {integrity: sha512-WzBtkYtZHATLPe8XRharxZXxQ9cdLrQWHiwxt+BJ5rBsisQrKeeV86ErxPSVhcG6xCEuNhs0SqLpWr7XDa2k6w==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [win32]
|
|
||||||
|
|
||||||
'@jridgewell/sourcemap-codec@1.5.5':
|
'@jridgewell/sourcemap-codec@1.5.5':
|
||||||
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||||
|
|
||||||
@@ -1130,11 +961,6 @@ packages:
|
|||||||
safer-buffer@2.1.2:
|
safer-buffer@2.1.2:
|
||||||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||||
|
|
||||||
semver@7.8.4:
|
|
||||||
resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
send@0.19.2:
|
send@0.19.2:
|
||||||
resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==}
|
resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
@@ -1146,10 +972,6 @@ packages:
|
|||||||
setprototypeof@1.2.0:
|
setprototypeof@1.2.0:
|
||||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||||
|
|
||||||
sharp@0.35.1:
|
|
||||||
resolution: {integrity: sha512-lW979AMi+ESidzMv/Lnv+F9bknzLyxLqFI05Sm433vOeRcltgxQmXpnfOOFIAlKtwXU/ksupm2srQoFCkR214g==}
|
|
||||||
engines: {node: '>=20.9.0'}
|
|
||||||
|
|
||||||
side-channel-list@1.0.1:
|
side-channel-list@1.0.1:
|
||||||
resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==}
|
resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -1403,122 +1225,11 @@ snapshots:
|
|||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@emnapi/runtime@1.11.1':
|
|
||||||
dependencies:
|
|
||||||
tslib: 2.8.1
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@emnapi/wasi-threads@1.2.1':
|
'@emnapi/wasi-threads@1.2.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@img/colour@1.1.0': {}
|
|
||||||
|
|
||||||
'@img/sharp-darwin-arm64@0.35.1':
|
|
||||||
optionalDependencies:
|
|
||||||
'@img/sharp-libvips-darwin-arm64': 1.3.0
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-darwin-x64@0.35.1':
|
|
||||||
optionalDependencies:
|
|
||||||
'@img/sharp-libvips-darwin-x64': 1.3.0
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-freebsd-wasm32@0.35.1':
|
|
||||||
dependencies:
|
|
||||||
'@img/sharp-wasm32': 0.35.1
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-libvips-darwin-arm64@1.3.0':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-libvips-darwin-x64@1.3.0':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-arm64@1.3.0':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-arm@1.3.0':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-ppc64@1.3.0':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-riscv64@1.3.0':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-s390x@1.3.0':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-x64@1.3.0':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linuxmusl-arm64@1.3.0':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linuxmusl-x64@1.3.0':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-linux-arm64@0.35.1':
|
|
||||||
optionalDependencies:
|
|
||||||
'@img/sharp-libvips-linux-arm64': 1.3.0
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-linux-arm@0.35.1':
|
|
||||||
optionalDependencies:
|
|
||||||
'@img/sharp-libvips-linux-arm': 1.3.0
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-linux-ppc64@0.35.1':
|
|
||||||
optionalDependencies:
|
|
||||||
'@img/sharp-libvips-linux-ppc64': 1.3.0
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-linux-riscv64@0.35.1':
|
|
||||||
optionalDependencies:
|
|
||||||
'@img/sharp-libvips-linux-riscv64': 1.3.0
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-linux-s390x@0.35.1':
|
|
||||||
optionalDependencies:
|
|
||||||
'@img/sharp-libvips-linux-s390x': 1.3.0
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-linux-x64@0.35.1':
|
|
||||||
optionalDependencies:
|
|
||||||
'@img/sharp-libvips-linux-x64': 1.3.0
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-linuxmusl-arm64@0.35.1':
|
|
||||||
optionalDependencies:
|
|
||||||
'@img/sharp-libvips-linuxmusl-arm64': 1.3.0
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-linuxmusl-x64@0.35.1':
|
|
||||||
optionalDependencies:
|
|
||||||
'@img/sharp-libvips-linuxmusl-x64': 1.3.0
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-wasm32@0.35.1':
|
|
||||||
dependencies:
|
|
||||||
'@emnapi/runtime': 1.11.1
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-webcontainers-wasm32@0.35.1':
|
|
||||||
dependencies:
|
|
||||||
'@img/sharp-wasm32': 0.35.1
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-win32-arm64@0.35.1':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-win32-ia32@0.35.1':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@img/sharp-win32-x64@0.35.1':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@jridgewell/sourcemap-codec@1.5.5': {}
|
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||||
|
|
||||||
'@messageformat/core@3.4.0':
|
'@messageformat/core@3.4.0':
|
||||||
@@ -2324,8 +2035,6 @@ snapshots:
|
|||||||
|
|
||||||
safer-buffer@2.1.2: {}
|
safer-buffer@2.1.2: {}
|
||||||
|
|
||||||
semver@7.8.4: {}
|
|
||||||
|
|
||||||
send@0.19.2:
|
send@0.19.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 2.6.9
|
debug: 2.6.9
|
||||||
@@ -2355,38 +2064,6 @@ snapshots:
|
|||||||
|
|
||||||
setprototypeof@1.2.0: {}
|
setprototypeof@1.2.0: {}
|
||||||
|
|
||||||
sharp@0.35.1:
|
|
||||||
dependencies:
|
|
||||||
'@img/colour': 1.1.0
|
|
||||||
detect-libc: 2.1.2
|
|
||||||
semver: 7.8.4
|
|
||||||
optionalDependencies:
|
|
||||||
'@img/sharp-darwin-arm64': 0.35.1
|
|
||||||
'@img/sharp-darwin-x64': 0.35.1
|
|
||||||
'@img/sharp-freebsd-wasm32': 0.35.1
|
|
||||||
'@img/sharp-libvips-darwin-arm64': 1.3.0
|
|
||||||
'@img/sharp-libvips-darwin-x64': 1.3.0
|
|
||||||
'@img/sharp-libvips-linux-arm': 1.3.0
|
|
||||||
'@img/sharp-libvips-linux-arm64': 1.3.0
|
|
||||||
'@img/sharp-libvips-linux-ppc64': 1.3.0
|
|
||||||
'@img/sharp-libvips-linux-riscv64': 1.3.0
|
|
||||||
'@img/sharp-libvips-linux-s390x': 1.3.0
|
|
||||||
'@img/sharp-libvips-linux-x64': 1.3.0
|
|
||||||
'@img/sharp-libvips-linuxmusl-arm64': 1.3.0
|
|
||||||
'@img/sharp-libvips-linuxmusl-x64': 1.3.0
|
|
||||||
'@img/sharp-linux-arm': 0.35.1
|
|
||||||
'@img/sharp-linux-arm64': 0.35.1
|
|
||||||
'@img/sharp-linux-ppc64': 0.35.1
|
|
||||||
'@img/sharp-linux-riscv64': 0.35.1
|
|
||||||
'@img/sharp-linux-s390x': 0.35.1
|
|
||||||
'@img/sharp-linux-x64': 0.35.1
|
|
||||||
'@img/sharp-linuxmusl-arm64': 0.35.1
|
|
||||||
'@img/sharp-linuxmusl-x64': 0.35.1
|
|
||||||
'@img/sharp-webcontainers-wasm32': 0.35.1
|
|
||||||
'@img/sharp-win32-arm64': 0.35.1
|
|
||||||
'@img/sharp-win32-ia32': 0.35.1
|
|
||||||
'@img/sharp-win32-x64': 0.35.1
|
|
||||||
|
|
||||||
side-channel-list@1.0.1:
|
side-channel-list@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,698 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<u-popup v-model="localVisible" mode="bottom" :height="height" :closeable="true" @close="handleClose">
|
||||||
|
<view class="print-popup">
|
||||||
|
<!-- 标题栏 -->
|
||||||
|
<view class="print-popup__header">
|
||||||
|
<text class="print-popup__title">标签打印</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 隐藏画布,用于标签绘制 -->
|
||||||
|
<canvas
|
||||||
|
:id="canvasId"
|
||||||
|
:canvas-id="canvasId"
|
||||||
|
type="2d"
|
||||||
|
:style="canvasStyles"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<scroll-view scroll-y="true" class="print-popup__body">
|
||||||
|
<!-- 预览区域 -->
|
||||||
|
<view class="preview-section" v-if="previewList.length > 0">
|
||||||
|
<text class="preview-section__title">打印预览</text>
|
||||||
|
<view class="preview-section__list">
|
||||||
|
<image
|
||||||
|
v-for="item in previewList"
|
||||||
|
:src="item.value"
|
||||||
|
:key="item.key"
|
||||||
|
class="preview-img"
|
||||||
|
mode="widthFix"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 打印机选择 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">打印机</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<picker :value="deviceIndex" :range="deviceList" @change="onDeviceChanged" range-key="name">
|
||||||
|
<view class="setting-row__picker">
|
||||||
|
<text
|
||||||
|
class="setting-row__value"
|
||||||
|
:class="{ 'setting-row__value--empty': !deviceList[deviceIndex]?.deviceId }"
|
||||||
|
>
|
||||||
|
{{ deviceList[deviceIndex]?.name || '未检测到打印机' }}
|
||||||
|
</text>
|
||||||
|
<u-icon name="arrow-down" :size="24" color="#999" />
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 出纸方向 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">出纸方向</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<picker :value="rotationIndex" :range="rotationList" @change="onRotationChanged" range-key="name">
|
||||||
|
<view class="setting-row__picker">
|
||||||
|
<text class="setting-row__value">{{ rotationList[rotationIndex]?.name || '' }}</text>
|
||||||
|
<u-icon name="arrow-down" :size="24" color="#999" />
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 纸张类型 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">纸张类型</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<picker :value="gapIndex" :range="gapList" @change="onGapTypeChanged" range-key="name">
|
||||||
|
<view class="setting-row__picker">
|
||||||
|
<text class="setting-row__value">{{ gapList[gapIndex]?.name || '' }}</text>
|
||||||
|
<u-icon name="arrow-down" :size="24" color="#999" />
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 打印浓度 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">打印浓度</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<picker :value="darknessIndex" :range="darknessList" @change="onDarknessChanged" range-key="name">
|
||||||
|
<view class="setting-row__picker">
|
||||||
|
<text class="setting-row__value">{{ darknessList[darknessIndex]?.name || '' }}</text>
|
||||||
|
<u-icon name="arrow-down" :size="24" color="#999" />
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 打印速度 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">打印速度</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<picker :value="speedIndex" :range="speedList" @change="onPrintSpeedChanged" range-key="name">
|
||||||
|
<view class="setting-row__picker">
|
||||||
|
<text class="setting-row__value">{{ speedList[speedIndex]?.name || '' }}</text>
|
||||||
|
<u-icon name="arrow-down" :size="24" color="#999" />
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 灰度阈值 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">灰度阈值</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<input class="setting-row__input" type="number" v-model="threshold" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- JSON配置模式 -->
|
||||||
|
<view class="setting-row">
|
||||||
|
<text class="setting-row__label">JSON配置</text>
|
||||||
|
<view class="setting-row__right">
|
||||||
|
<switch :checked="jsonMode" @change="onPrintModeChanged" style="transform: scale(0.75)" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- 底部操作按钮 -->
|
||||||
|
<view class="print-popup__footer">
|
||||||
|
<view class="footer-grid">
|
||||||
|
<view class="footer-btn" @click="handleStartDiscovery">
|
||||||
|
<u-icon name="search" :size="30" color="#2979ff" />
|
||||||
|
<text>搜索打印机</text>
|
||||||
|
</view>
|
||||||
|
<view class="footer-btn" @click="handleStopDiscovery">
|
||||||
|
<u-icon name="close-circle" :size="30" color="#f56c6c" />
|
||||||
|
<text>停止搜索</text>
|
||||||
|
</view>
|
||||||
|
<view class="footer-btn" @click="handleOpenPrinter">
|
||||||
|
<u-icon name="link" :size="30" color="#2979ff" />
|
||||||
|
<text>连接打印机</text>
|
||||||
|
</view>
|
||||||
|
<view class="footer-btn" @click="handleClosePrinter">
|
||||||
|
<u-icon name="minus-circle" :size="30" color="#f56c6c" />
|
||||||
|
<text>断开连接</text>
|
||||||
|
</view>
|
||||||
|
<view class="footer-btn footer-btn--print" @click="handlePrintLabel">
|
||||||
|
<u-icon v-if="!printing" name="printer" :size="30" color="#fff" />
|
||||||
|
<u-icon v-else name="reload" :size="30" color="#fff" class="spinning" />
|
||||||
|
<text>{{ printing ? '打印中...' : '打印' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, onBeforeUnmount, nextTick, getCurrentInstance } from 'vue'
|
||||||
|
import {
|
||||||
|
DrawType,
|
||||||
|
LPAPIFactory
|
||||||
|
} from '@/assets/js/js_sdk'
|
||||||
|
import '@/utils/bwipjs-polyfill.js'
|
||||||
|
import bwipjs from '@/scanpages/assets/bwip-js/bwip-js.mjs'
|
||||||
|
|
||||||
|
// ===== Props =====
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: { type: Boolean, default: false },
|
||||||
|
height: { type: String, default: '85%' },
|
||||||
|
labelWidth: { type: Number, default: 50 },
|
||||||
|
labelHeight: { type: Number, default: 30 },
|
||||||
|
margin: { type: Number, default: 2 },
|
||||||
|
barcodeText: { type: String, default: '12345678' },
|
||||||
|
barcodeTopText: { type: String, default: '' },
|
||||||
|
barcodeBottomText: { type: String, default: '' }
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue', 'close', 'printed', 'error'])
|
||||||
|
|
||||||
|
const instance = getCurrentInstance()
|
||||||
|
|
||||||
|
// ===== 响应式数据 =====
|
||||||
|
const canvasId = 'lpapi-ble-popup'
|
||||||
|
const labelW = ref(960)
|
||||||
|
const labelH = ref(960)
|
||||||
|
const canvasStyles = ref({})
|
||||||
|
const localVisible = ref(false)
|
||||||
|
const deviceList = ref([{ name: '未检测到打印机' }])
|
||||||
|
const deviceIndex = ref(0)
|
||||||
|
const rotationIndex = ref(1)
|
||||||
|
const rotationList = [
|
||||||
|
{ name: '横向打印', value: 0 },
|
||||||
|
{ name: '右转90度', value: 90 },
|
||||||
|
{ name: '转转180度', value: 180 },
|
||||||
|
{ name: '左转90度', value: 270 }
|
||||||
|
]
|
||||||
|
const gapList = [
|
||||||
|
{ name: '随打印机设置', value: 255 },
|
||||||
|
{ name: '小票纸', value: 0 },
|
||||||
|
{ name: '不干胶', value: 2 },
|
||||||
|
{ name: '卡纸', value: 3 }
|
||||||
|
]
|
||||||
|
const gapIndex = ref(0)
|
||||||
|
const darknessList = [
|
||||||
|
{ name: '随打印机设置', value: 255 },
|
||||||
|
{ name: '6 (正常)', value: 6 },
|
||||||
|
{ name: '7', value: 7 },
|
||||||
|
{ name: '8', value: 8 },
|
||||||
|
{ name: '9', value: 9 },
|
||||||
|
{ name: '10 (较浓)', value: 10 },
|
||||||
|
{ name: '11', value: 11 },
|
||||||
|
{ name: '12', value: 12 },
|
||||||
|
{ name: '13', value: 13 },
|
||||||
|
{ name: '14', value: 14 },
|
||||||
|
{ name: '15 (最浓)', value: 15 }
|
||||||
|
]
|
||||||
|
const darknessIndex = ref(0)
|
||||||
|
const speedList = [
|
||||||
|
{ name: '随打印机设置', value: 255 },
|
||||||
|
{ name: '最慢', value: 1 },
|
||||||
|
{ name: '较慢', value: 2 },
|
||||||
|
{ name: '正常', value: 3 },
|
||||||
|
{ name: '较快', value: 4 },
|
||||||
|
{ name: '最快', value: 5 }
|
||||||
|
]
|
||||||
|
const speedIndex = ref(0)
|
||||||
|
const threshold = ref(128)
|
||||||
|
const jsonMode = ref(false)
|
||||||
|
const printing = ref(false)
|
||||||
|
const isWeiXin = ref(false)
|
||||||
|
const isAlipay = ref(false)
|
||||||
|
const lpapi = ref(undefined)
|
||||||
|
const context = ref(undefined)
|
||||||
|
const previewList = ref([])
|
||||||
|
|
||||||
|
// ===== 取值辅助 =====
|
||||||
|
const getDevice = () => {
|
||||||
|
return deviceList.value[deviceIndex.value]
|
||||||
|
}
|
||||||
|
const getOrientation = () => {
|
||||||
|
return rotationList[rotationIndex.value]?.value || 0
|
||||||
|
}
|
||||||
|
const getGapType = () => {
|
||||||
|
return gapList[gapIndex.value]?.value || 255
|
||||||
|
}
|
||||||
|
const getPrintDarkness = () => {
|
||||||
|
return darknessList[darknessIndex.value]?.value || 255
|
||||||
|
}
|
||||||
|
const getPrintSpeed = () => {
|
||||||
|
return speedList[speedIndex.value]?.value || 255
|
||||||
|
}
|
||||||
|
const getThreshold = () => {
|
||||||
|
return Number(threshold.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Canvas 样式 =====
|
||||||
|
const updateCanvasStyle = () => {
|
||||||
|
var pos = { position: 'absolute' }
|
||||||
|
if (isWeiXin.value) {
|
||||||
|
pos.left = '-999999rpx'
|
||||||
|
pos.top = '-999999rpx'
|
||||||
|
pos.opacity = '0'
|
||||||
|
pos.pointerEvents = 'none'
|
||||||
|
pos.zIndex = '-1'
|
||||||
|
} else {
|
||||||
|
pos.left = '-999999rpx'
|
||||||
|
pos.top = '-999999rpx'
|
||||||
|
}
|
||||||
|
canvasStyles.value = Object.assign(
|
||||||
|
{ width: labelW.value + 'px', height: labelH.value + 'px' },
|
||||||
|
pos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Canvas 更新 =====
|
||||||
|
const updateCanvas = (jobInfo) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (jobInfo && jobInfo.canvas) {
|
||||||
|
labelW.value = jobInfo.canvas.width
|
||||||
|
labelH.value = jobInfo.canvas.height
|
||||||
|
updateCanvasStyle()
|
||||||
|
}
|
||||||
|
setTimeout(() => resolve(true), 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== PDF417 条码生成(使用 bwip-js)=====
|
||||||
|
const _renderBwipjs = (canvas, opts) => {
|
||||||
|
try {
|
||||||
|
bwipjs.toCanvas(canvas, opts)
|
||||||
|
} catch (e) {
|
||||||
|
if (typeof canvas.getContext === 'function') {
|
||||||
|
var proto = Object.getPrototypeOf(canvas)
|
||||||
|
var ctorName = proto && proto.constructor && proto.constructor.name
|
||||||
|
if (ctorName && !(/HTMLCanvasElement|OffscreenCanvas/).test(ctorName)) {
|
||||||
|
try {
|
||||||
|
Object.defineProperty(proto.constructor, 'name', { configurable: true, value: 'HTMLCanvasElement' })
|
||||||
|
bwipjs.toCanvas(canvas, opts)
|
||||||
|
Object.defineProperty(proto.constructor, 'name', { configurable: true, value: ctorName })
|
||||||
|
return
|
||||||
|
} catch (e2) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const generateBarcodeImage = (text, widthMM, heightMM) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var dpi = 203
|
||||||
|
var pxPerMM = dpi / 25.4
|
||||||
|
var tw = Math.round(widthMM * pxPerMM)
|
||||||
|
var th = Math.round(heightMM * pxPerMM)
|
||||||
|
|
||||||
|
var baseScale = Math.max(3, Math.floor(tw / 60))
|
||||||
|
var bwipOpts = {
|
||||||
|
bcid: 'pdf417',
|
||||||
|
text: text,
|
||||||
|
scale: baseScale,
|
||||||
|
includetext: false,
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
var query = uni.createSelectorQuery().in(instance)
|
||||||
|
query.select('#' + canvasId).node().exec((res) => {
|
||||||
|
try {
|
||||||
|
if (!res || !res[0] || !res[0].node) {
|
||||||
|
return reject(new Error('canvas 未找到'))
|
||||||
|
}
|
||||||
|
var canvas = res[0].node
|
||||||
|
_renderBwipjs(canvas, bwipOpts)
|
||||||
|
console.log('bwip-js PDF417:', { w: canvas.width, h: canvas.height, tw: tw, th: th })
|
||||||
|
|
||||||
|
uni.canvasToTempFilePath({
|
||||||
|
canvas: canvas,
|
||||||
|
x: 0, y: 0,
|
||||||
|
width: canvas.width,
|
||||||
|
height: canvas.height,
|
||||||
|
success: (t) => {
|
||||||
|
if (isWeiXin.value) {
|
||||||
|
var img = canvas.createImage()
|
||||||
|
img.src = t.tempFilePath
|
||||||
|
img.onload = () => { resolve(img) }
|
||||||
|
img.onerror = (e) => { reject(e) }
|
||||||
|
} else {
|
||||||
|
resolve(t.tempFilePath)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (e) => { reject(e) }
|
||||||
|
})
|
||||||
|
} catch (e) { reject(e) }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 标签绘制(总入口) =====
|
||||||
|
const printLabel = (isPreview) => {
|
||||||
|
if (jsonMode.value) {
|
||||||
|
return printLabelWithJsonMode(isPreview)
|
||||||
|
} else {
|
||||||
|
return printLabelWithDrawMode(isPreview)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const printLabelWithDrawMode = async (isPreview) => {
|
||||||
|
var api = lpapi.value
|
||||||
|
var lW = props.labelWidth
|
||||||
|
var lH = props.labelHeight
|
||||||
|
var m = props.margin
|
||||||
|
var uW = lW - m * 2
|
||||||
|
|
||||||
|
var jobInfo = api.startJob({
|
||||||
|
context: context.value,
|
||||||
|
width: lW,
|
||||||
|
height: lH,
|
||||||
|
orientation: getOrientation(),
|
||||||
|
isPreview: isPreview
|
||||||
|
})
|
||||||
|
await updateCanvas(jobInfo)
|
||||||
|
|
||||||
|
if (props.barcodeTopText) {
|
||||||
|
api.drawText({
|
||||||
|
text: props.barcodeTopText,
|
||||||
|
x: m,
|
||||||
|
y: m,
|
||||||
|
width: uW,
|
||||||
|
height: 5,
|
||||||
|
fontHeight: 4,
|
||||||
|
horizontalAlignment: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var barcodeY = m + (props.barcodeTopText ? 7 : 0)
|
||||||
|
var barcodeH = lH - m * 2 - (props.barcodeTopText ? 7 : 0) - (props.barcodeBottomText ? 7 : 0)
|
||||||
|
try {
|
||||||
|
var img = await generateBarcodeImage(props.barcodeText, uW, barcodeH)
|
||||||
|
api.drawImage({ img: img, x: m, y: barcodeY, width: uW, height: barcodeH })
|
||||||
|
} catch (e) {
|
||||||
|
console.error('PDF417 绘制失败:', e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.barcodeBottomText) {
|
||||||
|
var by = lH - m - 5
|
||||||
|
api.drawText({
|
||||||
|
text: props.barcodeBottomText,
|
||||||
|
x: m,
|
||||||
|
y: by,
|
||||||
|
width: uW,
|
||||||
|
height: 5,
|
||||||
|
fontHeight: 3.5,
|
||||||
|
horizontalAlignment: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.commitJob({
|
||||||
|
gapType: getGapType(),
|
||||||
|
printDarkness: getPrintDarkness(),
|
||||||
|
printSpeed: getPrintSpeed()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const printLabelWithJsonMode = (isPreview) => {
|
||||||
|
var device = getDevice()
|
||||||
|
var lW = props.labelWidth
|
||||||
|
var lH = props.labelHeight
|
||||||
|
var m = props.margin
|
||||||
|
var uW = lW - m * 2
|
||||||
|
|
||||||
|
var jobPage = []
|
||||||
|
|
||||||
|
if (props.barcodeTopText) {
|
||||||
|
jobPage.push({
|
||||||
|
type: DrawType.text,
|
||||||
|
text: props.barcodeTopText,
|
||||||
|
x: m,
|
||||||
|
y: m,
|
||||||
|
width: uW,
|
||||||
|
height: 5,
|
||||||
|
fontHeight: 4,
|
||||||
|
horizontalAlignment: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var barcodeY = m + (props.barcodeTopText ? 7 : 0)
|
||||||
|
var barcodeH = lH - m * 2 - (props.barcodeTopText ? 7 : 0) - (props.barcodeBottomText ? 7 : 0)
|
||||||
|
return generateBarcodeImage(props.barcodeText, uW, barcodeH).then((img) => {
|
||||||
|
jobPage.push({
|
||||||
|
type: DrawType.image,
|
||||||
|
img: img,
|
||||||
|
x: m,
|
||||||
|
y: barcodeY,
|
||||||
|
width: uW,
|
||||||
|
height: barcodeH
|
||||||
|
})
|
||||||
|
|
||||||
|
if (props.barcodeBottomText) {
|
||||||
|
jobPage.push({
|
||||||
|
type: DrawType.text,
|
||||||
|
text: props.barcodeBottomText,
|
||||||
|
x: m,
|
||||||
|
y: lH - m - 5,
|
||||||
|
width: uW,
|
||||||
|
height: 5,
|
||||||
|
fontHeight: 3.5,
|
||||||
|
horizontalAlignment: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return lpapi.value.print({
|
||||||
|
jobInfo: {
|
||||||
|
jobWidth: lW,
|
||||||
|
jobHeight: lH,
|
||||||
|
orientation: getOrientation(),
|
||||||
|
isPreview: isPreview
|
||||||
|
},
|
||||||
|
printerInfo: {
|
||||||
|
name: device ? device.name : undefined,
|
||||||
|
deviceId: device ? device.deviceId : undefined
|
||||||
|
},
|
||||||
|
jobPage: jobPage,
|
||||||
|
onJobCreated: (jobInfo) => {
|
||||||
|
return updateCanvas(jobInfo)
|
||||||
|
},
|
||||||
|
onPageComplete: (res) => {
|
||||||
|
// 标签页面渲染完毕时的回调
|
||||||
|
},
|
||||||
|
onPagePrintComplete: (res) => {
|
||||||
|
// 标签页面打印完毕时的回调
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 初始化 =====
|
||||||
|
const initPrinter = () => {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
isWeiXin.value = true
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
isAlipay.value = true
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
updateCanvasStyle()
|
||||||
|
|
||||||
|
lpapi.value = LPAPIFactory.getInstance({ showLog: 4 })
|
||||||
|
|
||||||
|
lpapi.value.startDiscovery({
|
||||||
|
timeout: 0,
|
||||||
|
deviceFound: (devices) => {
|
||||||
|
if (devices && devices.length > 0) {
|
||||||
|
deviceList.value.splice(0)
|
||||||
|
deviceList.value.push(...devices)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (isWeiXin.value) {
|
||||||
|
context.value = lpapi.value.createDrawContext()
|
||||||
|
} else {
|
||||||
|
context.value = lpapi.value.createDrawContext({ canvasId: canvasId })
|
||||||
|
}
|
||||||
|
if (context.value) {
|
||||||
|
lpapi.value.setDrawContext(context.value)
|
||||||
|
handlePreviewLabel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 选择器变更 =====
|
||||||
|
const onDeviceChanged = (e) => {
|
||||||
|
deviceIndex.value = e ? e.detail.value : 0
|
||||||
|
}
|
||||||
|
const onRotationChanged = (e) => {
|
||||||
|
rotationIndex.value = e ? e.detail.value : 0
|
||||||
|
}
|
||||||
|
const onGapTypeChanged = (e) => {
|
||||||
|
gapIndex.value = e ? e.detail.value : 0
|
||||||
|
}
|
||||||
|
const onDarknessChanged = (e) => {
|
||||||
|
darknessIndex.value = e ? e.detail.value : 0
|
||||||
|
}
|
||||||
|
const onPrintSpeedChanged = (e) => {
|
||||||
|
speedIndex.value = e ? e.detail.value : 0
|
||||||
|
}
|
||||||
|
const onPrintModeChanged = (e) => {
|
||||||
|
jsonMode.value = e.detail.value
|
||||||
|
handlePreviewLabel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 打印机操作 =====
|
||||||
|
const handleStartDiscovery = () => {
|
||||||
|
uni.showLoading({ title: '正在搜索打印机...' })
|
||||||
|
lpapi.value.startDiscovery({
|
||||||
|
timeout: 5000,
|
||||||
|
deviceFound: (devices) => {
|
||||||
|
if (devices && devices.length > 0) {
|
||||||
|
deviceList.value.splice(0)
|
||||||
|
deviceList.value.push(...devices)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
adapterStateChange: (result) => {
|
||||||
|
if (!result.discovering) {
|
||||||
|
uni.hideLoading()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleStopDiscovery = () => {
|
||||||
|
lpapi.value.stopDiscovery()
|
||||||
|
uni.hideLoading()
|
||||||
|
}
|
||||||
|
const handleOpenPrinter = () => {
|
||||||
|
const currDevice = getDevice()
|
||||||
|
if (!currDevice || !currDevice.deviceId) {
|
||||||
|
uni.showToast({ title: '未检测到打印机', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.showLoading({ title: '正在连接打印机...' })
|
||||||
|
lpapi.value.openPrinter({
|
||||||
|
name: currDevice.name,
|
||||||
|
deviceId: currDevice.deviceId,
|
||||||
|
tryTimes: isAlipay.value ? 1 : 5,
|
||||||
|
success: (resp) => {
|
||||||
|
console.log('---- 【打印机连接成功】')
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({ title: '打印机连接成功!', icon: 'success' })
|
||||||
|
},
|
||||||
|
fail: (resp) => {
|
||||||
|
console.warn('---- 【打印机连接失败】:', JSON.stringify(resp))
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({ title: '打印机连接失败!', icon: 'error' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handleClosePrinter = () => {
|
||||||
|
console.log('---- 关闭打印机!')
|
||||||
|
lpapi.value.closePrinter()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 预览 =====
|
||||||
|
const handlePreviewLabel = () => {
|
||||||
|
previewList.value.splice(0)
|
||||||
|
printLabel(true).then((res) => {
|
||||||
|
if (res.statusCode === 0) {
|
||||||
|
res.previewData.forEach((v) => {
|
||||||
|
previewList.value.push({
|
||||||
|
value: v,
|
||||||
|
key: Date.now() + '-' + Math.random() * 1000
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.warn('预览失败:', res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 打印 =====
|
||||||
|
const handlePrintLabel = async () => {
|
||||||
|
printing.value = true
|
||||||
|
try {
|
||||||
|
var d = getDevice()
|
||||||
|
if (!d || !d.deviceId) {
|
||||||
|
printing.value = false
|
||||||
|
return uni.showToast({ title: '未检测到打印机', icon: 'none' })
|
||||||
|
}
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
lpapi.value.openPrinter({
|
||||||
|
name: d.name,
|
||||||
|
deviceId: d.deviceId,
|
||||||
|
tryTimes: 5,
|
||||||
|
success: resolve,
|
||||||
|
fail: reject
|
||||||
|
})
|
||||||
|
})
|
||||||
|
var res = await printLabel(false)
|
||||||
|
if (res.statusCode === 0) {
|
||||||
|
uni.showToast({ title: '打印成功!', icon: 'success' })
|
||||||
|
emit('printed', { statusCode: 0 })
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: res.errMsg || '打印失败!', icon: 'error' })
|
||||||
|
emit('error', res)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('打印异常:', e)
|
||||||
|
uni.showToast({ title: '打印机连接失败!', icon: 'error' })
|
||||||
|
emit('error', e)
|
||||||
|
} finally {
|
||||||
|
printing.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 关闭弹窗 =====
|
||||||
|
const handleClose = () => {
|
||||||
|
handleClosePrinter()
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 监听器 =====
|
||||||
|
watch(() => props.modelValue, (val) => {
|
||||||
|
localVisible.value = val
|
||||||
|
if (val) nextTick(() => initPrinter())
|
||||||
|
})
|
||||||
|
watch(localVisible, (val) => {
|
||||||
|
emit('update:modelValue', val)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (lpapi.value) {
|
||||||
|
lpapi.value.closePrinter()
|
||||||
|
lpapi.value.stopDiscovery()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.print-popup { display: flex; flex-direction: column; height: 100%; background: #f5f6f8;
|
||||||
|
&__header { flex-shrink: 0; padding: 28rpx 32rpx 20rpx; text-align: center; border-bottom: 1rpx solid #e8ecf1; }
|
||||||
|
&__title { font-size: 32rpx; font-weight: 700; color: #1a1a2e; }
|
||||||
|
&__body { flex: 1; overflow-y: auto; overflow-x: hidden; box-sizing: border-box; padding: 20rpx 24rpx; }
|
||||||
|
&__footer { flex-shrink: 0; padding: 12rpx 24rpx; padding-bottom: calc(12rpx + env(safe-area-inset-bottom)); background: #fff; border-top: 1rpx solid #e8ecf1; }
|
||||||
|
}
|
||||||
|
.footer-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12rpx; }
|
||||||
|
.footer-btn { display: flex; align-items: center; justify-content: center; gap: 8rpx; height: 76rpx; font-size: 26rpx; font-weight: 500; border-radius: 12rpx; background: #f5f6f8; color: #1a1a2e; transition: transform .15s, box-shadow .15s;
|
||||||
|
&:active { transform: scale(.95); opacity: .85; }
|
||||||
|
&--print { background: linear-gradient(135deg, #2979ff, #5a9aff); color: #fff; box-shadow: 0 4rpx 16rpx rgba(41,121,255,.35); grid-column: 1 / -1;}
|
||||||
|
}
|
||||||
|
.spinning { animation: spin .8s linear infinite; }
|
||||||
|
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
||||||
|
.setting-row { display: flex; align-items: center; justify-content: space-between; box-sizing: border-box; padding: 22rpx 24rpx; margin-bottom: 12rpx; background: #fff; border-radius: 12rpx;
|
||||||
|
&__label { font-size: 26rpx; color: #6b7c93; flex-shrink: 0; width: 160rpx; }
|
||||||
|
&__right { flex: 1; display: flex; justify-content: flex-end; }
|
||||||
|
&__picker { display: flex; align-items: center; gap: 8rpx; }
|
||||||
|
&__value { font-size: 26rpx; color: #1a1a2e; font-weight: 500;
|
||||||
|
&--empty { color: #b0bec5; }
|
||||||
|
}
|
||||||
|
&__input { flex: 1; font-size: 26rpx; color: #1a1a2e; text-align: right; padding: 4rpx 0; }
|
||||||
|
}
|
||||||
|
.preview-section { margin-bottom: 24rpx; padding: 20rpx; background: #fff; border-radius: 12rpx; overflow: hidden;
|
||||||
|
&__title { display: block; font-size: 26rpx; font-weight: 600; color: #1a1a2e; margin-bottom: 16rpx; }
|
||||||
|
&__list { display: flex; flex-wrap: wrap; justify-content: center; gap: 16rpx; }
|
||||||
|
}
|
||||||
|
.preview-img { width: 100%; border: 1rpx dashed #ccc; border-radius: 4rpx; }
|
||||||
|
</style>
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
<view class="print-bar">
|
<view class="print-bar">
|
||||||
<view class="print-btn" @click="showPrint = true">
|
<view class="print-btn" @click="showPrint = true">
|
||||||
<u-icon name="printer" :size="32" color="#fff" />
|
<u-icon name="printer" :size="32" color="#fff" />
|
||||||
<text class="print-btn__text">打印二维码</text>
|
<text class="print-btn__text">预览打印</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 52 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 4.1 KiB |
@@ -0,0 +1,24 @@
|
|||||||
|
// 微信小程序 atob polyfill(bwip-js 字体解码依赖)
|
||||||
|
// 此文件作为副作用导入,必须在 bwip-js 之前加载
|
||||||
|
|
||||||
|
var _chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
|
||||||
|
|
||||||
|
function _atob(input) {
|
||||||
|
var str = String(input).replace(/[=]+$/, '')
|
||||||
|
var output = ''
|
||||||
|
var bc = 0, bs, buffer = 0, i = 0
|
||||||
|
for (; str.charAt(i | 0); i++) {
|
||||||
|
bs = _chars.indexOf(str.charAt(i))
|
||||||
|
buffer = (buffer << 6) | bs
|
||||||
|
bc += 6
|
||||||
|
if (bc >= 8) {
|
||||||
|
bc -= 8
|
||||||
|
output += String.fromCharCode((buffer >>> bc) & 255)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同时设置 globalThis 和 global(兼容不同微信基础库版本)
|
||||||
|
try { globalThis.atob = globalThis.atob || _atob } catch (e) {}
|
||||||
|
try { global.atob = global.atob || _atob } catch (e) {}
|
||||||
Reference in New Issue
Block a user