Parcourir la source

add share.ejs

guoziyun il y a 11 mois
Parent
commit
f4f67cadfe
6 fichiers modifiés avec 380 ajouts et 183 suppressions
  1. 1 0
      app.js
  2. 0 0
      dist/.well-known/assetlinks_debug.json
  3. 1 1
      routes/v2/detail.js
  4. 54 0
      routes/v2/share.js
  5. 189 182
      views/v2/detail.ejs
  6. 135 0
      views/v2/share.ejs

+ 1 - 0
app.js

@@ -105,6 +105,7 @@ app.use('/', require('./routes/v2/index'));  // 首页和具体分类合集页
 app.use('/coloring-page', require('./routes/v2/detail'))  // 详情页
 app.use('/coloring-pages', require('./routes/v2/coloring-pages')) // 所有精选合集页
 app.use('/coloring-page-gallery', require('./routes/v2/gallery')) // 图库页
+app.use('/share', require('./routes/v2/share')) // deeplink share专属页面
 
 
 

+ 0 - 0
dist/.well-known/assetlinks_product.json → dist/.well-known/assetlinks_debug.json


+ 1 - 1
routes/v2/detail.js

@@ -23,7 +23,7 @@ router.get('/:id', function (req, res, next) {
 
     let cacheKey = `${CACHE_PREFIX}_detail_${id}`;
     let htmlData = await redis.getAsync(cacheKey);
-    // htmlData = null;
+    htmlData = null;
     if (!htmlData) {
       // 详情
       let doc = await models.Art

+ 54 - 0
routes/v2/share.js

@@ -0,0 +1,54 @@
+var express = require('express');
+var router = express.Router();
+const utils = require('../../libs/utils');
+const config = require('../../config/app');
+
+// deeplink share 专属页路由
+router.get('/:id', function (req, res, next) {
+  (async function () {
+    let id = req.params.id;
+    utils.validators.validateId(id);
+
+    let host = config.cdnHost ?? config.resHost;
+
+    let imageUrl = `${host}/thumbs/coloring-page/work/480/${id}.webp`;
+    let applink = `https://art.pcoloring.com${req.originalUrl}`;
+    let downlink = `https://pcoloring.com/anc/`;
+
+
+    const userAgent = req.headers['user-agent'];
+    console.log('User-Agent:', userAgent);
+    if (userAgent) {
+      const ua = userAgent.toLowerCase();
+      if (ua.includes('iphone') || ua.includes('ipad') || ua.includes('ipod')) {
+        downlink = 'itms-apps://itunes.apple.com/app/id1575480118?action=write-review';
+      } else if (ua.includes('android')) {
+        downlink = 'https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number&pcampaignid=web_share';
+      }
+    }
+
+
+
+    let data = {
+      id,
+      imageUrl,
+      applink,
+      downlink,
+    }
+
+    // 渲染EJS模板到内存中
+    res.render('v2/share', data, async (err, html) => {
+      if (err) {
+        // 如果渲染出错,调用next()传递错误
+        return next(err);
+      }
+      res.send(html);
+    });
+
+
+  })().catch(next);
+
+});
+
+
+module.exports = router;

+ 189 - 182
views/v2/detail.ejs

@@ -11,8 +11,22 @@
   <meta name="description" content="<%= description %>">
   <meta property="og:title" content="<%= title %>">
   <meta property="og:description" content="<%= description %>">
-
-  <meta name="apple-itunes-app" content="app-id=1575480118, app-argument=https://art.pcoloring.com/play/<%= detail._id %>">
+  <meta property="og:image" content="<%= detail.poster %>">
+  <meta property="og:type" content="website">
+
+  <!-- MARK: Universal Link / Android App Link 的核心配置 -->
+  <!-- 这些 meta 标签的值应该是完整的 HTTPS 链接,Facebook 会识别并尝试拉起 App -->
+  <meta property="og:url" content="https://art.pcoloring.com/coloring-page/<%= detail._id %>" />
+  <!-- **Universal Link 路径** -->
+  <meta property="al:ios:url" content="https://art.pcoloring.com/coloring-page/<%= detail._id %>" />
+  <!-- **Universal Link 路径** -->
+  <meta property="al:ios:app_store_id" content="1575480118" /> <!-- **iOS App Store ID** -->
+  <meta property="al:ios:app_name" content="Art Number Coloring Book" /> <!-- **iOS 应用名称** -->
+
+  <meta property="al:android:package" content="com.pcoloring.art.puzzle.color.by.number" /> <!-- **Android 包名** -->
+  <meta property="al:android:url" content="https://art.pcoloring.com/coloring-page/<%= detail._id %>" />
+  <!-- ** Universal Link 路径** -->
+  <meta property="al:android:app_name" content="Art Number Coloring Book" /> <!-- **Android 应用名称** -->
 
   <link rel="stylesheet" href="/stylesheets/v2/styles.css">
   <style>
@@ -249,7 +263,46 @@
         },
         "datePublished": "<%= detail.publishTime %>"
     }
-    </script>
+  </script>
+
+  <script>
+    const baseUniversalLink = 'https://art.pcoloring.com';
+    const currentPageLink = baseUniversalLink + window.location.pathname + window.location.search;
+    const appDeeplink = baseUniversalLink + window.location.pathname.replace('coloring-page', 'share') + window.location.search;
+
+    const linkDownloadCommon = 'https://pcoloring.com/anc/'; // 通用下载页
+    const linkDownloadAppStore = 'itms-apps://itunes.apple.com/app/id1575480118?action=write-review'; // ios app下载链接
+    const linkDownloadPlayMarket = 'https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number&pcampaignid=web_share';  // android app 下载链接
+    const ua = window.navigator.userAgent.toLowerCase();
+
+    // 动态更新 Open Graph 和 App Links 的 URL 为 Universal Link
+    document.querySelector('meta[property="og:url"]').content = currentPageLink;
+    document.querySelector('meta[property="al:ios:url"]').content = currentPageLink;
+    document.querySelector('meta[property="al:android:url"]').content = currentPageLink;
+
+    function functionDownload() {
+      if (ua.search("iphone") > -1 || ua.search("ipad") > -1 || ua.search("ipod") > -1) {
+        // 对于 iOS 设备,尝试直接打开 Universal Link
+        // 如果 Universal Link 配置正确,浏览器会尝试拉起 App
+        // 否则会降级到网页或 App Store
+        window.location.href = appDeeplink; // 尝试 Universal Link
+        // 如果 Universal Link 失败,可以设置一个延时跳转到 App Store
+        setTimeout(function () {
+          window.location.href = linkDownloadAppStore;
+        }, 250); // 250ms 延迟,给 Universal Link 尝试拉起 App 的时间
+      } else if (ua.search("android") > -1) {
+        // 对于 Android 设备,尝试直接打开 App Link
+        window.location.href = appDeeplink; // 尝试 App Link
+        setTimeout(function () {
+          window.location.href = linkDownloadPlayMarket;
+        }, 250); // 250ms 延迟
+      } else {
+        // 对于其他设备,直接跳转到 Android 下载链接(或通用下载页)
+        window.location.href = linkDownloadCommon;
+      }
+    }
+
+  </script>
 </head>
 <!-- Google tag (gtag.js) -->
 <script async src="https://www.googletagmanager.com/gtag/js?id=G-JBGGVGLHTP"></script>
@@ -273,14 +326,18 @@
           <% if (detail.totalStartCount> 0) { %> <%=detail.totalStartCount%> people have participated in coloring this
               work, and <%=detail.totalDoneCount%> have completed it. Come and take on the challenge! <% } %>
         </p>
-        <h3 id="status" data-content-id="<%= detail._id %>" style="display: none;">You have completed 50%—keep going and finish it!</h3>
+        <h3 id="status" data-content-id="<%= detail._id %>" style="display: none;">You have completed 50%—keep going and
+          finish it!</h3>
         <div class="creator-info">
           <div class="creator-avatar">
-            <a href="/coloring-page-gallery?author=<%= detail.user.username %>"><img src="<%= detail.user.avatar %>" width="100%", height="100%", style="border-radius: 50%;"></a>
+            <a href="/coloring-page-gallery?author=<%= detail.user.username %>"><img src="<%= detail.user.avatar %>"
+                width="100%" , height="100%" , style="border-radius: 50%;"></a>
           </div>
           <div>
             <div class="creator-name">
-              <a href="/coloring-page-gallery?author=<%= detail.user.username %>" style="color: var(--secondary-color)"><%= detail.user.username %></a>
+              <a href="/coloring-page-gallery?author=<%= detail.user.username %>" style="color: var(--secondary-color)">
+                <%= detail.user.username %>
+              </a>
             </div>
             <div class="creator-date">Published on <%= detail.publishTime %>
             </div>
@@ -289,7 +346,9 @@
 
         <div class="tags">
           <% detail.tags.forEach(tag=> { %>
-            <a href="/coloring-page-gallery?category=<%= tag %>"><span class="tag"><%= tag %></span></a>
+            <a href="/coloring-page-gallery?category=<%= tag %>"><span class="tag">
+                <%= tag %>
+              </span></a>
             <% }); %>
         </div>
 
@@ -303,7 +362,8 @@
           <a id="repaintBtn" onclick="onRepaint('<%= detail._id %>')" class="btn" style="display: none;">Repaint</a>
           <a id="reviewBtn" href="/play/<%= detail._id %>" class="btn"
             style="background-color: orange; display: none;">Review</a>
-          <a id="appBtn" class="btn" style="background-color: darkolivegreen;">Paint on APP</a>
+          <a id="appBtn" class="btn" href="#" onclick="functionDownload()"
+            style="background-color: darkolivegreen;">Paint on APP</a>
           <a href="/download/pdf/page/<%= detail._id %>" class="btn"
             style="background-color: lightseagreen;">Download</a>
           <a id="printBtn" onclick="printImage('<%= detail._id %>')" class="btn"
@@ -316,8 +376,9 @@
         <p>
           <%= detail.desc %>
         </p>
-        <p>You can <strong>download it in High-definition PDF format, print it</strong>, or choose to <strong>color online (using our app or directly in a
-          browser)</strong>—completely free of charge.</p>
+        <p>You can <strong>download it in High-definition PDF format, print it</strong>, or choose to <strong>color
+            online (using our app or directly in a
+            browser)</strong>—completely free of charge.</p>
         <p>Coloring this page can help reduce stress, improve focus, and allow you to express your artistic side.
           Whether
           you prefer traditional coloring tools or digital methods, this design will look stunning when complete.</p>
@@ -350,16 +411,20 @@
         <h2>Browse More Coloring Collections</h2>
         <div class="collection-grid">
           <% collections.forEach(item=> { %>
-          <a href="<%= item.uri %>" class="collection-card">
+            <a href="<%= item.uri %>" class="collection-card">
               <div class="collection-image">
-                  <img src="<%= item.image %>" alt="<%= item.title %>">
+                <img src="<%= item.image %>" alt="<%= item.title %>">
               </div>
               <div class="collection-info">
-                  <div class="collection-title"><%= item.title %></div>
-                  <p class="collection-desc"><%= item.description %></p>
+                <div class="collection-title">
+                  <%= item.title %>
+                </div>
+                <p class="collection-desc">
+                  <%= item.description %>
+                </p>
               </div>
-          </a>
-          <% }); %>
+            </a>
+            <% }); %>
         </div>
       </section>
 
