| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- <?php
- namespace app\common\library\ps;
- use think\Config;
- /**
- * Lodop 模式:测试环境只预览,生产可改为正式打印。
- */
- class LodopPrinter
- {
- /**
- * @return string preview|print
- */
- public static function mode()
- {
- $mode = Config::get('site.ps_lodop_mode') ?: (Config::get('ps.lodop.mode') ?: 'preview');
- return $mode === 'print' ? 'print' : 'preview';
- }
- /**
- * 下发给前端的 Lodop 调用包。多张流程单用 NEWPAGE 分页,copies 为整套重复次数。
- *
- * @param string $html 兼容单页
- * @param string $title
- * @param array $pages [['html'=>..., 'title'=>...], ...]
- * @param int $copies
- * @param array $page ['w'=>mm,'h'=>mm,'paper_size'=>'A4']
- * @return array
- */
- public static function buildTask($html, $title = '流程单', array $pages = [], $copies = 1, array $page = [])
- {
- $mode = self::mode();
- $copies = max(1, (int)$copies);
- if (!$pages) {
- $pages = [[
- 'html' => $html,
- 'title' => $title,
- ]];
- }
- $first = $pages[0]['html'] ?? $html;
- $printTexts = [];
- foreach ($pages as $row) {
- if (!empty($row['print_items']) && is_array($row['print_items'])) {
- $printTexts[] = $row['print_items'];
- } elseif (!empty($row['items']) && is_array($row['items'])) {
- $printTexts[] = $row['items'];
- } else {
- $printTexts[] = [];
- }
- }
- return [
- 'mode' => $mode,
- 'js_url' => Config::get('site.ps_lodop_js') ?: (Config::get('ps.lodop.c_lodop_js') ?: 'http://localhost:8000/CLodopfuncs.js'),
- 'title' => $title,
- 'html' => $first,
- 'pages' => $pages,
- 'print_texts' => $printTexts,
- 'copies' => $copies,
- 'print_api' => $mode === 'print' ? 'PRINT' : 'PREVIEW',
- 'page' => $page,
- 'commands' => self::commands($pages, $title, $copies, $mode, $page),
- ];
- }
- /**
- * 前端按顺序调用 CLODOP 的指令列表
- * @param array $pages
- * @param string $title
- * @param int $copies
- * @param string $mode
- * @param array $page
- * @return array
- */
- protected static function commands(array $pages, $title, $copies, $mode, array $page = [])
- {
- $size = self::paperMm($page);
- $w = $size['w'];
- $h = $size['h'];
- $wMm = $w . 'mm';
- $hMm = $h . 'mm';
- $commands = [
- ['PRINT_INIT', $title],
- // 第四参数不要写 A4/A5:打印机没有该纸时会落到默认标签纸(常见 90×60、110×210)。
- ['SET_PRINT_PAGESIZE', 1, (int)round($w * 10), (int)round($h * 10), ''],
- ['SET_PRINT_MODE', 'POS_BASEON_PAPER', 1],
- ['SET_PRINT_COPIES', $copies],
- ['SET_PRINT_STYLE', 'FontName', '微软雅黑'],
- ['SET_PRINT_STYLE', 'FontSize', 10],
- ['SET_PRINT_STYLE', 'Bold', 0],
- ['SET_PRINT_STYLE', 'Italic', 0],
- ];
- $last = count($pages) - 1;
- foreach ($pages as $index => $item) {
- $texts = [];
- if (!empty($item['print_items']) && is_array($item['print_items'])) {
- $texts = $item['print_items'];
- } elseif (!empty($item['items']) && is_array($item['items'])) {
- $texts = $item['items'];
- }
- if ($texts) {
- foreach ($texts as $row) {
- if (($row['type'] ?? '') === 'qrcode') {
- $img = trim((string)($row['image'] ?? ''));
- $qrTop = (string)($row['top'] ?? '0mm');
- $qrLeft = (string)($row['left'] ?? '0mm');
- $qrWidth = (string)($row['width'] ?? '24mm');
- $qrHeight = (string)($row['height'] ?? '24mm');
- if ($img !== '') {
- $commands[] = [
- 'ADD_PRINT_IMAGE',
- $qrTop,
- $qrLeft,
- $qrWidth,
- $qrHeight,
- $img,
- ];
- $commands[] = ['SET_PRINT_STYLEA', 0, 'Stretch', 1];
- } else {
- $commands[] = [
- 'ADD_PRINT_BARCODE',
- $qrTop,
- $qrLeft,
- $qrWidth,
- $qrHeight,
- 'QRCode',
- (string)($row['text'] ?? ''),
- ];
- $commands[] = ['SET_PRINT_STYLEA', 0, 'QRCodeErrorLevel', 'L'];
- $commands[] = ['SET_PRINT_STYLEA', 0, 'DataCharset', 'UTF-8'];
- }
- continue;
- }
- $commands[] = [
- 'ADD_PRINT_TEXT',
- $row['top'],
- $row['left'],
- $row['width'],
- $row['height'],
- (string)($row['text'] ?? ''),
- ];
- $commands[] = ['SET_PRINT_STYLEA', 0, 'FontName', $row['font'] ?? '微软雅黑'];
- $commands[] = ['SET_PRINT_STYLEA', 0, 'FontSize', (int)($row['size'] ?? 10)];
- $commands[] = ['SET_PRINT_STYLEA', 0, 'Bold', !empty($row['bold']) ? 1 : 0];
- $commands[] = ['SET_PRINT_STYLEA', 0, 'Italic', 0];
- $commands[] = ['SET_PRINT_STYLEA', 0, 'Alignment', (int)($row['align'] ?? 1)];
- }
- } else {
- $html = self::stripCoverImage((string)($item['html'] ?? ''));
- $commands[] = ['ADD_PRINT_HTM', 0, 0, $wMm, $hMm, self::wrapHtml($html, $w, $h)];
- }
- if ($index < $last) {
- $commands[] = ['NEWPAGE'];
- }
- }
- $commands[] = [$mode === 'print' ? 'PRINT' : 'PREVIEW'];
- return $commands;
- }
- /**
- * 纸张毫米。始终带实数宽高,避免落到打印机默认标签纸。
- * @param array $page
- * @return array{w:float,h:float,paper_size:string}
- */
- protected static function paperMm(array $page)
- {
- $resolved = PaperSize::resolve(
- (string)($page['paper_size'] ?? ''),
- (float)($page['w'] ?? 0),
- (float)($page['h'] ?? 0)
- );
- return [
- 'w' => (float)$resolved['w'],
- 'h' => (float)$resolved['h'],
- 'paper_size' => (string)$resolved['name'],
- ];
- }
- /**
- * @param string $html
- * @return string
- */
- protected static function stripCoverImage($html)
- {
- $html = preg_replace('/<img[^>]*alt="流程单底图"[^>]*>/i', '', (string)$html);
- return is_string($html) ? $html : '';
- }
- /**
- * @param string $html
- * @param float $w
- * @param float $h
- * @return string
- */
- protected static function wrapHtml($html, $w, $h)
- {
- return '<!DOCTYPE html><html><head><meta charset="utf-8">'
- . '<style>html,body{margin:0;padding:0;width:' . $w . 'mm;height:' . $h . 'mm;overflow:hidden;background:transparent;font-family:\'Microsoft YaHei\',\'微软雅黑\',sans-serif;font-size:13px;font-weight:normal;}</style>'
- . '</head><body>' . $html . '</body></html>';
- }
- }
|