diff --git a/CHANGELOG.md b/CHANGELOG.md index 9325b2c..ce9a7c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.41] - 2026-06-15 + +### 改进 +- 标签打印布局优化:编号字体与度数/日期统一大小,内容整体下移并填满标签底部,店名适当放大 +- 标签度数与规格之间加宽间距,两个字段更易区分 + ## [1.0.40] - 2026-06-15 ### 新功能 diff --git a/client/lib/core/utils/print_util_stub.dart b/client/lib/core/utils/print_util_stub.dart index 6c0aa23..b41436e 100644 --- a/client/lib/core/utils/print_util_stub.dart +++ b/client/lib/core/utils/print_util_stub.dart @@ -224,26 +224,38 @@ Future _renderLabelBitmap({ // 扫码溯源:居中于二维码正下方 _drawText(canvas, '扫码溯源', qrLeft, qrTop + qrS + 2, 14, qrS, center: true); - // 左侧文字(无字段名标签):按行等比分配高度铺满,字号自适应填充 + // 左侧文字:固定字号 + 自适应行间距(与二维码上下对齐,行距均匀分配剩余空间) const lx = 22.0; const textMaxW = qrLeft - lx - 6; // 164 + + // 字号固定:只有商品名按宽度自适应,其余行均固定,杜绝自动放大 + const double kShopSize = 17.0; // 酒行名,粗体 + const double kSmallSize = 13.0; // 编号 / 度数 / 日期,统一小字 + // 商品名:仅按宽度适配,上限 26px,下限 14px + final double nameSize = _fitFont(name, textMaxW, 1000, true, 26.0).clamp(14.0, 26.0); + final codeText = code.isNotEmpty ? '编号:$code' : ''; final rows = <(String, double, bool)>[ - (shop, 0.9, true), - (name, 1.5, true), - if (codeText.isNotEmpty) (codeText, 1.0, false), - if (degSpec.isNotEmpty) (degSpec, 1.05, false), - if (date.isNotEmpty) (date, 1.0, false), + if (shop.isNotEmpty) (shop, kShopSize, true), + if (name.isNotEmpty) (name, nameSize, true), + if (codeText.isNotEmpty) (codeText, kSmallSize, false), + if (degSpec.isNotEmpty) (degSpec, kSmallSize, false), + if (date.isNotEmpty) (date, kSmallSize, false), ]; - const topY = 4.0, botY = 156.0; - final totalWeight = rows.fold(0, (a, r) => a + r.$2); - double yy = topY; + + // 文字区域:整体略低于二维码顶部,底部延伸至扫码溯源文字下方 + const double kTextTop = 16.0; // 比二维码顶部(8)低一些,整体下移 + const double kTextBot = 150.0; // 延伸至底部,减少留白 + const double kLineH = 1.35; // 行高倍数(字号 × 行高 = 该行占用高度) + final double totalTextH = rows.fold(0.0, (s, r) => s + r.$2 * kLineH); + final int n = rows.length; + final double rawGap = n > 0 ? (kTextBot - kTextTop - totalTextH) / (n + 1) : 4.0; + final double gap = rawGap < 1.5 ? 1.5 : rawGap; + + double yy = kTextTop + gap; for (final r in rows) { - final rowH = (botY - topY) * r.$2 / totalWeight; - final fs = _fitFont(r.$1, textMaxW, rowH * 0.84, r.$3, 30); - final ty = yy + (rowH - fs * 1.25) / 2; - _drawText(canvas, r.$1, lx, ty < yy ? yy : ty, fs, textMaxW, bold: r.$3); - yy += rowH; + _drawText(canvas, r.$1, lx, yy, r.$2, textMaxW, bold: r.$3); + yy += r.$2 * kLineH + gap; } return recorder.endRecording().toImage(w, h); @@ -327,7 +339,7 @@ Future printProductLabelImpl({ final specVal = (spec ?? '').isNotEmpty ? spec! : ''; final seriesVal = (series ?? '').isNotEmpty ? series! : ''; // 度数(系列) + 规格 同一行 - final degSpecVal = [seriesVal, specVal].where((s) => s.isNotEmpty).join(' '); + final degSpecVal = [seriesVal, specVal].where((s) => s.isNotEmpty).join(' '); final dateVal = (productionDate ?? '').isNotEmpty ? (productionDate!.length > 10 ? productionDate.substring(0, 10) : productionDate) : '—'; @@ -484,7 +496,7 @@ Future printProductLabelImpl({ Future renderLabelPreviewImpl(LabelData label) async { final specVal = (label.spec ?? '').isNotEmpty ? label.spec! : ''; final seriesVal = (label.series ?? '').isNotEmpty ? label.series! : ''; - final degSpecVal = [seriesVal, specVal].where((s) => s.isNotEmpty).join(' '); + final degSpecVal = [seriesVal, specVal].where((s) => s.isNotEmpty).join(' '); final dateVal = (label.productionDate ?? '').isNotEmpty ? (label.productionDate!.length > 10 ? label.productionDate!.substring(0, 10)