@@ -368,135 +433,89 @@
 
     <%- include('footer') %>
 
-    <script src="/scripts/script.js"></script>
-    <script src="/scripts/progress2.js"></script>
+      <script src="/scripts/script.js"></script>
+      <script src="/scripts/progress2.js"></script>
+
+      <script>
+        // 重新进入或返回,强制刷新
+        window.addEventListener('pageshow', function (event) {
+          if (event.persisted) {
+            window.location.reload();
+          }
+        });
 
-    <script>
-      // 重新进入或返回,强制刷新
-      window.addEventListener('pageshow', function (event) {
-        if (event.persisted) {
-          window.location.reload();
+        function isMobileDevice() {
+          return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
         }
-      });
 
-      function isMobileDevice() {
-        return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
-      }
+        window.onload = function () {
+          if (isMobileDevice()) {
+            const printBtn = document.getElementById('printBtn');
+            printBtn.style.display = 'none'; // 移动端隐藏打印按钮
+          }
+        };
 
-      window.onload = function () {
-        if (isMobileDevice()) {
-          const printBtn = document.getElementById('printBtn');
-          printBtn.style.display = 'none'; // 移动端隐藏打印按钮
+        function jumpToAppDownload() {
+          const userAgent = navigator.userAgent || navigator.vendor || window.opera;
+
+          // Android 检测
+          if (/android/i.test(userAgent)) {
+            window.open('https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number', '_blank');
+          }
+          // iOS 检测
+          else if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
+            window.open('https://apps.apple.com/gb/app/art-number-coloring-book/id1575480118', '_blank');
+          }
+          // 其他操作系统(例如桌面)
+          else {
+            // 可以显示一个提示,或者跳转到通用的下载页面
+            console.log('无法确定操作系统,或者为桌面操作系统');
+            window.open('https://pcoloring.com/anc/', '_blank');
+          }
         }
-      };
 
-      function jumpToAppDownload() {
-        const userAgent = navigator.userAgent || navigator.vendor || window.opera;
 
-        // Android 检测
-        if (/android/i.test(userAgent)) {
-          window.open('https://play.google.com/store/apps/details?id=com.pcoloring.art.puzzle.color.by.number', '_blank');
-        }
-        // iOS 检测
-        else if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
-          window.open('https://apps.apple.com/gb/app/art-number-coloring-book/id1575480118', '_blank');
-        }
-        // 其他操作系统(例如桌面)
-        else {
-          // 可以显示一个提示,或者跳转到通用的下载页面
-          console.log('无法确定操作系统,或者为桌面操作系统');
-          window.open('https://pcoloring.com/anc/', '_blank');
-        }
-      }
+        // document.getElementById('appBtn').addEventListener('click', function () {
+        //   jumpToAppDownload()
+        // });
 
