瀏覽代碼

coloring: logo/logo文字/slogon/内容列表图 支持用户上传替换

- manifest.json 新增 4 个可选素材定义
- configGenerator.ts 优先使用用户上传素材,否则回退模板默认
- storageService scanAssetFiles 扩展检测新素材类型
guoziyun 3 周之前
父節點
當前提交
7987a42dcf

+ 17 - 5
platform/server/src/services/configGenerator.ts

@@ -36,15 +36,27 @@ export function generateAdConfig(input: GenerateInput): string {
     lines.push(`import specialUrl from "/assets/user/${files.special}?url";`);
   }
 
-  // == 模板自有素材 ==
+  // == 模板自有素材(用户上传则优先使用)==
   lines.push("");
   lines.push("// ==== 模板自有素材 ====");
   lines.push(`import numberFontUrl from "/assets/fonts/numbers_roboto_500.png?url";`);
   lines.push(`import fingerUrl from "/assets/img/finger.png?url";`);
-  lines.push(`import logoUrl from "/assets/img/logo.png?url";`);
-  lines.push(`import logoTxtUrl from "/assets/img/logo-txt.png?url";`);
-  lines.push(`import coloringPagesUrl from "/assets/img/coloring-pages.png?url";`);
-  lines.push(`import slogonUrl from "/assets/img/slogon.png?url";`);
+
+  // 可替换素材:优先用用户上传的,否则用模板默认
+  const replaceableAssets = [
+    { key: "logo", file: "logo.png", var: "logoUrl", defaultPath: "/assets/img/logo.png" },
+    { key: "logoTxt", file: "logo-txt.png", var: "logoTxtUrl", defaultPath: "/assets/img/logo-txt.png" },
+    { key: "slogon", file: "slogon.png", var: "slogonUrl", defaultPath: "/assets/img/slogon.png" },
+    { key: "coloringPages", file: "coloring-pages.png", var: "coloringPagesUrl", defaultPath: "/assets/img/coloring-pages.png" },
+  ];
+  for (const a of replaceableAssets) {
+    const userFile = (files as unknown as Record<string, string | null>)[a.key];
+    if (userFile) {
+      lines.push(`import ${a.var} from "/assets/user/${userFile}?url";`);
+    } else {
+      lines.push(`import ${a.var} from "${a.defaultPath}?url";`);
+    }
+  }
 
   // == adAssets 导出 ==
   lines.push("");

+ 21 - 4
platform/server/src/services/storageService.ts

@@ -82,10 +82,23 @@ export function getBuildOutputDir(
   return dir;
 }
 
-export function scanAssetFiles(
-  assetsDir: string
-): { config: boolean; page: boolean; map: boolean; special: string | null } {
-  const result = { config: false, page: false, map: false, special: null as string | null };
+export interface ScannedAssets {
+  config: boolean;
+  page: boolean;
+  map: boolean;
+  special: string | null;
+  logo: string | null;
+  logoTxt: string | null;
+  slogon: string | null;
+  coloringPages: string | null;
+}
+
+export function scanAssetFiles(assetsDir: string): ScannedAssets {
+  const result: ScannedAssets = {
+    config: false, page: false, map: false,
+    special: null, logo: null, logoTxt: null,
+    slogon: null, coloringPages: null,
+  };
 
   if (!fs.existsSync(assetsDir)) return result;
 
@@ -97,6 +110,10 @@ export function scanAssetFiles(
       result.page = true;
     else if (lower === "map.png") result.map = true;
     else if (lower.startsWith("special.")) result.special = file;
+    else if (lower === "logo.png") result.logo = file;
+    else if (lower === "logo-txt.png") result.logoTxt = file;
+    else if (lower === "slogon.png") result.slogon = file;
+    else if (lower === "coloring-pages.png") result.coloringPages = file;
   }
 
   return result;

+ 5 - 1
templates/coloring/manifest.json

@@ -11,7 +11,11 @@
       { "key": "map",     "file": "map.png",     "label": "映射图",       "accept": ".png" }
     ],
     "optional": [
-      { "key": "special", "file": "special.jpeg", "label": "着色参考图(推荐,无则自动生成)", "accept": ".jpeg,.jpg,.png" }
+      { "key": "special", "file": "special.jpeg", "label": "着色参考图(推荐,无则自动生成)", "accept": ".jpeg,.jpg,.png" },
+      { "key": "logo", "file": "logo.png", "label": "Logo 图标(默认模板自带)", "accept": ".png" },
+      { "key": "logoTxt", "file": "logo-txt.png", "label": "Logo 文字图(默认模板自带)", "accept": ".png" },
+      { "key": "slogon", "file": "slogon.png", "label": "Slogon 宣传语图(默认模板自带)", "accept": ".png" },
+      { "key": "coloringPages", "file": "coloring-pages.png", "label": "内容列表图(默认模板自带)", "accept": ".png" }
     ]
   },
   "theme": {

+ 3 - 3
templates/coloring/src/filler/index.ts

@@ -54,9 +54,9 @@ async function init() {
 
   // CTA 光晕颜色 → RGB 分量(CSS 变量供 rgba() 使用)
   const glowHex = adTheme.ctaGlowColor || "#ff5f1f";
-  root.style.setProperty("--cta-glow-r", parseInt(glowHex.slice(1, 3), 16));
-  root.style.setProperty("--cta-glow-g", parseInt(glowHex.slice(3, 5), 16));
-  root.style.setProperty("--cta-glow-b", parseInt(glowHex.slice(5, 7), 16));
+  root.style.setProperty("--cta-glow-r", String(parseInt(glowHex.slice(1, 3), 16)));
+  root.style.setProperty("--cta-glow-g", String(parseInt(glowHex.slice(3, 5), 16)));
+  root.style.setProperty("--cta-glow-b", String(parseInt(glowHex.slice(5, 7), 16)));
 
   // 直接应用 CTA 文案和样式
   const ctaBtn = document.getElementById("cta-btn");