All checks were successful
site-dist-deploy / build-and-deploy (push) Successful in 1m8s
291 lines
8.5 KiB
Vue
291 lines
8.5 KiB
Vue
<template>
|
||
<div class="font-sans text-white">
|
||
<div class="flex flex-col gap-[10px]">
|
||
<div
|
||
v-for="item in downloadMethods"
|
||
:key="item.id"
|
||
@click="toggle(item.id)"
|
||
class="group relative flex flex-col rounded-[30px] border-[4px] border-white bg-black pt-4 pb-2 transition-all md:pb-6"
|
||
>
|
||
<div class="px-4 md:pl-[42px]">
|
||
<div
|
||
class="flex flex-wrap items-center gap-x-2 text-sm leading-tight font-bold md:text-2xl"
|
||
>
|
||
<StartIcon v-if="item.isHot" class="size-[20px] md:size-[30px]" />
|
||
<span>{{ item.title }}</span>
|
||
|
||
<span v-if="item.subtitle" class="font-medium">——{{ item.subtitle }}</span>
|
||
|
||
<span v-if="item.highlight" class="font-black text-[#FF00FF]"
|
||
>——{{ item.highlight }}</span
|
||
>
|
||
</div>
|
||
|
||
<!-- 打开按钮 -->
|
||
<div
|
||
class="flex items-center justify-end gap-1.5 self-end text-sm font-bold group-hover:opacity-100"
|
||
>
|
||
<div
|
||
v-show="activeId !== item.id"
|
||
class="mt-[16px] flex items-center gap-[10px] md:mt-[60px] md:text-xl"
|
||
>
|
||
<span class="tracking-tight">点击展开详情</span>
|
||
<ArrowIcon class="size-[12px] md:size-[18px]" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="activeId === item.id" class="px-2 md:pt-8">
|
||
<div
|
||
class="animate-in fade-in zoom-in-95 border-t-2 border-white pt-[10px] text-[15px] leading-relaxed duration-200 md:pt-[20px]"
|
||
>
|
||
<!-- 内容区域 (点击图片不收起,只有特定的关闭按钮收起) -->
|
||
<div class="relative px-2" @click.stop>
|
||
<div
|
||
class="flex items-center justify-end gap-1.5 self-end text-sm font-bold group-hover:opacity-100 md:text-xl"
|
||
>
|
||
<div class="relative z-10 flex items-center gap-[10px]" @click="toggle(item.id)">
|
||
<span class="tracking-tight">点击收起</span>
|
||
<ArrowIcon class="size-[12px] rotate-180 md:size-[22px]" />
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Mobile Image Stack -->
|
||
<div class="relative -mt-10 flex flex-col md:hidden">
|
||
<img
|
||
v-for="(img, idx) in item.mobileImages"
|
||
:key="idx"
|
||
:src="img"
|
||
class="w-full"
|
||
alt="mobile guide"
|
||
/>
|
||
<!-- Mobile Hot Zones -->
|
||
<div
|
||
v-for="(hz, hzIdx) in item.mobileHotzones"
|
||
:key="hzIdx"
|
||
class="absolute z-20 cursor-pointer"
|
||
:style="{
|
||
left: hz.x + 'px',
|
||
top: hz.y + 'px',
|
||
width: hz.w + 'px',
|
||
height: hz.h + 'px',
|
||
}"
|
||
@click="handleHotzone(hz)"
|
||
></div>
|
||
</div>
|
||
|
||
<!-- PC Image Stack -->
|
||
<div class="relative mt-4 hidden flex-col md:flex">
|
||
<img
|
||
v-for="(img, idx) in item.pcImages"
|
||
:key="idx"
|
||
:src="img"
|
||
class="w-full"
|
||
alt="pc guide"
|
||
/>
|
||
<!-- PC Hot Zones -->
|
||
<div
|
||
v-for="(hz, hzIdx) in item.pcHotzones"
|
||
:key="hzIdx"
|
||
class="absolute z-20 cursor-pointer"
|
||
:style="{
|
||
left: hz.x + 'px',
|
||
top: hz.y + 'px',
|
||
width: hz.w + 'px',
|
||
height: hz.h + 'px',
|
||
}"
|
||
@click="handleHotzone(hz)"
|
||
>
|
||
<span class="text-xs font-bold text-black" v-if="hz.type === 'text'">{{
|
||
hz.payload
|
||
}}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 底部收起按钮 -->
|
||
<div class="absolute right-4 bottom-4 z-10">
|
||
<div @click="toggle(item.id)" class="h-[30px] w-[200px]"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed } from 'vue'
|
||
import ArrowIcon from './arrow-icon.svg?component'
|
||
import StartIcon from './Star-1.svg?component'
|
||
import { toast } from 'vue-sonner'
|
||
|
||
// Sliced WebP Images
|
||
// Method 1
|
||
import m1_1 from './mobile1/row-1-column-1.webp'
|
||
import m1_2 from './mobile1/row-2-column-1.webp'
|
||
import m1_3 from './mobile1/row-3-column-1.webp'
|
||
import pc1_1 from './pc1/row-1-column-1.webp'
|
||
import pc1_2 from './pc1/row-2-column-1.webp'
|
||
import pc1_3 from './pc1/row-3-column-1.webp'
|
||
|
||
// Method 2
|
||
import m2_1 from './mobile2/row-1-column-1.webp'
|
||
import m2_2 from './mobile2/row-2-column-1.webp'
|
||
import m2_3 from './mobile2/row-3-column-1.webp'
|
||
import pc2_1 from './pc2/row-1-column-1.webp'
|
||
import pc2_2 from './pc2/row-2-column-1.webp'
|
||
import pc2_3 from './pc2/row-3-column-1.webp'
|
||
|
||
// Method 3
|
||
import m3_1 from './mobile3/row-1-column-1.webp'
|
||
import m3_2 from './mobile3/row-2-column-1.webp'
|
||
import m3_3 from './mobile3/row-3-column-1.webp'
|
||
import pc3_1 from './pc3/row-1-column-1.webp'
|
||
import pc3_2 from './pc3/row-2-column-1.webp'
|
||
import pc3_3 from './pc3/row-3-column-1.webp'
|
||
|
||
interface Hotzone {
|
||
x: number
|
||
y: number
|
||
w: number
|
||
h: number
|
||
type: 'copy' | 'link'
|
||
payload: string
|
||
label?: string
|
||
}
|
||
const accounts = [
|
||
{ account: 'prla08741@gmx.com', password: 'Qw990088' },
|
||
{ account: 'guazhexing721@gmx.com', password: 'Qw990088' },
|
||
]
|
||
const selectedIndex = ref(0) // 直接在内部定义数据
|
||
const downloadMethods = computed(() => {
|
||
const account = accounts[selectedIndex.value]
|
||
return [
|
||
{
|
||
id: 1,
|
||
title: '创建新“香港Apple ID”',
|
||
subtitle: '首推',
|
||
isHot: true,
|
||
highlight: '',
|
||
mobileImages: [m1_1, m1_2, m1_3],
|
||
pcImages: [pc1_1, pc1_2, pc1_3],
|
||
mobileHotzones: [] as Hotzone[],
|
||
pcHotzones: [
|
||
{
|
||
x: 410,
|
||
y: 224,
|
||
w: 140,
|
||
h: 20,
|
||
type: 'link',
|
||
payload: 'https://account.apple.com/account',
|
||
},
|
||
] as Hotzone[],
|
||
},
|
||
{
|
||
id: 2,
|
||
title: '修改已有 Apple ID 至 <香港>',
|
||
subtitle: '',
|
||
isHot: false,
|
||
highlight: '',
|
||
mobileImages: [m2_1, m2_2, m2_3],
|
||
pcImages: [pc2_1, pc2_2, pc2_3],
|
||
mobileHotzones: [] as Hotzone[],
|
||
pcHotzones: [
|
||
{
|
||
x: 410,
|
||
y: 224,
|
||
w: 140,
|
||
h: 20,
|
||
type: 'link',
|
||
payload: 'https://account.apple.com',
|
||
},
|
||
] as Hotzone[],
|
||
},
|
||
{
|
||
id: 3,
|
||
title: '使用Hi快提供的公用账号',
|
||
subtitle: '',
|
||
isHot: false,
|
||
highlight: '谨慎选择',
|
||
mobileImages: [m3_1, m3_2, m3_3],
|
||
pcImages: [pc3_1, pc3_2, pc3_3],
|
||
mobileHotzones: [] as Hotzone[],
|
||
pcHotzones: [
|
||
{
|
||
x: 103,
|
||
y: 1426,
|
||
w: 140,
|
||
h: 20,
|
||
type: 'text', // 展示账号文字
|
||
payload: account.account,
|
||
},
|
||
{
|
||
x: 103,
|
||
y: 1463,
|
||
w: 140,
|
||
h: 20,
|
||
type: 'text', // 展示密码文字
|
||
payload: account.password,
|
||
},
|
||
{
|
||
x: 103,
|
||
y: 1414,
|
||
w: 194,
|
||
h: 34,
|
||
type: 'copy',
|
||
payload: account.account,
|
||
label: '账号', // account
|
||
},
|
||
{
|
||
x: 103,
|
||
y: 1451,
|
||
w: 194,
|
||
h: 34,
|
||
type: 'copy',
|
||
payload: account.password,
|
||
label: '密码', // 复制提示
|
||
},
|
||
] as Hotzone[],
|
||
},
|
||
]
|
||
})
|
||
|
||
const activeId = ref<number | null>(null)
|
||
|
||
const toggle = (id: number) => {
|
||
if (activeId.value === id) {
|
||
activeId.value = null
|
||
} else {
|
||
activeId.value = id
|
||
|
||
// 重点:当点开 ID 为 3 的面板时,随机切换账号索引
|
||
if (id === 3) {
|
||
// 生成一个与当前不同的随机数,或者纯随机
|
||
selectedIndex.value = selectedIndex.value === 0 ? 1 : 0
|
||
}
|
||
}
|
||
}
|
||
|
||
const handleHotzone = (hz: Hotzone) => {
|
||
if (hz.type === 'copy') {
|
||
navigator.clipboard.writeText(hz.payload)
|
||
toast.success(`${hz.label || '内容'}已复制`)
|
||
} else if (hz.type === 'link') {
|
||
window.open(hz.payload, '_blank')
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 针对整体风格进行微调 */
|
||
.font-bold {
|
||
letter-spacing: -0.02em;
|
||
}
|
||
|
||
/* 移除移动端点击的高亮蓝色框 */
|
||
div {
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
</style>
|