7b3a0ecdeb
设备管理「价签·编辑」进入独立编辑器屏 /devices/label-template: - 左实时预览走真实 renderLabelPreview 渲染路径(示例数据, debounce 重渲) - 右属性面板:多模板管理(编辑对象/打印默认分离)、显示字段手风琴、 高级区域位置、打印参数 - 存 shop.custom_fields.label_templates + label_template_active(零后端改) - Option A:同物理行两字段(编号+型号 / 版本+日期)共用字号·加粗·对齐, 各自独立开关;仅品名支持自动字号;字体不做(热敏单色) - 打印联动:LabelPreviewDialog 改 ConsumerStatefulWidget, 未显式传模板时 自动取本店 active 模板→所有打印入口(商品详情/出入库列表/编辑抽屉)一致生效 守护: - 默认输出逐像素零变化由 label_render_golden_test 守(改内置默认常量才触发) - 存储读写由 label_template_storage_test 单测守(纯内存, 不触真实库) - 编辑器挂载由 label_template_editor_smoke_test 守 - 本屏不入自动 fidelity/golden 闸(左预览 Picture.toImage 需 runAsync, pumpAndSettle 骨架驱动不了), 原因+替代守法记入 CONTRACT 块4 design-first:原型 label-template-editor.html 去字体选择器、加 Option A 配对 镜像, 与真实屏同提交。真机热敏打印坐标/条码可扫须用户在打印机验收。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bupi8Kdqkfx2N5acFsHTx5
52 lines
1.9 KiB
Dart
52 lines
1.9 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:jiu_client/core/utils/label_template.dart';
|
|
|
|
/// 锁死模板存储读写(走 shop.custom_fields,零后端改动)与 JSON 往返,
|
|
/// 不触真实库——纯内存对象校验。
|
|
void main() {
|
|
group('LabelTemplate 存储 helpers', () {
|
|
test('custom_fields 无模板时回退内置默认', () {
|
|
final list = readLabelTemplates(<String, dynamic>{});
|
|
expect(list, hasLength(1));
|
|
expect(list.first.id, 'builtin-default');
|
|
});
|
|
|
|
test('activeLabelTemplate 按 id 命中,缺失回退第一项', () {
|
|
final a = LabelTemplate.builtinDefault();
|
|
final b = a.copyWith(id: 'tpl-2', name: '大字号');
|
|
final cf = <String, dynamic>{
|
|
'label_templates': [a.toJson(), b.toJson()],
|
|
'label_template_active': 'tpl-2',
|
|
};
|
|
expect(activeLabelTemplate(cf).id, 'tpl-2');
|
|
|
|
cf['label_template_active'] = 'nope';
|
|
expect(activeLabelTemplate(cf).id, 'builtin-default');
|
|
});
|
|
|
|
test('toJson → fromJson 往返保真(几何/开关/样式)', () {
|
|
final src = LabelTemplate.builtinDefault();
|
|
src.textStack.subLines[0].fontSize = 16;
|
|
src.textStack.subLines[0].bold = true;
|
|
src.qr.size = 120;
|
|
src.print.direction = 0;
|
|
final back = LabelTemplate.fromJson(src.toJson());
|
|
expect(back.textStack.subLines[0].fontSize, 16);
|
|
expect(back.textStack.subLines[0].bold, true);
|
|
expect(back.qr.size, 120);
|
|
expect(back.print.direction, 0);
|
|
});
|
|
|
|
test('存 → 读回列表保持顺序与命名', () {
|
|
final a = LabelTemplate.builtinDefault();
|
|
final b = a.copyWith(id: 'tpl-2', name: '双语抬头');
|
|
final cf = <String, dynamic>{
|
|
'label_templates': [a.toJson(), b.toJson()],
|
|
};
|
|
final list = readLabelTemplates(cf);
|
|
expect(list.map((t) => t.id), ['builtin-default', 'tpl-2']);
|
|
expect(list[1].name, '双语抬头');
|
|
});
|
|
});
|
|
}
|