Pārlūkot izejas kodu

feat: storeUrl 改造为可配置参数,移除 userAgent 动态检测

- 删除 storeUrls.ts(硬编码 URL + navigator.userAgent 检测)
- AdPlatformAdapter 接口新增 setStoreUrl(url) 方法
- 各 adapter 内部缓存 _storeUrl,openStore() 直接使用
- manifest.json 新增 storeUrl 主题属性(type: url)
- ThemeEditor 新增 url 类型渲染:输入框 + Google Play / App Store 预设按钮
- index.ts 初始化时串接 adTheme.storeUrl → adapter.setStoreUrl()
- configGenerator 生成的 adTheme 包含 storeUrl 字段
- 防御性设计:adapter 默认 _storeUrl 为 Google Play 链接
guoziyun 2 nedēļas atpakaļ
vecāks
revīzija
7bb9a81e9e

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
platform/client/dist/assets/index-BLSVrq0u.css


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
platform/client/dist/assets/index-CATpT7G9.css


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
platform/client/dist/assets/index-DH95Jq3D.js


+ 2 - 2
platform/client/dist/index.html

@@ -4,8 +4,8 @@
     <meta charset="UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>Playable Ads Platform</title>
-    <script type="module" crossorigin src="/ads/assets/index-C2oFMHOx.js"></script>
-    <link rel="stylesheet" crossorigin href="/ads/assets/index-CATpT7G9.css">
+    <script type="module" crossorigin src="/ads/assets/index-DH95Jq3D.js"></script>
+    <link rel="stylesheet" crossorigin href="/ads/assets/index-BLSVrq0u.css">
   </head>
   <body>
     <div id="root"></div>

+ 26 - 0
platform/client/src/components/ThemeEditor.module.css

@@ -54,6 +54,32 @@
   color: var(--color-text-secondary);
 }
 