-      
-      document.getElementById('appBtn').addEventListener('click', function () {
-        jumpToAppDownload()
-      });
-      
-
-
-      /*
-      document.addEventListener('DOMContentLoaded', function() {
-        const contentId = document.getElementById('status').dataset.contentId; // 获取当前填色页的ID
-        const appScheme = `artcoloringapp://play/${contentId}`; // 自定义 URI Scheme (备用方案)
-        const universalLink = window.location.href; // Universal Link / Android App Link 就是当前页面的URL
-
-        // 尝试拉起App的函数
-        function tryOpenApp() {
-            // 尝试使用 Universal Link / Android App Link
-            // 浏览器会自动尝试处理这些链接,如果配置正确,App会直接打开
-            // 对于 iOS Safari,如果配置了Universal Links,直接点击分享链接就会拉起App
-            // 对于 Android Chrome,如果配置了App Links,直接点击分享链接也会拉起App
-
-            // 处理用户点击页面内按钮的情况,或作为回退机制
-            setTimeout(function() {
-                // 如果App没有被拉起 (例如,App未安装或Universal Link/App Link未生效)
-                // 此时可以判断是否需要跳转到App Store/Google Play
-                if (!document.hidden) { // 检查页面是否仍然可见,表示App未被拉起
-                    console.log("App not opened, redirecting to store or showing smart banner.");
-                    jumpToAppDownload();
-                    // 在这里可以实现 Deferred Deep Link 逻辑
-                    // 1. 显示一个智能 App 横幅 (Smart App Banner) 引导用户下载
-                    // 2. 直接重定向到App Store/Google Play
-                    // 例如:
-                    // window.location.href = "https://your-app-store-link.com";
-                }
-            }, 1500); // 给浏览器足够的时间尝试拉起App
-        }
 
-        // 绑定到“Paint on APP”按钮
-        const appBtn = document.getElementById('appBtn');
-        if (appBtn) {
-            appBtn.addEventListener('click', function(event) {
-                event.preventDefault(); // 阻止默认的链接跳转行为
-                window.location.href = appScheme; // 优先尝试自定义 Scheme(在某些旧版系统或浏览器中可能有效)
-                tryOpenApp(); // 之后尝试Universal Link/App Link的逻辑
-            });
-        }
+        async function printImage(id) {
+          try {
+            const response = await fetch(`/download/pdf/page/${id}`);
 
-        // **对于社交媒体分享的场景:**
-        // Universal Links / Android App Links 的核心在于,当用户点击一个指向您网站的链接时,
-        // 操作系统(而不是浏览器)会首先判断是否有匹配的已安装 App。
-        // 如果有,就直接打开 App 并传递链接参数;如果没有,才会在浏览器中打开网页。
-        // 这意味着,您不需要在页面加载时自动执行 JavaScript 来“拉起”App,
-        // 而是依赖操作系统本身的机制。
-        //
-        // 但是,您可以在页面加载时,根据需要添加一个智能横幅或提示。
-        //
-        // 智能横幅示例 (iOS Safari):
-        // <meta name="apple-itunes-app" content="app-id=YOUR_APP_STORE_ID, app-argument=https://art.pcoloring.com/play/63071db0b4aa5241f192c4c0">
-        //
-        // Android Chrome 的 App Install Banner 会自动处理。
-
-    });
-    */
-
-
-      async function printImage(id) {
-        try {
-          const response = await fetch(`/download/pdf/page/${id}`);
-
-          if (!response.ok) {
-            throw new Error(`HTTP error! status: ${response.status}`);
-          }
+            if (!response.ok) {
+              throw new Error(`HTTP error! status: ${response.status}`);
+            }
 
-          const pdfBlob = await response.blob();
-          const pdfUrl = URL.createObjectURL(pdfBlob);
+            const pdfBlob = await response.blob();
+            const pdfUrl = URL.createObjectURL(pdfBlob);
 
-          const printWindow = window.open(pdfUrl, '_blank');
-          printWindow.onload = () => {
-            printWindow.print();
-          };
+            const printWindow = window.open(pdfUrl, '_blank');
+            printWindow.onload = () => {
+              printWindow.print();
+            };
 
-          URL.revokeObjectURL(pdfUrl); // 释放 URL 对象
-        } catch (error) {
-          console.error('Error printing image:', error);
+            URL.revokeObjectURL(pdfUrl); // 释放 URL 对象
+          } catch (error) {
+            console.error('Error printing image:', error);
+          }
         }
