|
|
@@ -8,7 +8,9 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
import java.util.Date;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
|
|
|
@Service
|
|
|
public class ProductSkuService {
|
|
|
@@ -26,6 +28,7 @@ public class ProductSkuService {
|
|
|
|
|
|
@Transactional
|
|
|
public ProductSku create(ProductSku sku) {
|
|
|
+ sku.setSpecs(normalizeSpecsToJson(sku.getSpecs()));
|
|
|
sku.setCreateTime(new Date());
|
|
|
sku.setUpdateTime(new Date());
|
|
|
if (sku.getEnabled() == null) {
|
|
|
@@ -37,6 +40,9 @@ public class ProductSkuService {
|
|
|
|
|
|
@Transactional
|
|
|
public void update(ProductSku sku) {
|
|
|
+ if (sku.getSpecs() != null) {
|
|
|
+ sku.setSpecs(normalizeSpecsToJson(sku.getSpecs()));
|
|
|
+ }
|
|
|
sku.setUpdateTime(new Date());
|
|
|
skuMapper.updateById(sku);
|
|
|
}
|
|
|
@@ -69,4 +75,55 @@ public class ProductSkuService {
|
|
|
}
|
|
|
return sku.getStock() >= quantity;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将 specs 规格字符串规范化为合法 JSON 对象。
|
|
|
+ *
|
|
|
+ * product_skus.specs 列为 MySQL JSON NOT NULL,只接受合法 JSON。
|
|
|
+ * 前端 ProductSkuEditor 允许用户输入 "颜色:红色;尺码:M" 这种格式,
|
|
|
+ * 直接插入会被 MySQL 拒绝(Invalid JSON text)。
|
|
|
+ * 此方法将 "k1:v1;k2:v2" 格式转为 {"k1":"v1","k2":"v2"};
|
|
|
+ * 如果已经是合法 JSON 字符串则原样返回。
|
|
|
+ */
|
|
|
+ static String normalizeSpecsToJson(String specs) {
|
|
|
+ if (specs == null || specs.trim().isEmpty()) {
|
|
|
+ return "{}";
|
|
|
+ }
|
|
|
+ String trimmed = specs.trim();
|
|
|
+ // 已是合法 JSON 对象/数组,直接返回
|
|
|
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
|
+ return trimmed;
|
|
|
+ }
|
|
|
+ // 将 k1:v1;k2:v2 格式转为 JSON 对象
|
|
|
+ Map<String, String> map = new LinkedHashMap<>();
|
|
|
+ String[] pairs = trimmed.split("[;;]");
|
|
|
+ for (String pair : pairs) {
|
|
|
+ pair = pair.trim();
|
|
|
+ if (pair.isEmpty()) continue;
|
|
|
+ String[] kv = pair.split("[::]", 2);
|
|
|
+ if (kv.length == 2) {
|
|
|
+ map.put(kv[0].trim(), kv[1].trim());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (map.isEmpty()) {
|
|
|
+ return "{}";
|
|
|
+ }
|
|
|
+ // 手动构建 JSON 字符串(避免引入 Jackson 依赖)
|
|
|
+ StringBuilder sb = new StringBuilder("{");
|
|
|
+ boolean first = true;
|
|
|
+ for (Map.Entry<String, String> entry : map.entrySet()) {
|
|
|
+ if (!first) sb.append(",");
|
|
|
+ first = false;
|
|
|
+ sb.append("\"").append(escapeJson(entry.getKey())).append("\":");
|
|
|
+ sb.append("\"").append(escapeJson(entry.getValue())).append("\"");
|
|
|
+ }
|
|
|
+ sb.append("}");
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String escapeJson(String s) {
|
|
|
+ if (s == null) return "";
|
|
|
+ return s.replace("\\", "\\\\").replace("\"", "\\\"")
|
|
|
+ .replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t");
|
|
|
+ }
|
|
|
}
|