+.urlRow {
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+}
+
+.presetBtns {
+  display: flex;
+  gap: 8px;
+}
+
+.presetBtn {
+  padding: 4px 10px;
+  border: 1px solid var(--color-border);
+  border-radius: 4px;
+  background: var(--color-bg-secondary, #f5f5f5);
+  font-size: 12px;
+  color: var(--color-text-secondary);
+  cursor: pointer;
+}
+
+.presetBtn:hover {
+  border-color: var(--color-primary);
+  color: var(--color-primary);
+}
+
 .saveBtn {
   padding: 8px 16px;
   border: 1px solid var(--color-primary);

+ 39 - 0
platform/client/src/components/ThemeEditor.tsx

@@ -78,6 +78,45 @@ export default function ThemeEditor({ creativeId, theme, themeProps, onUpdated }
               }
               className={styles.textInput}
             />
+          ) : prop.type === "url" ? (
+            <div className={styles.urlRow}>
+              <input
+                type="url"
+                value={values[prop.key] || prop.default}
+                onChange={(e) =>
+                  setValues((v) => ({ ...v, [prop.key]: e.target.value }))
+                }
+                className={styles.textInput}
+                placeholder={prop.default}
+              />
+              <div className={styles.presetBtns}>
+                <button
+                  type="button"
+                  className={styles.presetBtn}
+                  onClick={() =>
+                    setValues((v) => ({
+                      ...v,
+                      [prop.key]:
+                        "https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number",
+                    }))
+                  }
+                >
+                  Google Play
+                </button>
+                <button
+                  type="button"
+                  className={styles.presetBtn}
+                  onClick={() =>
+                    setValues((v) => ({
+                      ...v,
+                      [prop.key]: "https://apps.apple.com/app/id1575480118",
+                    }))
+                  }
+                >
+                  App Store
+                </button>
+              </div>
+            </div>
           ) : prop.type === "css-gradient" ? (
             <GradientEditor
               value={values[prop.key] || prop.default}

+ 1 - 1
platform/client/src/types/index.ts

@@ -40,7 +40,7 @@ export interface AssetDef {
 export interface ThemeProp {
   key: string;
   label: string;
-  type: "css-gradient" | "text" | "color";
+  type: "css-gradient" | "text" | "color" | "url";
   default: string;
   maxLength?: number;
 }

+ 1 - 1
platform/server/dist/services/configGenerator.d.ts.map

@@ -1 +1 @@
-{"version":3,"file":"configGenerator.d.ts","sourceRoot":"","sources":["../../src/services/configGenerator.ts"],"names":[],"mappings":"AAMA,UAAU,aAAa;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAqE7D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAkBhF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAO5C"}
+{"version":3,"file":"configGenerator.d.ts","sourceRoot":"","sources":["../../src/services/configGenerator.ts"],"names":[],"mappings":"AAMA,UAAU,aAAa;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAsE7D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAkBhF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAO5C"}

+ 1 - 0
platform/server/dist/services/configGenerator.js

@@ -76,6 +76,7 @@ function generateAdConfig(input) {
     lines.push(`  ctaGradient: ${JSON.stringify(input.theme.ctaGradient || "linear-gradient(135deg, #ff5f1f 0%, #ffb300 100%)")},`);
     lines.push(`  ctaGlowColor: ${JSON.stringify(input.theme.ctaGlowColor || "#ff5f1f")},`);
     lines.push(`  ctaText: ${JSON.stringify(input.theme.ctaText || "PLAY NOW")},`);
+    lines.push(`  storeUrl: ${JSON.stringify(input.theme.storeUrl || "https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number")},`);
     lines.push(`  frameColor: ${JSON.stringify(input.theme.frameColor || "#edce9b")},`);
     lines.push(`  frameLineWidth: ${JSON.stringify(Number(input.theme.frameLineWidth) || 16)},`);
     lines.push("};");

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
platform/server/dist/services/configGenerator.js.map


+ 1 - 0
platform/server/src/services/configGenerator.ts

@@ -82,6 +82,7 @@ export function generateAdConfig(input: GenerateInput): string {
   lines.push(`  ctaGradient: ${JSON.stringify(input.theme.ctaGradient || "linear-gradient(135deg, #ff5f1f 0%, #ffb300 100%)")},`);
   lines.push(`  ctaGlowColor: ${JSON.stringify(input.theme.ctaGlowColor || "#ff5f1f")},`);
   lines.push(`  ctaText: ${JSON.stringify(input.theme.ctaText || "PLAY NOW")},`);
+  lines.push(`  storeUrl: ${JSON.stringify(input.theme.storeUrl || "https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number")},`);
   lines.push(`  frameColor: ${JSON.stringify(input.theme.frameColor || "#edce9b")},`);
   lines.push(`  frameLineWidth: ${JSON.stringify(Number(input.theme.frameLineWidth) || 16)},`);
   lines.push("};");

+ 1 - 0
templates/coloring/manifest.json

@@ -24,6 +24,7 @@
       { "key": "ctaGradient",   "label": "CTA 按钮渐变",  "type": "css-gradient", "default": "linear-gradient(135deg, #ff5f1f 0%, #ffb300 100%)" },
       { "key": "ctaGlowColor",  "label": "CTA 光晕颜色",  "type": "color",        "default": "#ff5f1f" },
       { "key": "ctaText",       "label": "CTA 按钮文案",  "type": "text",         "default": "PLAY NOW", "maxLength": 30 },
+      { "key": "storeUrl",      "label": "应用商店链接",   "type": "url",          "default": "https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number" },
       { "key": "frameColor",    "label": "完成相框颜色",   "type": "color",        "default": "#edce9b" },
       { "key": "frameLineWidth","label": "完成相框线宽",   "type": "number",       "default": 16, "min": 4, "max": 40 }
     ]

+ 2 - 0
templates/coloring/src/filler/ad-config.ts

@@ -41,6 +41,8 @@ export const adTheme = {
   ctaGradient: "linear-gradient(135deg, #ff5f1f 0%, #ffb300 100%)",
   ctaGlowColor: "#ff5f1f",
   ctaText: "PLAY NOW",
+  storeUrl:
+    "https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number",
   frameColor: "#edce9b",
   frameLineWidth: 16,
 };

+ 9 - 2
templates/coloring/src/filler/ad-platform/adapters/applovin.ts

@@ -1,10 +1,13 @@
 import { AdPlatformAdapter } from "../types";
 import { openWithMraidOrWindow, setupMraidCustomClose } from "./helpers";
-import { getStoreUrl } from "./storeUrls";
+
+const DEFAULT_STORE_URL =
+  "https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number";
 
 export function createApplovinAdapter(): AdPlatformAdapter {
   let started = false;
   let ended = false;
+  let _storeUrl = DEFAULT_STORE_URL;
 
   return {
     platform: "applovin",
@@ -30,7 +33,11 @@ export function createApplovinAdapter(): AdPlatformAdapter {
         window.ExitApi.exit();
         return;
       }
-      openWithMraidOrWindow(getStoreUrl());
+      openWithMraidOrWindow(_storeUrl);
+    },
+
+    setStoreUrl(url: string) {
+      _storeUrl = url;
     },
 
     shouldUseCustomLoading() {

+ 9 - 2
templates/coloring/src/filler/ad-platform/adapters/google.ts

@@ -1,9 +1,12 @@
 import { AdPlatformAdapter } from "../types";
-import { getStoreUrl } from "./storeUrls";
+
+const DEFAULT_STORE_URL =
+  "https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number";
 
 export function createGoogleAdapter(): AdPlatformAdapter {
   let started = false;
   let ended = false;
+  let _storeUrl = DEFAULT_STORE_URL;
 
   return {
     platform: "google",
@@ -27,10 +30,14 @@ export function createGoogleAdapter(): AdPlatformAdapter {
         window.ExitApi.exit();
       } else {
         // 非 Google 广告环境下的 fallback(如本地调试)
-        window.open(getStoreUrl(), "_blank");
+        window.open(_storeUrl, "_blank");
       }
     },
 
+    setStoreUrl(url: string) {
+      _storeUrl = url;
+    },
+
     shouldUseCustomLoading() {
       return true;
     },

+ 5 - 0
templates/coloring/src/filler/ad-platform/adapters/playturbo.ts

@@ -4,6 +4,7 @@ export function createPlayturboAdapter(): AdPlatformAdapter {
   let ready = false;
   let started = false;
   let ended = false;
+  let _storeUrl = "";
 
   const adapter: AdPlatformAdapter = {
     platform: "playturbo",
@@ -34,6 +35,10 @@ export function createPlayturboAdapter(): AdPlatformAdapter {
       window.install?.();
     },
 
+    setStoreUrl(url: string) {
+      _storeUrl = url;
+    },
+
     shouldUseCustomLoading() {
       return false;
     },

+ 0 - 16
templates/coloring/src/filler/ad-platform/adapters/storeUrls.ts

@@ -1,16 +0,0 @@
-/** App Store / Google Play 落地页链接,按需替换 */
-// 正式上线时换回自己的 app:
-const STORE_URL_IOS = "https://apps.apple.com/app/id1575480118";
-const STORE_URL_ANDROID =
-  "https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number";
-
-// // 测试期间使用 PBN,避免产生无效转化
-// const STORE_URL_IOS =
-//   "https://apps.apple.com/gb/app/paint-by-number-coloring-games/id1420058690";
-// const STORE_URL_ANDROID =
-//   "https://play.google.com/store/apps/details?id=com.oakever.paintbynumber";
-
-export function getStoreUrl(): string {
-  if (/android/i.test(navigator.userAgent)) return STORE_URL_ANDROID;
-  return STORE_URL_IOS;
-}

+ 9 - 2
templates/coloring/src/filler/ad-platform/adapters/unity.ts

@@ -1,11 +1,14 @@
 import { AdPlatformAdapter } from "../types";
 import { openWithMraidOrWindow, setupMraidCustomClose } from "./helpers";
-import { getStoreUrl } from "./storeUrls";
+
+const DEFAULT_STORE_URL =
+  "https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number";
 
 export function createUnityAdapter(): AdPlatformAdapter {
   let ready = false;
   let started = false;
   let ended = false;
+  let _storeUrl = DEFAULT_STORE_URL;
 
   function notifyReady() {
     if (ready) return;
@@ -40,7 +43,11 @@ export function createUnityAdapter(): AdPlatformAdapter {
     },
 
     openStore() {
-      openWithMraidOrWindow(getStoreUrl());
+      openWithMraidOrWindow(_storeUrl);
+    },
+
+    setStoreUrl(url: string) {
+      _storeUrl = url;
     },
 
     shouldUseCustomLoading() {

+ 1 - 0
templates/coloring/src/filler/ad-platform/types.ts

@@ -7,6 +7,7 @@ export interface AdPlatformAdapter {
   onGameStart(): void;
   onGameEnd(): void;
   openStore(): void;
+  setStoreUrl(url: string): void;
   shouldUseCustomLoading(): boolean;
   shouldShowAdBadge(): boolean;
 }

+ 1 - 0
templates/coloring/src/filler/index.ts

@@ -31,6 +31,7 @@ import { adAssets, adTheme } from "#ad-config";
 window.addEventListener("load", () => {
   document.body.dataset.adPlatform = adPlatform.platform;
   adPlatform.init();
+  adPlatform.setStoreUrl(adTheme.storeUrl);
   initCta(adPlatform);
   init();
 });

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels