feat(client): 标签模板编辑器头部加「打印」按钮(重置与保存之间)
打印当前预览:复用出签弹窗 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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bupi8Kdqkfx2N5acFsHTx5
This commit is contained in:
@@ -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<void> _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<void> _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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Vendored
+2
-2
File diff suppressed because one or more lines are too long
@@ -117,6 +117,7 @@
|
||||
<h1>标签模板编辑器</h1><span class="sub">左侧实时预览 · 右侧属性面板</span>
|
||||
<div class="actions">
|
||||
<div class="btn ghost" onclick="resetTpl()"><svg viewBox="0 0 24 24"><use href="#i-refresh"/></svg>重置</div>
|
||||
<div class="btn ghost" onclick="printTpl()"><svg viewBox="0 0 24 24"><use href="#i-printer"/></svg>打印</div>
|
||||
<div class="btn primary" onclick="toast('模板已保存 ✓')"><svg viewBox="0 0 24 24"><use href="#i-check"/></svg>保存</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -377,6 +378,8 @@
|
||||
document.getElementById('label').style.transform = 'scale('+z+')';
|
||||
}
|
||||
function resetTpl(){ toast('已重置为默认版式'); }
|
||||
/* 打印当前预览:真实端弹出签打印弹窗(选打印机/份数),此处仅提示 */
|
||||
function printTpl(){ toast('打开打印预览…'); }
|
||||
/* 模板:下拉选=正在编辑;「设默认」=打印实际使用的那个(二者可不同) */
|
||||
const TPLS = ['默认版式', '大字号简约', '双语抬头'];
|
||||
let tplEditing = '默认版式'; // 正在编辑
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user