|
|
@@ -0,0 +1,305 @@
|
|
|
+<template>
|
|
|
+ <div class="desktop-add-guide">
|
|
|
+ <!-- 主要添加方案 -->
|
|
|
+ <div class="main-solutions">
|
|
|
+ <h3 class="text-lg font-semibold text-white/90 mb-4">快速添加到桌面</h3>
|
|
|
+
|
|
|
+ <!-- 方案列表 -->
|
|
|
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
+ <!-- Web Shortcuts API -->
|
|
|
+ <div v-if="capabilities.hasWebShortcuts"
|
|
|
+ class="solution-card bg-blue-500/10 border border-blue-500/20">
|
|
|
+ <div class="flex items-center gap-3 mb-3">
|
|
|
+ <div class="w-10 h-10 rounded-full bg-blue-500/20 flex items-center justify-center">
|
|
|
+ <svg class="w-5 h-5 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <h4 class="font-medium text-blue-200">一键添加快捷方式</h4>
|
|
|
+ <p class="text-sm text-blue-300/80">最新浏览器支持</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <button @click="addWebShortcut"
|
|
|
+ :disabled="isAdding"
|
|
|
+ class="w-full px-4 py-2 rounded-lg bg-blue-500/20 text-blue-300 text-sm font-medium hover:bg-blue-500/30 transition disabled:opacity-50">
|
|
|
+ <svg v-if="isAdding" class="w-4 h-4 animate-spin mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
|
|
|
+ </svg>
|
|
|
+ <span v-else>立即添加</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- PWA安装 -->
|
|
|
+ <div v-if="capabilities.hasBeforeInstallPrompt"
|
|
|
+ class="solution-card bg-green-500/10 border border-green-500/20">
|
|
|
+ <div class="flex items-center gap-3 mb-3">
|
|
|
+ <div class="w-10 h-10 rounded-full bg-green-500/20 flex items-center justify-center">
|
|
|
+ <svg class="w-5 h-5 text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <h4 class="font-medium text-green-200">安装为PWA应用</h4>
|
|
|
+ <p class="text-sm text-green-300/80">完整应用体验</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <button @click="installPWA"
|
|
|
+ :disabled="isInstalling"
|
|
|
+ class="w-full px-4 py-2 rounded-lg bg-green-500/20 text-green-300 text-sm font-medium hover:bg-green-500/30 transition disabled:opacity-50">
|
|
|
+ <svg v-if="isInstalling" class="w-4 h-4 animate-spin mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
|
|
|
+ </svg>
|
|
|
+ <span v-else>安装应用</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 书签方案 -->
|
|
|
+ <div v-if="capabilities.hasClipboard || capabilities.hasShare"
|
|
|
+ class="solution-card bg-purple-500/10 border border-purple-500/20">
|
|
|
+ <div class="flex items-center gap-3 mb-3">
|
|
|
+ <div class="w-10 h-10 rounded-full bg-purple-500/20 flex items-center justify-center">
|
|
|
+ <svg class="w-5 h-5 text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z"/>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <h4 class="font-medium text-purple-200">保存为书签</h4>
|
|
|
+ <p class="text-sm text-purple-300/80">通用兼容方案</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <button @click="addBookmark"
|
|
|
+ :disabled="isAdding"
|
|
|
+ class="w-full px-4 py-2 rounded-lg bg-purple-500/20 text-purple-300 text-sm font-medium hover:bg-purple-500/30 transition disabled:opacity-50">
|
|
|
+ <svg v-if="isAdding" class="w-4 h-4 animate-spin mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
|
|
|
+ </svg>
|
|
|
+ <span v-else>保存书签</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 二维码方案 -->
|
|
|
+ <div class="solution-card bg-orange-500/10 border border-orange-500/20">
|
|
|
+ <div class="flex items-center gap-3 mb-3">
|
|
|
+ <div class="w-10 h-10 rounded-full bg-orange-500/20 flex items-center justify-center">
|
|
|
+ <svg class="w-5 h-5 text-orange-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v1m6 11h2m-6 0h-2v4m0-11v3m0 0h.01M12 12h4.01M16 20h4M4 12h4m12 0h.01M5 8h2a1 1 0 001-1V5a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1zm12 0h2a1 1 0 001-1V5a1 1 0 00-1-1h-2a1 1 0 00-1 1v2a1 1 0 001 1zM5 20h2a1 1 0 001-1v-2a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1z"/>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <h4 class="font-medium text-orange-200">二维码分享</h4>
|
|
|
+ <p class="text-sm text-orange-300/80">扫码快速访问</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <button @click="showQRCode"
|
|
|
+ class="w-full px-4 py-2 rounded-lg bg-orange-500/20 text-orange-300 text-sm font-medium hover:bg-orange-500/30 transition">
|
|
|
+ 生成二维码
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 二维码弹窗 -->
|
|
|
+ <div v-if="showQR" class="fixed inset-0 z-50 bg-black/60 flex items-center justify-center p-4">
|
|
|
+ <div class="bg-surface rounded-2xl border border-white/10 p-6 max-w-sm w-full">
|
|
|
+ <div class="flex items-center justify-between mb-4">
|
|
|
+ <h3 class="text-lg font-semibold text-white/90">二维码分享</h3>
|
|
|
+ <button @click="showQR = false" class="text-white/60 hover:text-white">
|
|
|
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div class="text-center">
|
|
|
+ <img :src="qrCodeUrl" alt="二维码" class="mx-auto mb-4 rounded-lg">
|
|
|
+ <p class="text-sm text-white/60 mb-4">扫描二维码快速访问</p>
|
|
|
+ <button @click="downloadQR"
|
|
|
+ class="px-4 py-2 rounded-lg bg-brand text-slate-900 text-sm font-medium">
|
|
|
+ 下载二维码
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 浏览器特定指导 -->
|
|
|
+ <div v-if="browserGuide" class="mt-6 p-4 rounded-xl bg-amber-500/10 border border-amber-500/20">
|
|
|
+ <div class="flex items-start gap-3">
|
|
|
+ <div class="flex-shrink-0 w-8 h-8 rounded-full bg-amber-500/20 flex items-center justify-center">
|
|
|
+ <svg class="w-4 h-4 text-amber-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <div class="flex-1">
|
|
|
+ <h4 class="font-medium text-amber-200">{{ browserGuide.title }}</h4>
|
|
|
+ <p class="text-sm text-amber-300/80 mt-1">{{ browserGuide.description }}</p>
|
|
|
+ <ol class="mt-2 space-y-1 text-sm text-amber-300/70">
|
|
|
+ <li v-for="(step, index) in browserGuide.steps" :key="index" class="flex items-start gap-2">
|
|
|
+ <span class="flex-shrink-0 w-4 h-4 rounded-full bg-amber-500/30 flex items-center justify-center text-xs font-medium">{{ index + 1 }}</span>
|
|
|
+ <span>{{ step }}</span>
|
|
|
+ </li>
|
|
|
+ </ol>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, computed, onMounted } from 'vue';
|
|
|
+import {
|
|
|
+ getBrowserCapabilities,
|
|
|
+ createWebShortcut,
|
|
|
+ createBookmark,
|
|
|
+ generateQRCode,
|
|
|
+ getBestDesktopSolution
|
|
|
+} from '@/utils/desktop-shortcuts';
|
|
|
+import { installPWA as installPWAUtil, getDeferredPrompt } from '@/utils/pwa';
|
|
|
+
|
|
|
+// 状态
|
|
|
+const isAdding = ref(false);
|
|
|
+const isInstalling = ref(false);
|
|
|
+const showQR = ref(false);
|
|
|
+const qrCodeUrl = ref('');
|
|
|
+
|
|
|
+// 浏览器能力检测
|
|
|
+const capabilities = getBrowserCapabilities();
|
|
|
+
|
|
|
+// 浏览器特定指导
|
|
|
+const browserGuide = computed(() => {
|
|
|
+ if (capabilities.isQQ) {
|
|
|
+ return {
|
|
|
+ title: "QQ浏览器优化建议",
|
|
|
+ description: "为了获得最佳体验,建议:",
|
|
|
+ steps: [
|
|
|
+ "更新到最新版本的QQ浏览器",
|
|
|
+ "在设置中启用「桌面模式」",
|
|
|
+ "允许网站创建快捷方式"
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ if (capabilities.isUC) {
|
|
|
+ return {
|
|
|
+ title: "UC浏览器优化建议",
|
|
|
+ description: "为了获得最佳体验,建议:",
|
|
|
+ steps: [
|
|
|
+ "更新到最新版本的UC浏览器",
|
|
|
+ "在设置中启用「PWA支持」",
|
|
|
+ "允许网站添加到桌面"
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ if (capabilities.isWechat) {
|
|
|
+ return {
|
|
|
+ title: "微信内置浏览器",
|
|
|
+ description: "微信内置浏览器功能有限,建议:",
|
|
|
+ steps: [
|
|
|
+ "点击右上角「...」按钮",
|
|
|
+ "选择「在浏览器中打开」",
|
|
|
+ "在外部浏览器中添加快捷方式"
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+});
|
|
|
+
|
|
|
+// 添加Web Shortcut
|
|
|
+async function addWebShortcut() {
|
|
|
+ isAdding.value = true;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const success = await createWebShortcut({
|
|
|
+ title: 'Junma Show',
|
|
|
+ url: window.location.href,
|
|
|
+ icon: '/icons/icon-192x192.png',
|
|
|
+ description: '在线视频播放平台'
|
|
|
+ });
|
|
|
+
|
|
|
+ if (success) {
|
|
|
+ alert('✅ 快捷方式已添加到桌面!');
|
|
|
+ } else {
|
|
|
+ throw new Error('创建失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 添加快捷方式失败:', error);
|
|
|
+ alert('❌ 添加快捷方式失败,请尝试其他方案');
|
|
|
+ } finally {
|
|
|
+ isAdding.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 安装PWA
|
|
|
+async function installPWA() {
|
|
|
+ isInstalling.value = true;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const result = await installPWAUtil();
|
|
|
+
|
|
|
+ if (result.success) {
|
|
|
+ alert('✅ PWA应用安装成功!');
|
|
|
+ } else {
|
|
|
+ throw new Error(result.error || '安装失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error(' PWA安装失败:', error);
|
|
|
+ alert('当前浏览器暂不支持,推荐使用谷歌浏览器安装');
|
|
|
+ } finally {
|
|
|
+ isInstalling.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 添加书签
|
|
|
+async function addBookmark() {
|
|
|
+ isAdding.value = true;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const success = await createBookmark({
|
|
|
+ title: 'Junma Show',
|
|
|
+ url: window.location.href,
|
|
|
+ description: '在线视频播放平台'
|
|
|
+ });
|
|
|
+
|
|
|
+ if (success) {
|
|
|
+ alert('✅ 书签已保存!请按照提示添加到桌面');
|
|
|
+ } else {
|
|
|
+ throw new Error('保存失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ 保存书签失败:', error);
|
|
|
+ alert('当前浏览器暂不支持,推荐使用谷歌浏览器安装');
|
|
|
+ } finally {
|
|
|
+ isAdding.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 显示二维码
|
|
|
+function showQRCode() {
|
|
|
+ qrCodeUrl.value = generateQRCode({
|
|
|
+ title: 'Junma Show',
|
|
|
+ url: window.location.href,
|
|
|
+ size: 200
|
|
|
+ });
|
|
|
+ showQR.value = true;
|
|
|
+}
|
|
|
+
|
|
|
+// 下载二维码
|
|
|
+function downloadQR() {
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = qrCodeUrl.value;
|
|
|
+ link.download = 'junma-show-qr.png';
|
|
|
+ link.click();
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ console.log('🔍 浏览器能力检测:', capabilities);
|
|
|
+ console.log('📋 可用方案:', getBestDesktopSolution());
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.solution-card {
|
|
|
+ @apply p-4 rounded-xl transition-all duration-200 hover:scale-105;
|
|
|
+}
|
|
|
+</style>
|