Commit 1e825855 by qinjianhui

fix: 修复 Lodop 打印 PDF 到虚拟打印机时输出空白的问题

parent 51a1fdda
import useLodop from '@/utils/hooks/useLodop.ts'
import { printWithLodop } from '@/utils/lodopPrinter'
import { ElMessage } from 'element-plus'
import useLodop, { LODOPObject } from '@/utils/hooks/useLodop.ts'
const { getCLodop } = useLodop()
const lodopCall = async (fn: (lodop: LODOPObject) => string) => {
if (!window._lodop) {
window._lodop = getCLodop(null, null)
if (window._lodop) {
window._lodop.On_Return_Remain = true
window._lodop.SET_PRINT_MODE('CATCH_PRINT_STATUS', true)
window._lodopCallback = {}
window._lodop.On_Return = function (id, value) {
const cb = window._lodopCallback[id]
if (!cb) return
delete window._lodopCallback[id]
cb(value)
}
}
}
return new Promise((resolve) => {
let id
if (window._lodop) {
id = fn(window._lodop)
}
window._lodopCallback[id || 0] = resolve
})
}
function downloadPDF(url: string) {
if (!/^https?:/i.test(url)) return url
let xhr,
arrybuffer = false,
dataArray = null
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest()
} else {
xhr = new window.ActiveXObject('MSXML2.XMLHTTP')
}
xhr.open('GET', url, false) //同步方式
if (xhr.overrideMimeType)
try {
xhr.responseType = 'arraybuffer'
arrybuffer = true
} catch (err) {
xhr.overrideMimeType('text/plain; charset=x-user-defined')
}
xhr.send(null)
const data = xhr.response || xhr.responseBody
if (typeof Uint8Array !== 'undefined') {
if (arrybuffer) {
dataArray = new Uint8Array(data)
} else {
dataArray = new Uint8Array(data.length)
for (let i = 0; i < dataArray.length; i++) {
dataArray[i] = data.charCodeAt(i)
}
}
} else {
dataArray = window.VBS_BinaryToArray(data).toArray() //兼容IE低版本
}
const digits =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
let strData = ''
for (let i = 0, ii = dataArray.length; i < ii; i += 3) {
if (isNaN(dataArray[i])) break
const b1 = dataArray[i] & 0xff,
b2 = dataArray[i + 1] & 0xff,
b3 = dataArray[i + 2] & 0xff
const d1 = b1 >> 2,
d2 = ((b1 & 3) << 4) | (b2 >> 4)
const d3 = i + 1 < ii ? ((b2 & 0xf) << 2) | (b3 >> 6) : 64
const d4 = i + 2 < ii ? b3 & 0x3f : 64
strData +=
digits.substring(d1, d1 + 1) +
digits.substring(d2, d2 + 1) +
digits.substring(d3, d3 + 1) +
digits.substring(d4, d4 + 1)
}
return strData
}
export const print = async (url: string,printDevice:string) => {
await printWithLodop({
getCLodop: () => getCLodop(null, null),
printer: printDevice,
data: { filePath: url },
callback: (_status: boolean) => {},
baseUrl: '',
const lodop = getCLodop(null, null) //调用getLodop获取LODOP对象
if (!lodop) return
lodop.PRINT_INIT('打印内容')
// SET_PRINTER_INDEX 指定打印设备
const setPrintRes = lodop.SET_PRINTER_INDEX(printDevice)
if (!setPrintRes) {
ElMessage.warning('设置面单打印机出错')
return
}
lodop.ADD_PRINT_PDF(0, 0, '100%', '100%', downloadPDF(url))
console.log(lodop)
if (lodop.CVERSION) {
const startTime = Date.now()
const jobCode = await lodopCall((lodop: LODOPObject) => {
lodop.SET_PRINT_MODE('CATCH_PRINT_STATUS', true)
return lodop.PRINT()
})
console.log('[LODOP] job ' + jobCode)
// eslint-disable-next-line no-constant-condition
while (true) {
const ok = await lodopCall((lodop: LODOPObject) =>
lodop.GET_VALUE('PRINT_STATUS_OK', jobCode),
)
if (ok == 1) {
// 打印状态:成功
return
}
// 如果打印状态表示未成功或者返回了空,继续获取任务是否存在
const exist = await lodopCall((lodop: LODOPObject) =>
lodop.GET_VALUE('PRINT_STATUS_EXIST', jobCode),
)
console.log(
'[LODOP] PRINT_STATUS OK,EXIST',
jobCode,
ok,
exist,
`(${Date.now() - startTime}ms)`,
)
if (exist == 0) {
// 任务不存在了
return
}
await new Promise((r) => setTimeout(r, 500))
if (Date.now() - startTime >= 30000) {
ElMessage.error('打印超时(30秒)')
return
}
}
} else {
lodop.PRINT()
}
}
import { ElMessage } from 'element-plus'
import type { LODOPObject } from '@/utils/hooks/useLodop'
type LodopGetter = () => LODOPObject | null
export function downloadPDF(url: string): string {
if (!/^https?:/i.test(url)) return url
const xhr = new XMLHttpRequest()
let arrayBuffer = false
xhr.open('GET', url, false)
if (xhr.overrideMimeType) {
try {
xhr.responseType = 'arraybuffer'
arrayBuffer = true
} catch {
xhr.overrideMimeType('text/plain; charset=x-user-defined')
}
}
xhr.send(null)
const data = (xhr.response ||
(xhr as unknown as { responseBody?: unknown }).responseBody) as
| ArrayBuffer
| string
let dataArray: Uint8Array
if (arrayBuffer) {
dataArray = new Uint8Array(data as ArrayBuffer)
} else {
const text = data as string
dataArray = new Uint8Array(text.length)
for (let i = 0; i < dataArray.length; i++) dataArray[i] = text.charCodeAt(i)
}
const digits =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
let strData = ''
for (let i = 0, ii = dataArray.length; i < ii; i += 3) {
const b1 = dataArray[i] & 0xff
const b2 = dataArray[i + 1] & 0xff
const b3 = dataArray[i + 2] & 0xff
const d1 = b1 >> 2
const d2 = ((b1 & 3) << 4) | (b2 >> 4)
const d3 = i + 1 < ii ? ((b2 & 0xf) << 2) | (b3 >> 6) : 64
const d4 = i + 2 < ii ? b3 & 0x3f : 64
strData +=
digits.charAt(d1) +
digits.charAt(d2) +
digits.charAt(d3) +
digits.charAt(d4)
}
return 'data:application/pdf;base64,' + strData
}
export function createLodopCaller(getCLodop: LodopGetter) {
let lodop: LODOPObject | null = null
let lodopCallback: { [key: string]: (value: string) => void } = {}
return (fn: (lodop: LODOPObject) => string) => {
if (!lodop) {
lodop = getCLodop()
if (!lodop) return Promise.resolve('')
lodop.On_Return_Remain = true
lodop.SET_PRINT_MODE('CATCH_PRINT_STATUS', true)
lodopCallback = {}
lodop.On_Return = (id, value) => {
const cb = lodopCallback[id]
if (!cb) return
delete lodopCallback[id]
cb(value)
}
}
return new Promise<string>((resolve) => {
if (!lodop) {
resolve('')
return
}
const id = fn(lodop)
lodopCallback[id] = resolve
})
}
}
interface PrintData {
filePath?: string
fileData?: string
}
interface PrintWithLodopOptions {
getCLodop: LodopGetter
printer: string
data: PrintData
callback?: (success: boolean) => void
timeout?: number
baseUrl?: string
}
export async function printWithLodop(options: PrintWithLodopOptions) {
const {
getCLodop,
printer,
data,
callback,
timeout = 30000,
baseUrl = '',
} = options
const lodop = getCLodop()
if (!lodop) return
const lodopCall = createLodopCaller(getCLodop)
lodop.PRINT_INIT('打印内容')
const printerIndex = lodop.SET_PRINTER_INDEX(printer)
if (!printerIndex) {
ElMessage.error('打印机设置失败')
callback?.(false)
return
}
if (data.filePath) {
const strURL = /^https?:/i.test(data.filePath)
? data.filePath
: baseUrl + data.filePath
lodop.ADD_PRINT_PDF(
0,
0,
'100%',
'100%',
/^https?:/i.test(strURL) ? downloadPDF(strURL) : strURL,
)
} else {
lodop.SEND_PRINT_RAWDATA(data.fileData || '')
}
if (lodop.CVERSION) {
const startTime = Date.now()
const jobCode = await lodopCall((instance) => {
instance.SET_PRINT_MODE('CATCH_PRINT_STATUS', true)
return instance.PRINT()
})
let pending = true
while (pending) {
const ok = await lodopCall((instance) =>
instance.GET_VALUE('PRINT_STATUS_OK', jobCode),
)
if (ok == '1' || ok == '1.0') {
callback?.(true)
return
}
const exist = await lodopCall((instance) =>
instance.GET_VALUE('PRINT_STATUS_EXIST', jobCode),
)
if (exist == '0' || exist == '0.0') {
callback?.(true)
return
}
await new Promise((r) => setTimeout(r, 500))
if (Date.now() - startTime >= timeout) {
ElMessage.error(`打印超时(${Math.floor(timeout / 1000)}秒)`)
callback?.(false)
pending = false
}
}
return
}
lodop.PRINT()
callback?.(false)
}
......@@ -977,8 +977,7 @@ import {
import BigNumber from 'bignumber.js'
import { filePath } from '@/api/axios'
import { OrderData } from '@/types/api/podMakeOrder'
import useLodop from '@/utils/hooks/useLodop'
import { printWithLodop } from '@/utils/lodopPrinter'
import useLodop, { LODOPObject } from '@/utils/hooks/useLodop'
import LogisticsWaySelect from '@/views/logistics/components/LogisticsWaySelect'
import ProductTypeFilter from './component/ProductTypeFilter.vue'
import ConfirmOrderDialog from './component/ConfirmOrderDialog.vue'
......@@ -1470,7 +1469,9 @@ const baseProductColumns = computed(() => [
render: (row: ProductListData) => {
return (
<span>
{new BigNumber(row.templatePrice ?? 0).plus(row.craftPrice ?? 0).toString()}
{new BigNumber(row.templatePrice ?? 0)
.plus(row.craftPrice ?? 0)
.toString()}
</span>
)
},
......@@ -1976,14 +1977,131 @@ const printOrder = async (
data: OrderData,
callback: (status: boolean) => void,
) => {
await printWithLodop({
getCLodop: () => getCLodop(null, null),
printer: sheetPrinter.value,
data,
callback,
baseUrl: filePath,
const lodop = getCLodop(null, null)
if (!lodop) return
lodop.PRINT_INIT('打印内容')
const printerIndex = lodop.SET_PRINTER_INDEX(sheetPrinter.value)
console.log(
'printerIndex',
printerIndex,
`sheetPrinter.value:${sheetPrinter.value}`,
)
if (!printerIndex) {
ElMessage.error('打印机设置失败')
callback && callback(false)
return
}
if (data.filePath) {
const strURL = /^https?:/i.test(data.filePath)
? data.filePath
: filePath + data.filePath
const pdfData = /^https?:/i.test(strURL)
? await downloadPDF(strURL)
: strURL
lodop.ADD_PRINT_PDF(0, 0, '100%', '100%', pdfData)
} else {
lodop.SEND_PRINT_RAWDATA(data.fileData || '')
}
console.log('lodop.CVERSION', lodop.CVERSION)
if (lodop.CVERSION) {
const startTime = Date.now()
const jobCode = await lodopCall((lodop) => {
lodop.SET_PRINT_MODE('CATCH_PRINT_STATUS', true)
return lodop.PRINT()
})
console.log('jobCode', jobCode)
// eslint-disable-next-line no-constant-condition
while (true) {
const ok = await lodopCall((lodop) =>
lodop.GET_VALUE('PRINT_STATUS_OK', jobCode),
)
console.log('PRINT_STATUS_OK:', jobCode, `ok: ${ok}`)
if (ok == 1) {
console.log('打印成功')
// 打印状态:成功
callback && callback(true)
return
}
// 如果打印状态表示未成功或者返回了空,继续获取任务是否存在
const exist = await lodopCall((lodop) =>
lodop.GET_VALUE('PRINT_STATUS_EXIST', jobCode),
)
console.log(
'[LODOP] PRINT_STATUS OK,EXIST',
jobCode,
`ok:${ok}`,
`exist:${exist}`,
`jobCode:${jobCode}`,
`(${Date.now() - startTime}ms)`,
)
if (exist == 0) {
console.log('任务不存在了', `exist:${exist}`)
// 任务不存在了
callback && callback(true)
return
}
await new Promise((r) => setTimeout(r, 500))
if (Date.now() - startTime >= 30000) {
console.log('打印超时(30秒)')
ElMessage.error('打印超时(30秒)')
callback && callback(false)
return
}
}
} else {
lodop.PRINT()
callback && callback(false)
}
}
let _lodop: LODOPObject | null = null
let _lodopCallback: { [key: string]: (value: string) => void } = {}
const lodopCall = (fn: (lodop: LODOPObject) => string) => {
if (!_lodop) {
_lodop = getCLodop(null, null)
if (!_lodop) return
_lodop.On_Return_Remain = true
_lodop.SET_PRINT_MODE('CATCH_PRINT_STATUS', true)
_lodopCallback = {}
_lodop.On_Return = (id, value) => {
console.log('lodopCall return', id, JSON.stringify(value))
const cb = _lodopCallback[id]
if (!cb) return
delete _lodopCallback[id]
cb(value)
}
}
return new Promise((resolve) => {
if (!_lodop) return
const id = fn(_lodop)
console.log('lodopCall', id)
_lodopCallback[id] = resolve
})
}
const downloadPDF = async (url: string): Promise<string> => {
if (!/^https?:/i.test(url)) return url
const headers: Record<string, string> = {}
const token = localStorage.getItem('token')
if (token) headers['jwt-token'] = token
const response = await fetch(url, { headers })
if (!response.ok) {
console.error(
`PDF download failed: ${response.status} ${response.statusText}`,
)
return ''
}
const arrayBuffer = await response.arrayBuffer()
const bytes = new Uint8Array(arrayBuffer)
let binary = ''
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i])
}
return 'data:application/pdf;base64,' + btoa(binary)
}
const handleDownloadMaterial = async () => {
if (!ensureSelection()) return
const usePodOrderDownloadStatuses = ['PENDING_DELIVERY', 'SUSPEND']
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment