]> acesimba.cloud Git - StationBuilder.git/commitdiff
feat: 站点级样式生成范本增强(逐面板外观/配色板/标题模板修复,注入Cube名称)
authorwang.yu <wang.yu@advantech.com>
Mon, 17 Aug 2026 06:23:47 +0000 (14:23 +0800)
committerwang.yu <wang.yu@advantech.com>
Mon, 17 Aug 2026 06:23:47 +0000 (14:23 +0800)
db-sidecar.mjs

index ac8fbc50ed12497edec27b1667e6e85a521e3a41..f2edf90d47d81dbcb09f962aeff5b0b65b6c7af9 100644 (file)
@@ -79,13 +79,13 @@ Top-level structure (MUST include exactly these keys):
   "category_id": null,
   "name": "<dashboard name>",
   "id": <positive integer>,
-  "grid": { "theme": "light", "bgColor": "rgb(237,246,251)", "panelBgColor": "#F5F5F5", "panel": { "bgColor": "#FFFFFF", "titleColor": "#323232" }, "borderColor": "#C8C8C8", "borderWidth": 1, "borderRadius": 4, "gap": 6, "pageType": "custom", "pageWidth": 1920, "pageHeight": 1080, "showBorder": true, "bgType": "color", "bgImgType": "cover", "linearGradientParam1": "default", "linearGradientParam2": "#008cd633", "linearGradientParam3": "#008cd6", "linearGradientParamDeg": 45, "radialGradientParam1": "default", "radialGradientParam2": "#008cd633", "radialGradientParam3": "#008cd6" },
+  "grid": { "theme": "light", "bgColor": "rgb(237,246,251)", "panelBgColor": "#F5F5F5", "panel": { "bgColor": "#FFFFFF", "titleColor": "#323232" }, "borderColor": "#C8C8C8", "borderWidth": 1, "borderRadius": 4, "gap": 6, "pageType": "custom", "pageWidth": 1920, "pageHeight": 1080, "showBorder": true, "bgType": "color", "bgImgType": "cover", "linearGradientParam1": "default", "linearGradientParam2": "#5B7C9933", "linearGradientParam3": "#5B7C99", "linearGradientParamDeg": 45, "radialGradientParam1": "default", "radialGradientParam2": "#5B7C9933", "radialGradientParam3": "#5B7C99" },
   "panels": [...]
 }
 
 Layout rules:
 - 24-column grid, page 1920x1080.
-- First panel MUST be type "Title" at gridPos {w:24,h:2,x:0,y:0}, custom.title.label = dashboard name, fontSize 40, fontWeight "bold".
+- First panel MUST be type "Title" at gridPos {w:24,h:2,x:0,y:0}. Hide the default panel title bar: set style.title.show=false. Use custom.title.label = dashboard name, and make custom.title.style (fontSize, fontWeight, letterSpacing, textShadow, color, align) exactly match the Title panel style provided in the 视觉风格要求 section if present.
 - All other panels must have y >= 2.
 - Do NOT place panels that overlap or exceed x+w > 24.
 - Fill roughly 25 rows total (2 title + KPI rows + chart rows).
@@ -118,9 +118,9 @@ KPIIndicator panel specifics:
 - data.targets[0].dataType = "sum"
 - custom can include icon, thresholds, compare.
 
-Charts: include proper chartConfig, series, axes, colors from palette #0062CC,#00B900,#FF9300,#EBC147,#D73C74,#8048C8,#6D84C9,#34A0D5.
+Charts: include proper chartConfig, series, axes, colors. If a 视觉风格要求 section provides a 推荐配色板, use THAT palette first; otherwise use default #0062CC,#00B900,#FF9300,#EBC147,#D73C74,#8048C8,#6D84C9,#34A0D5.
 
