|
|
@@ -1,18 +1,31 @@
|
|
|
package shop.alien.store.service.impl;
|
|
|
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
import java.time.LocalDateTime;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
|
|
|
public class PrintTemplate {
|
|
|
|
|
|
/**
|
|
|
- * 生成订单小票
|
|
|
- * @param orderNo 订单号
|
|
|
- * @param items 商品列表
|
|
|
- * @param total 总金额
|
|
|
- * @return 打印文本
|
|
|
+ * 兼容旧的静态示例生成方法(保留)
|
|
|
*/
|
|
|
public static String buildOrder(String orderNo, String items, String total) {
|
|
|
- return "========== 测试门店 ==========\n" +
|
|
|
+ return " 结账单 \n" +
|
|
|
+ " 测试门店 \n" +
|
|
|
+ "============================\n" +
|
|
|
+ "桌号:" + 1 + "\n" +
|
|
|
+ "单号:" + 2 + "\n" +
|
|
|
+ "人数:" + 4 + "\n" +
|
|
|
+ "就餐时间:" + 2026 + "-04-06 10:00" + "\n" +
|
|
|
+ "姓名:" + "张大大" + "\n" +
|
|
|
+ "电话:" + 1800000000 + "\n" +
|
|
|
+ "结账时间:" + 2026 + "-04-06 13:00" + "\n" +
|
|
|
+ "收银员:" + "路通" + "\n" +
|
|
|
"订单号:" + orderNo + "\n" +
|
|
|
"时间:" + LocalDateTime.now() + "\n" +
|
|
|
"----------------------------\n" +
|
|
|
@@ -20,7 +33,153 @@ public class PrintTemplate {
|
|
|
"----------------------------\n" +
|
|
|
"合计:" + total + " 元\n" +
|
|
|
"支付方式:微信支付\n" +
|
|
|
+ "打印时间:"+ 2026 + "-04-06 13:00" + "\n" +
|
|
|
"----------------------------\n" +
|
|
|
"欢迎再次光临\n\n\n";
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 基于 store_receipt_template_config 的 JSON 配置动态渲染小票
|
|
|
+ * @param templateConfigJson 模板配置JSON(来自表 store_receipt_template_config.template_config_json)
|
|
|
+ * @param context 业务数据上下文(key 需与模板字段 key 对应;品项请放在 key = \"items\" 的 List<Map> 中)
|
|
|
+ * @return 打印文本
|
|
|
+ */
|
|
|
+ public static String buildFromConfig(String templateConfigJson, Map<String, Object> context) {
|
|
|
+ if (templateConfigJson == null || templateConfigJson.trim().isEmpty()) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ JSONObject root = JSON.parseObject(templateConfigJson);
|
|
|
+ if (root == null) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ JSONArray sections = root.getJSONArray("sections");
|
|
|
+ if (sections == null) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 辅助:横线与安全取值
|
|
|
+ String line = "----------------------------\n";
|
|
|
+ String thickLine = "============================\n";
|
|
|
+
|
|
|
+ for (int i = 0; i < sections.size(); i++) {
|
|
|
+ JSONObject section = sections.getJSONObject(i);
|
|
|
+ if (section == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ JSONArray fields = section.getJSONArray("fields");
|
|
|
+ if (fields == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // section 之间用粗分割
|
|
|
+ if (i == 0) {
|
|
|
+ // 首段上方打印抬头分割线(可选)
|
|
|
+ sb.append(thickLine);
|
|
|
+ } else {
|
|
|
+ sb.append(line);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int j = 0; j < fields.size(); j++) {
|
|
|
+ JSONObject field = fields.getJSONObject(j);
|
|
|
+ if (field == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ boolean visible = field.getBooleanValue("visible");
|
|
|
+ if (!visible) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String key = field.getString("key");
|
|
|
+ String titleName = nvl(field.getString("titleName"));
|
|
|
+ boolean divider = field.getBooleanValue("divider");
|
|
|
+ int blankLines = field.getIntValue("blankLines");
|
|
|
+
|
|
|
+ if ("item".equals(key)) {
|
|
|
+ // 品项区:打印表头 + 列表
|
|
|
+ JSONArray children = field.getJSONArray("children");
|
|
|
+ boolean showUnitPrice = childVisible(children, "unitPrice");
|
|
|
+ boolean showQuantity = childVisible(children, "quantity");
|
|
|
+ boolean showSubtotal = childVisible(children, "subtotal");
|
|
|
+
|
|
|
+ // 表头
|
|
|
+ sb.append(titleName).append("\n");
|
|
|
+ // 列标题(简洁处理)
|
|
|
+ List<String> headers = new ArrayList<>();
|
|
|
+ headers.add("品名");
|
|
|
+ if (showUnitPrice) headers.add("单价");
|
|
|
+ if (showQuantity) headers.add("数量");
|
|
|
+ if (showSubtotal) headers.add("小计");
|
|
|
+ sb.append(String.join(" ", headers)).append("\n");
|
|
|
+
|
|
|
+ // 数据
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ List<Map<String, Object>> items = (List<Map<String, Object>>) context.getOrDefault("items", new ArrayList<>());
|
|
|
+ for (Map<String, Object> item : items) {
|
|
|
+ String name = str(item.get("name"));
|
|
|
+ List<String> cols = new ArrayList<>();
|
|
|
+ cols.add(name);
|
|
|
+ if (showUnitPrice) cols.add(str(item.get("unitPrice")));
|
|
|
+ if (showQuantity) cols.add("x" + str(item.get("quantity")));
|
|
|
+ if (showSubtotal) cols.add(str(item.get("subtotal")));
|
|
|
+ sb.append(String.join(" ", cols)).append("\n");
|
|
|
+ }
|
|
|
+ } else if ("orderPrice".equals(key) || "paymentDiscount".equals(key) || "paymentInfo".equals(key)) {
|
|
|
+ // 具有子项的分组型文本
|
|
|
+ JSONArray children = field.getJSONArray("children");
|
|
|
+ if (children != null && !children.isEmpty()) {
|
|
|
+ sb.append(titleName).append("\n");
|
|
|
+ for (int k = 0; k < children.size(); k++) {
|
|
|
+ JSONObject child = children.getJSONObject(k);
|
|
|
+ if (child == null || !child.getBooleanValue("visible")) continue;
|
|
|
+ String subKey = nvl(child.getString("key"));
|
|
|
+ String subTitle = nvl(child.getString("titleName"));
|
|
|
+ if ("divider".equals(subKey)) {
|
|
|
+ sb.append(line);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Object val = context.get(subKey);
|
|
|
+ if (val != null && !"".equals(String.valueOf(val).trim())) {
|
|
|
+ sb.append(subTitle).append(":").append(val).append("\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 普通文本字段
|
|
|
+ Object value = context.get(key);
|
|
|
+ if (value != null && !"".equals(String.valueOf(value).trim())) {
|
|
|
+ sb.append(titleName).append(":").append(value).append("\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (divider) {
|
|
|
+ sb.append(line);
|
|
|
+ }
|
|
|
+ for (int b = 0; b < blankLines; b++) {
|
|
|
+ sb.append("\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 末尾多留空行,部分打印机需要
|
|
|
+ sb.append("\n\n");
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static boolean childVisible(JSONArray children, String key) {
|
|
|
+ if (children == null) return false;
|
|
|
+ for (int i = 0; i < children.size(); i++) {
|
|
|
+ JSONObject c = children.getJSONObject(i);
|
|
|
+ if (c == null) continue;
|
|
|
+ if (key.equals(c.getString("key"))) {
|
|
|
+ return c.getBooleanValue("visible");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String nvl(String s) {
|
|
|
+ return s == null ? "" : s;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String str(Object v) {
|
|
|
+ return v == null ? "" : String.valueOf(v);
|
|
|
+ }
|
|
|
}
|