chore: release client-v1.1.12
Deploy Client / build-client-web (push) Successful in 5m19s
Deploy Client / build-macos (push) Successful in 7m36s
Deploy Client / build-android (push) Successful in 6m18s
Deploy Client / build-ios (push) Successful in 6m2s
Deploy Client / build-windows (push) Successful in 5m27s
Deploy Client / release-deploy-client (push) Successful in 10m49s

价签标签两栏布局改版 + 生产日期修复 + 模板预览接真实渲染 +
Windows/macOS 应用内更新进度条修复。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bupi8Kdqkfx2N5acFsHTx5
This commit is contained in:
wangjia
2026-08-27 17:52:03 +08:00
parent eb7b0edc96
commit c3a127485f
11 changed files with 492 additions and 246 deletions
@@ -9,8 +9,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
import 'package:qr_flutter/qr_flutter.dart';
import '../../core/auth/auth_state.dart';
import '../../core/utils/print_util.dart' show LabelData;
import '../../widgets/label_preview_dialog.dart';
import '../../core/responsive/responsive.dart';
import '../../core/theme/app_dims.g.dart';
import '../../core/theme/context_tokens.dart';
@@ -932,8 +935,9 @@ class _DeviceManagementScreenState
// ── 区块 C:打印模板(静态两卡,仅桌面;拍板移动端无打印)────
Widget _tplGrid(dynamic t) {
final cards = [
_tplCard(
t, LucideIcons.tag, '标签模板 · 商品价签', '40×30mm · 品名 / 规格 / 条码 / 零售价'),
_tplCard(t, LucideIcons.tag, '标签模板 · 商品价签',
'40×20mm · 店名 / 品名 / 编号 / 度数规格 / 生产日期 / 二维码 + 底部整幅一维条码',
onPreview: _previewLabelTemplate),
_tplCard(t, LucideIcons.receiptText, '小票模板 · 出库单据',
'58mm 热敏 · 抬头 / 明细 / 合计 / 经手人'),
];
@@ -944,7 +948,8 @@ class _DeviceManagementScreenState
]);
}
Widget _tplCard(dynamic t, IconData icon, String name, String desc) {
Widget _tplCard(dynamic t, IconData icon, String name, String desc,
{VoidCallback? onPreview}) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
@@ -980,7 +985,8 @@ class _DeviceManagementScreenState
const SizedBox(height: 8),
Row(children: [
DsButton('预览',
small: true, onPressed: () => _snack('模板预览即将上线')),
small: true,
onPressed: onPreview ?? () => _snack('模板预览即将上线')),
const SizedBox(width: 8),
DsButton('编辑',
small: true, onPressed: () => _snack('模板编辑即将上线')),
@@ -992,6 +998,35 @@ class _DeviceManagementScreenState
);
}
// ── 标签模板预览:用示例数据 + 本地二维码,走真实标签渲染 ────
Future<void> _previewLabelTemplate() async {
final shop = ref.read(shopInfoProvider).valueOrNull;
// 本地生成一张示例二维码(与真实标签同一渲染路径,仅数据是示例)。
final painter = QrPainter(
data: 'https://jiu.51yanmei.com/p/sample',
version: QrVersions.auto,
gapless: true,
);
final img = await painter.toImageData(240);
if (!mounted || img == null) return;
final label = LabelData(
qrBytes: img.buffer.asUint8List(),
name: '示例·贵州茅台',
code: 'P0001',
series: '飞天',
spec: '500ml',
productionDate: '2024-05-18',
shopName: shop?.name ?? '示例酒行',
shopAddress: shop?.address ?? '',
shopPhone: shop?.phone ?? '',
);
if (!mounted) return;
showAppDialog(
context: context,
builder: (_) => LabelPreviewDialog(labels: [label]),
);
}
// ── 外设增删(店级 custom_fields.peripherals)───────────────
Future<void> _savePeripherals(List<Peripheral> items) async {
final shop = await ref.read(shopInfoProvider.future);
@@ -987,6 +987,7 @@ class _QRCodeDialogState extends ConsumerState<_QRCodeDialog> {
code: p.code,
spec: p.spec,
series: p.series,
productionDate: p.productionDate,
shopName: shopInfo?.name ?? '',
shopAddress: shopInfo?.address ?? '',
shopPhone: shopInfo?.phone ?? '',