-Theme: use light theme (grid.theme="light", bgColor rgb(237,246,251), panelBgColor #F5F5F5, panel.bgColor #FFFFFF, titleColor #323232, borderColor #C8C8C8). Do not mix darkBlue with light background.
+Theme: If a 视觉风格要求 section is provided below, follow IT exactly (its grid colors/borders/gradients take precedence) and ignore the default example colors in the grid above. Otherwise use the default light theme: grid.theme="light", bgColor rgb(237,246,251), panelBgColor #F5F5F5, panel.bgColor #FFFFFF, titleColor #323232, borderColor #C8C8C8. Do not mix darkBlue with light background.
 
 Output ONLY the raw JSON object. No markdown code fences, no explanation.
 `;
@@ -431,12 +431,13 @@ function buildCubePrompt(site, cube) {
 - 页面内容/要求: ${cube.content || "(未填写,请按总览型页面设计)"}
 
 请针对以上页面,生成对应的 Cube 仪表盘 JSON 文件(只输出该页面)。模拟数据需与上方站点资产配置保持一致;若属于同一站点的多个 Cube 页面,请保持各页面之间的数据关系合理。该 JSON 必须符合 dashboard-json-generator Skill 中 Cube 工具的规则,结构如下:
-${DASHBOARD_SPEC}${buildStylePrompt(site)}`;
+${DASHBOARD_SPEC}${buildStylePrompt(site, cube.name)}`;
 }
 
 // 站点级视觉风格范本:从所选样式库方案中提取可写入 grid 的主题参数(背景大图以占位描述代替,避免上下文膨胀),
 // 并在 buildCubePrompt 中复用,保证生成 / 重新生成 / 查看提示词 等路径都带同一段范本。
-function buildStylePrompt(site) {
+// cubeName 可选:提供时标题直接填好页面名称,避免模型漏填。
+function buildStylePrompt(site, cubeName) {
   if (!site || !site.style_id) return "";
   const row = db.prepare("SELECT id,name,json_text FROM page_styles WHERE id=?").get(site.style_id);
   if (!row) return "";
@@ -471,13 +472,69 @@ function buildStylePrompt(site) {
     pageType: g.pageType,
   };
   Object.keys(theme).forEach(k => theme[k] === undefined && delete theme[k]);
+
+  // 逐面板外观令牌:样式的"皮肤"主要来自这里(标题色 / 边框色 / 面板底色 / 组件类型)
+  const panels = (style.panels || []).map(p => ({
+    type: p.type,
+    titleColor: p.style?.title?.color,
+    borderColor: p.style?.border?.color,
+    bg: p.style?.background?.color,
+  }));
+
+  // 标题面板模板:必须复刻原样式第一个 Title panel。custom.title 已填好(label 为页面名称),
+  // 请原样写入;同时 style.title.show=false 且 style.title.color 也设为浅色,避免回退到默认灰色标题栏。
+  const first = style.panels?.[0];
+  const ct = first?.custom?.title;
+  const titleTemplate = first && first.type === "Title" && ct ? {
+    "style.title.show": false,
+    "style.title.color": ct.style?.color,
+    "custom.title": {
+      label: (cubeName && String(cubeName).trim()) ? cubeName : "<当前页面名称>",
+      style: ct.style,
+      align: ct.align,
+    },
+  } : null;
+
+  // 推荐配色板:扫描样式真实用到的颜色,供图表 / 文字 / 强调复用(替代默认色板)
+  const palette = extractColorPalette(style);
+
   return `
 
-视觉风格要求(站点级,适用本站点全部 Cube 页面):
-所选页面样式库方案:「${row.name}」。请严格参考以下视觉主题参数生成 dashboard JSON(仅输出符合该风格的外观,结构仍遵循上方 Cube 规范):
+【视觉风格要求 · 最高优先级】所选页面样式库方案:「${row.name}」。
+下方所有视觉参数必须原样写入生成 JSON 的 grid 与各 panel 的 style 中,并忽略上方 DASHBOARD_SPEC 里的默认 Theme 示例色(如 #008cd6)。结构仍遵循上方 Cube 规范。
+
+1) grid 级主题(背景 / 边框 / 圆角,请原样保留这些字段值;背景渐变由 bgType + bgColor + linearGradientParam(Deg,1,2,3) + radialGradientParam(1,2,3) 共同决定,请勿自行改成纯色):
 ${JSON.stringify(theme, null, 2)}
 
-说明:bgImg 为原样式的背景底图(已省略其 base64 内容),请保持与该图一致的明暗、色调与渐变质感;其余参数均为可直接写入 grid 的样式值。`;
+2) 标题面板模板(第一个 panel,type=Title,必须原样写入以下 custom.title(label 已填好,无需再改),并设 style.title.show=false。标题可见文字颜色以 custom.title.style.color 为准,请勿使用默认灰色标题栏):
+${JSON.stringify(titleTemplate, null, 2)}
+
+3) 逐面板外观参考(生成每种 type 的面板时,尽量采用本列表中同 type 面板的 titleColor / borderColor / bg;组件类型构成以本列表为准):
+${JSON.stringify(panels.slice(1), null, 2)}
+
+4) 推荐配色板(图表 series、文字、强调色优先使用以下颜色,而非默认色板):
+${JSON.stringify(palette)}
+
+说明:bgImg 为原样式的背景底图(已省略其 base64 内容),请保持与该图一致的明暗、色调与渐变质感;其余参数均为可直接写入 grid / panel.style 的样式值。`;
+}
+
+// 从样式 JSON 中扫描真实使用的颜色,提取为推荐配色板(跳过 base64 等大字段)。
+function extractColorPalette(style) {
+  const colors = new Map();
+  const scan = (o) => {
+    if (typeof o === "string") {
+      if (o.length > 5000) return; // 跳过 bgImg 等超大字段
+      const r = /#([0-9a-fA-F]{3,8})\b|rgba?\([^)]*\)/g;
+      let m;
+      while ((m = r.exec(o))) {
+        const c = m[0].toLowerCase();
+        colors.set(c, (colors.get(c) || 0) + 1);
+      }
+    } else if (Array.isArray(o)) o.forEach(scan);
+    else if (o && typeof o === "object") Object.values(o).forEach(scan);
+  };
+  scan(style);
+  return [...colors.entries()].sort((a, b) => b[1] - a[1]).slice(0, 12).map(e => e[0]);
 }
 async function generateCubeJson(site, cube, attempt = 1, previousErrors = "") {
   const promptBase = buildCubePrompt(site, cube);