feat: md样式优化
All checks were successful
缓存序列化结构检查 / cache-schema-check (push) Has been skipped

This commit is contained in:
2026-07-14 16:22:05 +08:00
parent cab3fea666
commit 6e06cbf5b5
3 changed files with 62 additions and 30 deletions

View File

@@ -130,9 +130,9 @@ public class ReportBuilder {
Set<String> oldHighlight = SkeletonAnnotator.pathsForOldSkeleton(kc.getFieldDetails());
Set<String> newHighlight = SkeletonAnnotator.pathsForNewSkeleton(kc.getFieldDetails());
String oldRendered = oldJson.isEmpty()
? "" : "" + SkeletonAnnotator.annotateForWecom(oldJson, oldHighlight) + "";
? "" : "" + SkeletonAnnotator.annotateOldForWecom(oldJson, oldHighlight) + "";
String newRendered = newJson.isEmpty()
? "" : "" + SkeletonAnnotator.annotateForWecom(newJson, newHighlight) + "";
? "" : "" + SkeletonAnnotator.annotateNewForWecom(newJson, newHighlight) + "";
if (oldJson.isEmpty() && !newJson.isEmpty()) {
sb.append(" > **value 新增为:** ").append(newRendered).append("\n\n");
} else if (!oldJson.isEmpty() && newJson.isEmpty()) {

View File

@@ -10,16 +10,20 @@ import java.util.List;
import java.util.Set;
/**
* 在骨架 JSON 中为改动字段加企微 warning 标注(仅改动片段染色,其余明文)。
* 在骨架 JSON 中为改动字段加企微颜色标注(仅改动片段染色,其余明文)。
* <ul>
* <li>删除字段 → 标在旧骨架</li>
* <li>新增字段 / 新增包装层 → 标在新骨架</li>
* <li>路径迁移 → 旧路径标旧骨架、新路径标新骨架</li>
* <li>删除字段 → 旧骨架,橙色 {@code warning}</li>
* <li>新增字段 / 新增包装层 → 新骨架,绿色 {@code info}</li>
* <li>路径迁移 → 旧路径橙、新路径绿</li>
* </ul>
*/
final class SkeletonAnnotator {
private static final String FONT_OPEN = "<font color=\"warning\">";
/** 企微橙:删除 / 旧侧变更 */
static final String COLOR_REMOVE = "warning";
/** 企微绿:新增 / 新侧变更 */
static final String COLOR_ADD = "info";
private static final String FONT_CLOSE = "</font>";
private SkeletonAnnotator() {
@@ -66,14 +70,32 @@ final class SkeletonAnnotator {
}
/**
* 标注改动字段:其余正文保持普通文本(避免整段包反引号导致企微整段变红)。
* 改动片段格式:{@code <font color="warning">"field":value</font>}
* 标注旧骨架改动字段(删除 → 橙色)。
*/
static String annotateOldForWecom(String json, Set<String> highlightPaths) {
return annotateForWecom(json, highlightPaths, COLOR_REMOVE);
}
/**
* 标注新骨架改动字段(新增 → 绿色)。
*/
static String annotateNewForWecom(String json, Set<String> highlightPaths) {
return annotateForWecom(json, highlightPaths, COLOR_ADD);
}
/**
* 仅标注改动字段:其余正文保持普通文本。
* 改动片段格式:{@code <font color="warning|info">"field":value</font>}
*/
static String annotateForWecom(String json, Set<String> highlightPaths) {
return annotateForWecom(json, highlightPaths, COLOR_REMOVE);
}
static String annotateForWecom(String json, Set<String> highlightPaths, String color) {
if (json == null || json.isEmpty()) {
return "";
}
return annotate(json, highlightPaths);
return annotate(json, highlightPaths, color);
}
/** @deprecated 使用 {@link #annotateForWecom},勿再整段包代码块 */
@@ -82,18 +104,27 @@ final class SkeletonAnnotator {
}
static String annotate(String json, Set<String> highlightPaths) {
return annotate(json, highlightPaths, COLOR_REMOVE);
}
static String annotate(String json, Set<String> highlightPaths, String color) {
if (json == null || json.isEmpty() || highlightPaths == null || highlightPaths.isEmpty()) {
return json == null ? "" : json;
}
String fontOpen = fontOpen(color);
String result = json;
List<String> sorted = new ArrayList<>(highlightPaths);
sorted.sort(Comparator.comparingInt(String::length).reversed());
for (String path : sorted) {
result = wrapOnePath(result, path);
result = wrapOnePath(result, path, fontOpen);
}
return result;
}
private static String fontOpen(String color) {
String c = color == null || color.isEmpty() ? COLOR_REMOVE : color;
return "<font color=\"" + c + "\">";
}
private static void addIfPresent(Set<String> paths, String path) {
if (path != null && !path.trim().isEmpty()) {
@@ -101,11 +132,10 @@ final class SkeletonAnnotator {
}
}
private static String wrapOnePath(String json, String path) {
private static String wrapOnePath(String json, String path, String fontOpen) {
if (path == null || path.isEmpty()) {
return json;
}
// 已标注过则跳过(避免重复)
String key = lastSegment(path);
if (key.isEmpty()) {
return json;
@@ -114,8 +144,7 @@ final class SkeletonAnnotator {
if (propStart < 0) {
return json;
}
// 已在 font 内则跳过
int fontBefore = json.lastIndexOf(FONT_OPEN, propStart);
int fontBefore = json.lastIndexOf("<font color=\"", propStart);
int fontCloseBefore = json.lastIndexOf(FONT_CLOSE, propStart);
if (fontBefore > fontCloseBefore) {
return json;
@@ -127,11 +156,11 @@ final class SkeletonAnnotator {
return json;
}
String frag = json.substring(propStart, valueEnd);
if (frag.contains(FONT_OPEN)) {
if (frag.contains("<font color=\"")) {
return json;
}
return json.substring(0, propStart)
+ FONT_OPEN + frag + FONT_CLOSE
+ fontOpen + frag + FONT_CLOSE
+ json.substring(valueEnd);
}
@@ -169,7 +198,6 @@ final class SkeletonAnnotator {
return -1;
}
} else if (c == '[') {
// 数组:进入第一个元素对象
int arrEnd = findMatchingBracket(json, valueStart);
int elemObj = json.indexOf('{', valueStart);
if (elemObj < 0 || elemObj >= arrEnd) {
@@ -193,7 +221,6 @@ final class SkeletonAnnotator {
if (idx < 0 || idx >= to) {
return -1;
}
// 粗略校验:前面应是 { 或 ,
int p = idx - 1;
while (p >= from && Character.isWhitespace(json.charAt(p))) {
p--;