feat: 添加 PWA 下载页面和路由配置;更新 PWA 图标设置
This commit is contained in:
@@ -204,6 +204,10 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
path: "/global-menu",
|
path: "/global-menu",
|
||||||
component: () => import("@/views/global-menu/index.vue"),
|
component: () => import("@/views/global-menu/index.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/pwa_download",
|
||||||
|
component: () => import("@/views/pwa/download.vue"),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
|
|||||||
253
src/views/pwa/download.vue
Normal file
253
src/views/pwa/download.vue
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
<script lang='ts' setup>
|
||||||
|
import { alertController } from "@ionic/vue";
|
||||||
|
import IconParkOutlineApplication from "~icons/icon-park-outline/application";
|
||||||
|
import IconParkOutlineCheckOne from "~icons/icon-park-outline/check-one";
|
||||||
|
import IconParkOutlineDownload from "~icons/icon-park-outline/download";
|
||||||
|
import IconParkOutlinePhone from "~icons/icon-park-outline/phone";
|
||||||
|
import IconParkOutlineShare from "~icons/icon-park-outline/share";
|
||||||
|
|
||||||
|
const { showInstallButton, isInstalled, promptInstall, isIOS, isIOSSafari } = usePWAInstall();
|
||||||
|
const platform = usePlatform();
|
||||||
|
|
||||||
|
const appName = "Riwa";
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const showIOSGuide = ref(false);
|
||||||
|
|
||||||
|
// 检测用户是否卸载过应用
|
||||||
|
const wasUninstalled = computed(() => {
|
||||||
|
// 如果localStorage中有标记表示曾经安装过,但当前未安装
|
||||||
|
const wasInstalled = localStorage.getItem("pwa-was-installed");
|
||||||
|
return wasInstalled === "true" && !isInstalled.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 显示下载按钮的条件:
|
||||||
|
// 1. 浏览器环境
|
||||||
|
// 2. 未安装或曾经卸载过
|
||||||
|
// 3. Android 或有安装提示事件
|
||||||
|
const shouldShowDownloadButton = computed(() => {
|
||||||
|
return platform === "browser" && (!isInstalled.value || wasUninstalled.value) && (showInstallButton.value || wasUninstalled.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// iOS 安装指引
|
||||||
|
async function showIOSInstallGuide() {
|
||||||
|
showIOSGuide.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理安装
|
||||||
|
async function handleInstall() {
|
||||||
|
if (isIOSSafari) {
|
||||||
|
await showIOSInstallGuide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading.value = true;
|
||||||
|
try {
|
||||||
|
const result = await promptInstall();
|
||||||
|
|
||||||
|
if (result.outcome === "accepted") {
|
||||||
|
// 记录已安装状态
|
||||||
|
localStorage.setItem("pwa-was-installed", "true");
|
||||||
|
|
||||||
|
const alert = await alertController.create({
|
||||||
|
header: "安装成功",
|
||||||
|
message: "应用已成功安装到您的设备",
|
||||||
|
buttons: ["确定"],
|
||||||
|
});
|
||||||
|
await alert.present();
|
||||||
|
}
|
||||||
|
else if (result.outcome === "ios-instruction") {
|
||||||
|
await showIOSInstallGuide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error("Installation error:", error);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听安装状态变化
|
||||||
|
watch(isInstalled, (installed) => {
|
||||||
|
if (installed) {
|
||||||
|
localStorage.setItem("pwa-was-installed", "true");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ion-page>
|
||||||
|
<ion-header class="ion-no-border">
|
||||||
|
<ion-toolbar class="ion-toolbar">
|
||||||
|
<ion-title>下载应用</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content :fullscreen="true">
|
||||||
|
<div class="flex flex-col items-center min-h-full px-6 py-12">
|
||||||
|
<!-- App Logo & Name -->
|
||||||
|
<div class="flex flex-col items-center mb-8">
|
||||||
|
<img alt="RWA平台" src="/favicon.svg" class="w-16 h-16">
|
||||||
|
<h1 class="text-3xl font-bold mb-2">
|
||||||
|
{{ appName }}
|
||||||
|
</h1>
|
||||||
|
<p class="text-text-500 text-center text-sm">
|
||||||
|
随时随地,管理您的数字资产
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 已安装状态 -->
|
||||||
|
<div v-if="isInstalled && !wasUninstalled" class="w-full max-w-md">
|
||||||
|
<div class="bg-success/10 border border-success/20 rounded-2xl p-6 text-center">
|
||||||
|
<IconParkOutlineCheckOne class="text-5xl text-success mx-auto mb-4" />
|
||||||
|
<h2 class="text-lg font-semibold text-success mb-2">
|
||||||
|
应用已安装
|
||||||
|
</h2>
|
||||||
|
<p class="text-sm text-text-500">
|
||||||
|
您可以在主屏幕找到应用图标
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- iOS 安装指引 -->
|
||||||
|
<div v-else-if="isIOSSafari || (platform === 'browser' && isIOS)" class="w-full max-w-md">
|
||||||
|
<div class="bg-background-secondary rounded-2xl p-6 mb-6">
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<IconParkOutlinePhone class="text-2xl text-primary mr-3" />
|
||||||
|
<h2 class="text-lg font-semibold">
|
||||||
|
iOS 安装步骤
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<!-- Step 1 -->
|
||||||
|
<div class="flex-center">
|
||||||
|
<div class="w-8 h-8 rounded-full bg-text-900 text-text-300 flex items-center justify-center font-bold text-sm mr-3 shrink-0">
|
||||||
|
1
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<p class="text-sm">
|
||||||
|
点击 Safari 底部的
|
||||||
|
<IconParkOutlineShare class="inline-block text-primary mx-1" />
|
||||||
|
<strong>分享</strong> 按钮
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Step 2 -->
|
||||||
|
<div class="flex-center">
|
||||||
|
<div class="w-8 h-8 rounded-full bg-text-900 text-text-300 flex items-center justify-center font-bold text-sm mr-3 shrink-0">
|
||||||
|
2
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<p class="text-sm">
|
||||||
|
在弹出的菜单中,向下滚动找到
|
||||||
|
<strong>"添加到主屏幕"</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Step 3 -->
|
||||||
|
<div class="flex-center">
|
||||||
|
<div class="w-8 h-8 rounded-full bg-text-900 text-text-300 flex items-center justify-center font-bold text-sm mr-3 shrink-0">
|
||||||
|
3
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<p class="text-sm">
|
||||||
|
点击 <strong>"添加"</strong> 完成安装
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 提示卡片 -->
|
||||||
|
<div class="bg-warning/10 border border-warning/20 rounded-xl p-4 text-sm text-text-600">
|
||||||
|
<p class="flex-center">
|
||||||
|
<span class="mr-2">💡</span>
|
||||||
|
<span>请使用 Safari 浏览器进行安装</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Android/Chrome 下载按钮 -->
|
||||||
|
<div v-else-if="shouldShowDownloadButton" class="w-full max-w-md">
|
||||||
|
<div class="bg-background-secondary rounded-2xl p-6 mb-6 text-center">
|
||||||
|
<IconParkOutlineDownload class="text-5xl text-primary mx-auto mb-4" />
|
||||||
|
<h2 class="text-xl font-semibold mb-2">
|
||||||
|
{{ wasUninstalled ? '重新安装应用' : '安装到设备' }}
|
||||||
|
</h2>
|
||||||
|
<p class="text-sm text-text-500 mb-6">
|
||||||
|
{{ wasUninstalled ? '快速重新安装应用到您的设备' : '一键安装,无需下载,即刻使用' }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ion-button
|
||||||
|
expand="block"
|
||||||
|
size="large"
|
||||||
|
class="font-semibold"
|
||||||
|
:disabled="isLoading"
|
||||||
|
@click="handleInstall"
|
||||||
|
>
|
||||||
|
<IconParkOutlineDownload v-if="!isLoading" class="mr-2" />
|
||||||
|
<ion-spinner v-if="isLoading" name="crescent" class="mr-2" />
|
||||||
|
{{ isLoading ? '安装中...' : wasUninstalled ? '重新安装' : '立即安装' }}
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 优势列表 -->
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="flex items-center text-sm">
|
||||||
|
<div class="w-8 h-8 rounded-full bg-success/10 flex items-center justify-center mr-3">
|
||||||
|
<IconParkOutlineCheckOne class="text-success" />
|
||||||
|
</div>
|
||||||
|
<span class="text-text-600">无需应用商店,快速安装</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center text-sm">
|
||||||
|
<div class="w-8 h-8 rounded-full bg-success/10 flex items-center justify-center mr-3">
|
||||||
|
<IconParkOutlineCheckOne class="text-success" />
|
||||||
|
</div>
|
||||||
|
<span class="text-text-600">占用空间小,运行流畅</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center text-sm">
|
||||||
|
<div class="w-8 h-8 rounded-full bg-success/10 flex items-center justify-center mr-3">
|
||||||
|
<IconParkOutlineCheckOne class="text-success" />
|
||||||
|
</div>
|
||||||
|
<span class="text-text-600">自动更新,始终最新版本</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 原生应用提示 -->
|
||||||
|
<div v-else-if="platform !== 'browser'" class="w-full max-w-md">
|
||||||
|
<div class="bg-background-secondary rounded-2xl p-6 text-center">
|
||||||
|
<IconParkOutlineCheckOne class="text-5xl text-success mx-auto mb-4" />
|
||||||
|
<h2 class="text-lg font-semibold mb-2">
|
||||||
|
您正在使用原生应用
|
||||||
|
</h2>
|
||||||
|
<p class="text-sm text-text-500">
|
||||||
|
已经是最新版本,无需下载
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 浏览器不支持提示 -->
|
||||||
|
<div v-else class="w-full max-w-md">
|
||||||
|
<div class="bg-warning/10 border border-warning/20 rounded-2xl p-6 text-center">
|
||||||
|
<p class="text-sm text-text-600">
|
||||||
|
当前浏览器暂不支持应用安装
|
||||||
|
</p>
|
||||||
|
<p class="text-xs text-text-500 mt-2">
|
||||||
|
建议使用 Chrome、Safari 或 Edge 浏览器
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang='css' scoped>
|
||||||
|
ion-content {
|
||||||
|
--background: var(--ion-background-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -57,20 +57,9 @@ export default defineConfig({
|
|||||||
prefer_related_applications: false,
|
prefer_related_applications: false,
|
||||||
icons: [
|
icons: [
|
||||||
{
|
{
|
||||||
src: "/pwa-192x192.png",
|
src: "/favicon.svg",
|
||||||
sizes: "192x192",
|
sizes: "192x192",
|
||||||
type: "image/png",
|
type: "image/svg",
|
||||||
},
|
|
||||||
{
|
|
||||||
src: "/pwa-512x512.png",
|
|
||||||
sizes: "512x512",
|
|
||||||
type: "image/png",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: "/pwa-512x512.png",
|
|
||||||
sizes: "512x512",
|
|
||||||
type: "image/png",
|
|
||||||
purpose: "any maskable",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user