feat:去除多余的【回到首页】
This commit is contained in:
parent
027e7025f2
commit
38cfa8684f
@ -1,112 +1,143 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { Monitor, Download, ArrowLeft, CheckCircle2, AlertCircle } from 'lucide-vue-next'
|
||||
import logoImg from '@/assets/logo.png'
|
||||
import { ref, computed, onMounted, onUnmounted } from "vue";
|
||||
import { RouterLink } from "vue-router";
|
||||
import {
|
||||
Monitor,
|
||||
Download,
|
||||
ArrowLeft,
|
||||
CheckCircle2,
|
||||
AlertCircle,
|
||||
} from "lucide-vue-next";
|
||||
import logoImg from "@/assets/logo.png";
|
||||
import {
|
||||
TEACHER_APP_DOWNLOAD_URL,
|
||||
TEACHER_APP_BACKUP_DOWNLOAD_URL,
|
||||
TEACHER_APP_FILE_NAME,
|
||||
TEACHER_APP_FILE_SIZE,
|
||||
TEACHER_DOWNLOAD_COUNTDOWN_SECONDS,
|
||||
} from '@/constants/teacherApp'
|
||||
} from "@/constants/teacherApp";
|
||||
|
||||
const secondsLeft = ref(TEACHER_DOWNLOAD_COUNTDOWN_SECONDS)
|
||||
const downloadStarted = ref(false)
|
||||
const secondsLeft = ref(TEACHER_DOWNLOAD_COUNTDOWN_SECONDS);
|
||||
const downloadStarted = ref(false);
|
||||
|
||||
let timer: ReturnType<typeof setInterval> | null = null
|
||||
let timer: ReturnType<typeof setInterval> | null = null;
|
||||
|
||||
const progress = computed(() => {
|
||||
const total = TEACHER_DOWNLOAD_COUNTDOWN_SECONDS
|
||||
return ((total - secondsLeft.value) / total) * 100
|
||||
})
|
||||
const total = TEACHER_DOWNLOAD_COUNTDOWN_SECONDS;
|
||||
return ((total - secondsLeft.value) / total) * 100;
|
||||
});
|
||||
|
||||
const countdownLabel = computed(() => String(Math.max(secondsLeft.value, 0)))
|
||||
const countdownLabel = computed(() => String(Math.max(secondsLeft.value, 0)));
|
||||
|
||||
function triggerDownload() {
|
||||
if (downloadStarted.value) return
|
||||
downloadStarted.value = true
|
||||
if (downloadStarted.value) return;
|
||||
downloadStarted.value = true;
|
||||
|
||||
const link = document.createElement('a')
|
||||
link.href = TEACHER_APP_DOWNLOAD_URL
|
||||
link.target = '_blank'
|
||||
link.rel = 'noopener noreferrer'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
const link = document.createElement("a");
|
||||
link.href = TEACHER_APP_DOWNLOAD_URL;
|
||||
link.target = "_blank";
|
||||
link.rel = "noopener noreferrer";
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
|
||||
function skipCountdown() {
|
||||
if (timer) {
|
||||
clearInterval(timer)
|
||||
timer = null
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
secondsLeft.value = 0
|
||||
triggerDownload()
|
||||
secondsLeft.value = 0;
|
||||
triggerDownload();
|
||||
}
|
||||
|
||||
function startCountdown() {
|
||||
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
const prefersReducedMotion = window.matchMedia(
|
||||
"(prefers-reduced-motion: reduce)",
|
||||
).matches;
|
||||
if (prefersReducedMotion) {
|
||||
secondsLeft.value = 0
|
||||
triggerDownload()
|
||||
return
|
||||
secondsLeft.value = 0;
|
||||
triggerDownload();
|
||||
return;
|
||||
}
|
||||
|
||||
timer = setInterval(() => {
|
||||
if (secondsLeft.value > 0) {
|
||||
secondsLeft.value -= 1
|
||||
secondsLeft.value -= 1;
|
||||
}
|
||||
if (secondsLeft.value <= 0) {
|
||||
if (timer) clearInterval(timer)
|
||||
timer = null
|
||||
triggerDownload()
|
||||
if (timer) clearInterval(timer);
|
||||
timer = null;
|
||||
triggerDownload();
|
||||
}
|
||||
}, 1000)
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
onMounted(startCountdown)
|
||||
onMounted(startCountdown);
|
||||
onUnmounted(() => {
|
||||
if (timer) clearInterval(timer)
|
||||
})
|
||||
if (timer) clearInterval(timer);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-screen relative overflow-hidden flex flex-col">
|
||||
<div class="absolute inset-0 bg-gradient-to-br from-bg-soft via-white to-indigo-50/80" />
|
||||
<div class="absolute top-16 -left-24 w-80 h-80 rounded-full bg-primary/10 blur-3xl" />
|
||||
<div class="absolute bottom-20 -right-32 w-96 h-96 rounded-full bg-cyan-500/10 blur-3xl" />
|
||||
|
||||
<header class="relative z-10 max-w-7xl mx-auto w-full px-4 sm:px-6 lg:px-8 pt-6">
|
||||
<RouterLink
|
||||
to="/"
|
||||
class="inline-flex items-center gap-2 text-sm font-medium text-text-muted hover:text-primary transition-colors duration-200 cursor-pointer"
|
||||
>
|
||||
<ArrowLeft class="w-4 h-4" />
|
||||
返回首页
|
||||
</RouterLink>
|
||||
</header>
|
||||
|
||||
<main class="relative z-10 flex-1 flex items-center justify-center px-4 sm:px-6 py-12">
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-br from-bg-soft via-white to-indigo-50/80"
|
||||
/>
|
||||
<div
|
||||
class="absolute top-16 -left-24 w-80 h-80 rounded-full bg-primary/10 blur-3xl"
|
||||
/>
|
||||
<div
|
||||
class="absolute bottom-20 -right-32 w-96 h-96 rounded-full bg-cyan-500/10 blur-3xl"
|
||||
/>
|
||||
<main
|
||||
class="relative z-10 flex-1 flex items-center justify-center px-4 sm:px-6 py-12"
|
||||
>
|
||||
<div class="w-full max-w-lg">
|
||||
<div class="glass-card-strong rounded-3xl p-8 sm:p-10 shadow-xl shadow-indigo-100/50 border border-white/60">
|
||||
<div
|
||||
class="glass-card-strong rounded-3xl p-8 sm:p-10 shadow-xl shadow-indigo-100/50 border border-white/60"
|
||||
>
|
||||
<div class="flex flex-col items-center text-center">
|
||||
<img :src="logoImg" alt="灵犀学" class="h-10 w-auto mb-6" />
|
||||
|
||||
<div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-cyan-50 to-teal-50 border border-cyan-500/20 flex items-center justify-center mb-5">
|
||||
<div
|
||||
class="w-14 h-14 rounded-2xl bg-gradient-to-br from-cyan-50 to-teal-50 border border-cyan-500/20 flex items-center justify-center mb-5"
|
||||
>
|
||||
<Monitor class="w-7 h-7 text-cyan-600" />
|
||||
</div>
|
||||
|
||||
<h1 class="text-2xl sm:text-3xl font-bold text-text-heading tracking-tight">
|
||||
<h1
|
||||
class="text-2xl sm:text-3xl font-bold text-text-heading tracking-tight"
|
||||
>
|
||||
灵犀学AI 教师端
|
||||
</h1>
|
||||
<p class="mt-2 text-text-muted text-sm sm:text-base">
|
||||
{{ downloadStarted ? '下载已启动,请查看浏览器下载栏' : '即将自动开始下载,请稍候' }}
|
||||
{{
|
||||
downloadStarted
|
||||
? "下载已启动,请查看浏览器下载栏"
|
||||
: "即将自动开始下载,请稍候"
|
||||
}}
|
||||
</p>
|
||||
|
||||
<div class="relative my-10" aria-live="polite" :aria-label="`倒计时 ${countdownLabel} 秒`">
|
||||
<svg class="w-36 h-36 -rotate-90" viewBox="0 0 120 120" aria-hidden="true">
|
||||
<circle cx="60" cy="60" r="52" fill="none" stroke="currentColor" stroke-width="8" class="text-indigo-100" />
|
||||
<div
|
||||
class="relative my-10"
|
||||
aria-live="polite"
|
||||
:aria-label="`倒计时 ${countdownLabel} 秒`"
|
||||
>
|
||||
<svg
|
||||
class="w-36 h-36 -rotate-90"
|
||||
viewBox="0 0 120 120"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<circle
|
||||
cx="60"
|
||||
cy="60"
|
||||
r="52"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="8"
|
||||
class="text-indigo-100"
|
||||
/>
|
||||
<circle
|
||||
cx="60"
|
||||
cy="60"
|
||||
@ -120,21 +151,38 @@ onUnmounted(() => {
|
||||
:stroke-dashoffset="`${2 * Math.PI * 52 * (1 - progress / 100)}`"
|
||||
/>
|
||||
</svg>
|
||||
<div class="absolute inset-0 flex flex-col items-center justify-center">
|
||||
<span v-if="!downloadStarted" class="text-5xl font-extrabold tabular-nums gradient-text">
|
||||
<div
|
||||
class="absolute inset-0 flex flex-col items-center justify-center"
|
||||
>
|
||||
<span
|
||||
v-if="!downloadStarted"
|
||||
class="text-5xl font-extrabold tabular-nums gradient-text"
|
||||
>
|
||||
{{ countdownLabel }}
|
||||
</span>
|
||||
<CheckCircle2 v-else class="w-12 h-12 text-accent" />
|
||||
<span class="mt-1 text-xs font-medium text-text-muted uppercase tracking-wider">
|
||||
{{ downloadStarted ? '已开始' : '秒后下载' }}
|
||||
<span
|
||||
class="mt-1 text-xs font-medium text-text-muted uppercase tracking-wider"
|
||||
>
|
||||
{{ downloadStarted ? "已开始" : "秒后下载" }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-full rounded-2xl bg-slate-50/80 border border-slate-200/80 px-4 py-3 text-left mb-6">
|
||||
<p class="text-xs font-semibold text-text-muted uppercase tracking-wide mb-1">安装包信息</p>
|
||||
<p class="text-sm font-semibold text-text-heading break-all">{{ TEACHER_APP_FILE_NAME }}</p>
|
||||
<p class="text-xs text-text-muted mt-1">Windows 64 位 · {{ TEACHER_APP_FILE_SIZE }}</p>
|
||||
<div
|
||||
class="w-full rounded-2xl bg-slate-50/80 border border-slate-200/80 px-4 py-3 text-left mb-6"
|
||||
>
|
||||
<p
|
||||
class="text-xs font-semibold text-text-muted uppercase tracking-wide mb-1"
|
||||
>
|
||||
安装包信息
|
||||
</p>
|
||||
<p class="text-sm font-semibold text-text-heading break-all">
|
||||
{{ TEACHER_APP_FILE_NAME }}
|
||||
</p>
|
||||
<p class="text-xs text-text-muted mt-1">
|
||||
Windows 64 位 · {{ TEACHER_APP_FILE_SIZE }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-3 w-full">
|
||||
@ -174,7 +222,9 @@ onUnmounted(() => {
|
||||
</RouterLink>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-start gap-2 text-left w-full rounded-xl bg-amber-50/80 border border-amber-200/60 px-3 py-2.5">
|
||||
<div
|
||||
class="mt-6 flex items-start gap-2 text-left w-full rounded-xl bg-amber-50/80 border border-amber-200/60 px-3 py-2.5"
|
||||
>
|
||||
<AlertCircle class="w-4 h-4 text-amber-600 shrink-0 mt-0.5" />
|
||||
<p class="text-xs text-amber-900/80 leading-relaxed">
|
||||
若未弹出下载,请检查浏览器是否拦截弹窗,或点击「重新下载」。
|
||||
@ -185,4 +235,4 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user