From 195b4d22e7f43672190968a84fe8df29168c3b73 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Sun, 30 Aug 2026 12:08:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(client):=20=E6=A0=87=E7=AD=BE=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E7=BC=96=E8=BE=91=E5=99=A8=E5=A4=B4=E9=83=A8=E5=8A=A0?= =?UTF-8?q?=E3=80=8C=E6=89=93=E5=8D=B0=E3=80=8D=E6=8C=89=E9=92=AE(?= =?UTF-8?q?=E9=87=8D=E7=BD=AE=E4=B8=8E=E4=BF=9D=E5=AD=98=E4=B9=8B=E9=97=B4?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 打印当前预览:复用出签弹窗 LabelPreviewDialog(选打印机/份数),传入正在 编辑的模板 _t 与示例数据。预览/打印共用 _sampleLabel() 抽出示例 LabelData。 L1 图标单源:新登记 i-printer(Lucide printer)到原型 icons.js + 官网 icons.njk 两端(check-l1-sync 同集要求),原型头部 use #i-printer。 design-first:原型 label-template-editor.html 同步加「打印」按钮 + printTpl() 占位,与真实屏同提交。smoke test 增头部「打印」按钮断言。 Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Bupi8Kdqkfx2N5acFsHTx5 --- .../devices/label_template_editor_screen.dart | 28 +++++++++++++++++-- .../label_template_editor_smoke_test.dart | 2 ++ design/prototype/screens/icons.js | 4 +-- .../screens/label-template-editor.html | 3 ++ web/_includes/icons.njk | 2 +- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/client/lib/screens/devices/label_template_editor_screen.dart b/client/lib/screens/devices/label_template_editor_screen.dart index b9320ad..1848882 100644 --- a/client/lib/screens/devices/label_template_editor_screen.dart +++ b/client/lib/screens/devices/label_template_editor_screen.dart @@ -18,6 +18,7 @@ import '../../providers/shop_provider.dart'; import '../../widgets/ds/ds_atoms.dart'; import '../../widgets/ds/ds_switch.dart'; import '../../widgets/ds/ds_toast.dart'; +import '../../widgets/label_preview_dialog.dart'; /// 标签价签模板编辑器(原型 `design/prototype/screens/label-template-editor.html`)。 /// @@ -177,12 +178,13 @@ class _LabelTemplateEditorScreenState Timer(const Duration(milliseconds: 150), _renderPreview); } - Future _renderPreview() async { + /// 预览/打印共用的示例数据(QR 已在 bootstrap 生成)。 + LabelData? _sampleLabel() { final qr = _qrBytes; - if (qr == null) return; + if (qr == null) return null; final shopName = ref.read(shopInfoProvider).valueOrNull?.name ?? '鼎晟酒行'; - final sample = LabelData( + return LabelData( qrBytes: qr, name: '贵州茅台酒', code: 'P1001', @@ -193,10 +195,28 @@ class _LabelTemplateEditorScreenState remark: '整箱现货', shopName: shopName, ); + } + + Future _renderPreview() async { + final sample = _sampleLabel(); + if (sample == null) return; final png = await renderLabelPreview(sample, template: _t); if (mounted && png != null) setState(() => _previewPng = png); } + /// 打印当前预览:复用出签弹窗(选打印机/份数),传入正在编辑的模板 [_t]。 + void _print() { + final sample = _sampleLabel(); + if (sample == null) { + _toast('预览尚未就绪,请稍候', err: true); + return; + } + showDialog( + context: context, + builder: (_) => LabelPreviewDialog(labels: [sample], template: _t), + ); + } + void _mutate(VoidCallback fn) { setState(fn); _scheduleRender(); @@ -513,6 +533,8 @@ class _LabelTemplateEditorScreenState const Spacer(), DsButton('重置', icon: LucideIcons.refreshCw, onPressed: _reset), const SizedBox(width: 10), + DsButton('打印', icon: LucideIcons.printer, onPressed: _print), + const SizedBox(width: 10), DsButton(_saving ? '保存中…' : '保存', icon: LucideIcons.check, variant: DsBtnVariant.primary, diff --git a/client/test/label_template_editor_smoke_test.dart b/client/test/label_template_editor_smoke_test.dart index 5c15576..3028058 100644 --- a/client/test/label_template_editor_smoke_test.dart +++ b/client/test/label_template_editor_smoke_test.dart @@ -38,6 +38,8 @@ void main() { expect(find.text('标签模板编辑器'), findsOneWidget); expect(find.text('显示字段'), findsOneWidget); expect(find.text('打印参数'), findsOneWidget); + // 头部「打印」按钮(打印当前预览) + expect(find.text('打印'), findsOneWidget); expect(find.text('模板'), findsWidgets); // 字段行齐全(品名 + 二维码等) expect(find.text('品名'), findsOneWidget); diff --git a/design/prototype/screens/icons.js b/design/prototype/screens/icons.js index ee379bd..c579cd9 100644 --- a/design/prototype/screens/icons.js +++ b/design/prototype/screens/icons.js @@ -1,8 +1,8 @@ // 图标 sprite —— 单一真源(Lucide 官方图标,ISC 许可) // 所有屏用 引用;改此处一个 symbol,全局生效。 -// 共 107 个:99 个源自 lucide-static,i-info/i-alert 为点改实心圆的清晰变体,,另有平台品牌图标 i-apple / i-android(simple-icons,填充式,path 自带 fill 覆盖描边样式)与 i-tablet-smartphone(lucide)。新增图标先在此登记 symbol,再用 use 引用。 +// 共 108 个:100 个源自 lucide-static(含 i-printer),i-info/i-alert 为点改实心圆的清晰变体,,另有平台品牌图标 i-apple / i-android(simple-icons,填充式,path 自带 fill 覆盖描边样式)与 i-tablet-smartphone(lucide)。新增图标先在此登记 symbol,再用 use 引用。 (function(){ - var SPRITE=''; + var SPRITE=''; function inject(){ if(document.getElementById('ym-icon-sprite'))return; var d=document.createElement('div'); d.id='ym-icon-sprite'; d.style.cssText='position:absolute;width:0;height:0'; d.innerHTML=SPRITE; document.body.insertBefore(d,document.body.firstChild); } if(document.readyState!=='loading')inject(); else document.addEventListener('DOMContentLoaded',inject); // ---- 徽章图标化(2026-07-04 拍板:全系统圆点→代表图标)---- diff --git a/design/prototype/screens/label-template-editor.html b/design/prototype/screens/label-template-editor.html index 092842f..300645d 100644 --- a/design/prototype/screens/label-template-editor.html +++ b/design/prototype/screens/label-template-editor.html @@ -117,6 +117,7 @@

标签模板编辑器

左侧实时预览 · 右侧属性面板
重置
+
打印
保存
@@ -377,6 +378,8 @@ document.getElementById('label').style.transform = 'scale('+z+')'; } function resetTpl(){ toast('已重置为默认版式'); } + /* 打印当前预览:真实端弹出签打印弹窗(选打印机/份数),此处仅提示 */ + function printTpl(){ toast('打开打印预览…'); } /* 模板:下拉选=正在编辑;「设默认」=打印实际使用的那个(二者可不同) */ const TPLS = ['默认版式', '大字号简约', '双语抬头']; let tplEditing = '默认版式'; // 正在编辑 diff --git a/web/_includes/icons.njk b/web/_includes/icons.njk index 0b07cb9..25c1b81 100644 --- a/web/_includes/icons.njk +++ b/web/_includes/icons.njk @@ -1,3 +1,3 @@ {# 图标雪碧图 — 单一真相源:自 design/prototype/screens/icons.js 提取(lucide 同源), 页面用 引用;修改图标请先改原型再同步 #} - +