-      }
 
-      function onDelete(id) {
-        if (confirm('确定要删除游戏进度吗?')) {
+        function onDelete(id) {
+          if (confirm('确定要删除游戏进度吗?')) {
+            // 删除本地存储
+            localStorage.removeItem(id);
+
+            const METADATA_KEY = '__storage_metadata__';
+            const metadata = JSON.parse(localStorage.getItem(METADATA_KEY) || '{}');
+            delete metadata[id];
+            localStorage.setItem(METADATA_KEY, JSON.stringify(metadata));
+            location.reload(); // 刷新页面恢复初始状态
+          }
+        }
+
+        function onRepaint(id) {
           // 删除本地存储
           localStorage.removeItem(id);
 
@@ -504,65 +523,53 @@
           const metadata = JSON.parse(localStorage.getItem(METADATA_KEY) || '{}');
           delete metadata[id];
           localStorage.setItem(METADATA_KEY, JSON.stringify(metadata));
-          location.reload(); // 刷新页面恢复初始状态
-        }
-      }
-
-      function onRepaint(id) {
-        // 删除本地存储
-        localStorage.removeItem(id);
 
-        const METADATA_KEY = '__storage_metadata__';
-        const metadata = JSON.parse(localStorage.getItem(METADATA_KEY) || '{}');
-        delete metadata[id];
-        localStorage.setItem(METADATA_KEY, JSON.stringify(metadata));
+          window.open(`/play/${id}`, '_self');
+        }
 
-        window.open(`/play/${id}`, '_self');
-      }
+        // 页面加载完成后执行
+        document.addEventListener('DOMContentLoaded', () => {
+          const METADATA_KEY = '__storage_metadata__';
 
-      // 页面加载完成后执行
-      document.addEventListener('DOMContentLoaded', () => {
-        const METADATA_KEY = '__storage_metadata__';
+          const container = document.getElementById('status');
+          const contentId = container.dataset.contentId;
 
-        const container = document.getElementById('status');
-        const contentId = container.dataset.contentId;
+          // 获取本地存储数据
+          const metaData = JSON.parse(localStorage.getItem(METADATA_KEY)) || {};
 
-        // 获取本地存储数据
-        const metaData = JSON.parse(localStorage.getItem(METADATA_KEY)) || {};
+          if (metaData[contentId]) {
+            const progress = Math.round(metaData[contentId].progress);
+            if (progress < 100) {
+              container.innerHTML = `You have completed ${progress}%—keep going and finish it!`;
+            } else {
+              container.innerHTML = `You have completed 100%, Good Job!`;
+              container.style = `color: var(--secondary-color)`
+            }
 
-        if (metaData[contentId]) {
-          const progress = Math.round(metaData[contentId].progress);
-          if (progress < 100) {
-            container.innerHTML = `You have completed ${progress}%—keep going and finish it!`;
-          } else {
-            container.innerHTML = `You have completed 100%, Good Job!`;
-            container.style  = `color: var(--secondary-color)`
-          }
-          
-          container.style.display = "block";
-
-          // 添加删除按钮
-          const deleteBtn = document.getElementById('deleteBtn');
-          deleteBtn.style.display = 'block';
-
-          // 开始填色按钮便成继续填色或重新填色
-          const playBtn = document.getElementById('playBtn');
-          const continueBtn = document.getElementById('continueBtn');
-          const repaintBtn = document.getElementById('repaintBtn');
-          const reviewBtn = document.getElementById('reviewBtn');
-          playBtn.style.display = 'none';
-          if (progress < 100) {
-            continueBtn.style.display = 'block';
-          } else {
-            repaintBtn.style.display = 'block';
-            reviewBtn.style.display = 'block';
-
-            const img = document.querySelector('#poster img');
-            img.src = img.src.replace('/page/', '/work/');
+            container.style.display = "block";
+
+            // 添加删除按钮
+            const deleteBtn = document.getElementById('deleteBtn');
+            deleteBtn.style.display = 'block';
+
+            // 开始填色按钮便成继续填色或重新填色
+            const playBtn = document.getElementById('playBtn');
+            const continueBtn = document.getElementById('continueBtn');
+            const repaintBtn = document.getElementById('repaintBtn');
+            const reviewBtn = document.getElementById('reviewBtn');
+            playBtn.style.display = 'none';
+            if (progress < 100) {
+              continueBtn.style.display = 'block';
+            } else {
+              repaintBtn.style.display = 'block';
+              reviewBtn.style.display = 'block';
+
+              const img = document.querySelector('#poster img');
+              img.src = img.src.replace('/page/', '/work/');
+            }
           }
-        }
-      });
-  </script>
+        });
+      </script>
 
 </body>
 

+ 135 - 0
views/v2/share.ejs

@@ -0,0 +1,135 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta http-equiv="x-ua-compatible" content="ie=edge">
+  <title>Art Number Coloring</title>
+  <link rel='stylesheet' href='/stylesheets/share.css' />
+
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <meta name="description" content="Free Coloring Pages Paint Online!">
+  <meta name="keywords" content="color, paint, app, ios, android, game">
+
+  <meta property="og:site_name" content="art.pcoloring.com">
+  <meta property="og:title" content="Art Number Coloring">
+  <meta property="og:description" content="Free Coloring Pages Paint Online!">
+  <meta property="og:image" content="<%= imageUrl %>">
+  <meta property="og:type" content="website">
+
+  <!-- MARK: Universal Link / Android App Link 的核心配置 -->
+  <!-- 这些 meta 标签的值应该是完整的 HTTPS 链接,Facebook 会识别并尝试拉起 App -->
+  <meta property="og:url" content="<%= applink %>" /> <!-- **Universal Link 路径** -->
+  <meta property="al:ios:url" content="<%= applink %>" /> <!-- **Universal Link 路径** -->
+  <meta property="al:ios:app_store_id" content="1575480118" /> <!-- **iOS App Store ID** -->
+  <meta property="al:ios:app_name" content="Art Number Coloring Book" /> <!-- **iOS 应用名称** -->
+
+  <meta property="al:android:package" content="com.pcoloring.art.puzzle.color.by.number" /> <!-- **Android 包名** -->
+  <meta property="al:android:url" content="<%= applink %>" /> <!-- ** Universal Link 路径** -->
+  <meta property="al:android:app_name" content="Art Number Coloring Book" /> <!-- **Android 应用名称** -->
+
+
+  <link rel="icon" href="/assets/icon/favicon.ico" type="image/x-icon">
+  <link rel="apple-touch-icon" sizes="180x180" href="/assets/icon/icon.png">
+
+  <style>
+    :root {
+      --primary-color: #ff6b6b;
+      --secondary-color: #4ecdc4;
+      --accent-color: #ffd166;
+      --background-color: #f9f9f9;
+      --text-color: #333;
+      --light-text: #666;
+      --border-color: #e0e0e0;
+    }
+
+    * {
+      margin: 0;
+      padding: 0;
+      box-sizing: border-box;
+      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+    }
+
+    body {
+      background-color: var(--background-color);
+      color: var(--text-color);
+      line-height: 1.6;
+    }
+
+    .container {
+      max-width: 1200px;
+      margin: 0 auto;
+      padding: 0 20px;
+    }
+
+    .btn {
+      display: inline-block;
+      background-color: var(--primary-color);
+      color: white;
+      border: none;
+      padding: 10px 20px;
+      border-radius: 5px;
+      font-size: 1.1rem;
+      font-weight: 500;
+      cursor: pointer;
+      transition: background-color 0.3s ease;
+      text-decoration: none;
+      text-align: center;
+      margin-right: 10px;
+      margin-bottom: 10px;
+    }
+
+    .btn:hover {
+      background-color: #ff4d4d;
+    }
+
+    .btn-secondary {
+      background-color: var(--secondary-color);
+    }
+
+    .btn-secondary:hover {
+      background-color: #37b0a8;
+    }
+
+    .content {
+      height: 100%;
+      width: 100%;
+      position: relative;
+      overflow: hidden;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+    }
+
+    .content img {
+      width: 100%;
+      max-width: 550px;
+      height: auto;
+      margin: 20px;
+    }
+
+    .buttons {
+      width: 100%;
+      max-width: 550px;
+      display: flex;
+      flex-wrap: wrap;
+      justify-content: space-between;
+      align-items: center;
+    }
+  </style>
+</head>
+
+<body>
+  <div class="container">
+    <div class="content">
+      <img src="<%= imageUrl %>" alt="Art Number Coloring" />
+      <div class="buttons">
+        <a href="/">Home</a>
+        <a href="<%= downlink %>" class="btn btn-secondary">Download App</a>
+        <a href="/coloring-page/<%= id %>">Detail>></a>
+      </div>
+    </div>
+  </div>
+</body>
+
+</html>