i-tools/pages/index.vue
2024-12-06 03:20:18 +08:00

206 lines
9.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<main class="min-h-screen bg-gray-100 p-4">
<div class="mx-auto w-full max-w-3xl bg-white shadow-lg rounded-lg p-8">
<div class="flex justify-between items-center mb-6">
<h1 class="text-2xl font-bold text-gray-800">阿里云盘连接</h1>
<a href="https://ghcr.io/ilay1678/alipan-tv-token"
target="_blank"
rel="noopener noreferrer"
class="text-gray-600 hover:text-blue-500 transition-colors"
title="Docker Image">
<svg class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor">
<path d="M13.983 11.078h2.119a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.119a.185.185 0 00-.185.185v1.888c0 .102.083.185.185.185m-2.954-5.43h2.118a.186.186 0 00.186-.186V3.574a.186.186 0 00-.186-.185h-2.118a.185.185 0 00-.185.185v1.888c0 .102.082.185.185.185m0 2.716h2.118a.187.187 0 00.186-.186V6.29a.186.186 0 00-.186-.185h-2.118a.185.185 0 00-.185.185v1.887c0 .102.082.185.185.186m-2.93 0h2.12a.186.186 0 00.184-.186V6.29a.185.185 0 00-.185-.185H8.1a.185.185 0 00-.185.185v1.887c0 .102.083.185.185.186m-2.964 0h2.119a.186.186 0 00.185-.186V6.29a.185.185 0 00-.185-.185H5.136a.186.186 0 00-.186.185v1.887c0 .102.084.185.186.186m5.893 2.715h2.118a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.118a.185.185 0 00-.185.185v1.888c0 .102.082.185.185.185m-2.93 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.185v1.888c0 .102.083.185.185.185m-2.964 0h2.119a.185.185 0 00.185-.185V9.006a.185.185 0 00-.184-.186h-2.12a.186.186 0 00-.186.186v1.887c0 .102.084.185.186.185m-2.92 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.185v1.888c0 .102.082.185.185.185M23.763 9.89c-.065-.051-.672-.51-1.954-.51-.338.001-.676.03-1.01.087-.248-1.7-1.653-2.53-1.716-2.566l-.344-.199-.226.327c-.284.438-.49.922-.612 1.43-.23.97-.09 1.882.403 2.661-.595.332-1.55.413-1.744.42H.751a.751.751 0 00-.75.748 11.376 11.376 0 00.692 4.062c.545 1.428 1.355 2.48 2.41 3.124 1.18.723 3.1 1.137 5.275 1.137.983.003 1.963-.086 2.93-.266a12.248 12.248 0 003.823-1.389c.98-.567 1.86-1.288 2.61-2.136 1.252-1.418 1.998-2.997 2.553-4.4h.221c1.372 0 2.215-.549 2.68-1.009.309-.293.55-.65.707-1.046l.098-.288z"/>
</svg>
</a>
</div>
<div class="space-y-8">
<div class="space-y-2">
<div class="relative">
<textarea
id="accessToken"
v-model="accessToken"
class="w-full rounded font-mono text-sm leading-normal border-2 border-dashed border-gray-300 p-3 pr-10 bg-white resize-none focus:outline-none focus:border-blue-500 transition-colors min-h-[120px] whitespace-pre-wrap overflow-auto placeholder:text-gray-400"
readonly
spellcheck="false"
placeholder="访问令牌"
/>
<button
data-clipboard-target="#accessToken"
:class="`absolute top-2 right-2 p-1 rounded transition-colors ${
hasAccessToken
? 'hover:bg-gray-100 text-gray-500 hover:text-blue-500'
: 'text-gray-300 cursor-not-allowed'
}`"
:disabled="!hasAccessToken"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
</button>
</div>
</div>
<div class="space-y-2">
<div class="relative">
<textarea
id="refreshToken"
v-model="refreshToken"
class="w-full rounded font-mono text-sm leading-normal border-2 border-dashed border-gray-300 p-3 pr-10 bg-white resize-none focus:outline-none focus:border-blue-500 transition-colors min-h-[120px] whitespace-pre-wrap overflow-auto placeholder:text-gray-400"
readonly
spellcheck="false"
placeholder="刷新令牌"
/>
<button
data-clipboard-target="#refreshToken"
:class="`absolute top-2 right-2 p-1 rounded transition-colors ${
hasRefreshToken
? 'hover:bg-gray-100 text-gray-500 hover:text-blue-500'
: 'text-gray-300 cursor-not-allowed'
}`"
:disabled="!hasRefreshToken"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
</button>
</div>
</div>
<div id="authSection" class="h-[52px]">
<div v-if="isLoading" class="flex justify-center items-center h-full">
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
<span class="ml-3 text-gray-600">正在获取授权链接...</span>
</div>
<button
v-else
@click="handleAuth(authUrl)"
:disabled="authorizing"
:class="`block w-full bg-blue-500 text-white text-center py-3 px-4 rounded transition-colors relative ${
authorizing ? 'bg-blue-400 cursor-not-allowed' : 'hover:bg-blue-600'
}`"
>
<div class="flex items-center justify-center">
<div v-if="authorizing" class="animate-spin rounded-full h-5 w-5 border-2 border-white border-t-transparent mr-2"></div>
<svg v-else xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
</svg>
{{ authorizing ? '授权中...' : '授权登录' }}
</div>
</button>
</div>
</div>
</div>
</main>
<a-modal
v-model:visible="isNoticeOpen"
title="使用说明"
@ok="closeNotice"
:maskClosable="false"
:closable="false"
:keyboard="false"
>
<p>本工具能帮助你一键获取阿里云盘TV版的刷新令牌完全免费TV接口能绕过三方应用权益包的速率限制但前提你得是SVIP</p>
<template #footer>
<a-button type="primary" @click="closeNotice">我知道了</a-button>
</template>
</a-modal>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue'
import { message } from 'ant-design-vue'
import ClipboardJS from 'clipboard'
const hasGenerated = ref(false)
const authUrl = ref('')
const isLoading = ref(true)
const hasAccessToken = ref(false)
const hasRefreshToken = ref(false)
const authorizing = ref(false)
const isNoticeOpen = ref(false) // 将 showNotice 改为 isNoticeOpen
const accessToken = ref('')
const refreshToken = ref('')
async function generateAuthUrl() {
try {
isLoading.value = true
const response = await fetch("/generate_qr", { method: "POST" })
const data = await response.json()
authUrl.value = `https://www.alipan.com/o/oauth/authorize?sid=${data.sid}`
checkStatus(data.sid)
} finally {
isLoading.value = false
}
}
function closeNotice() {
isNoticeOpen.value = false
}
async function checkStatus(sid) {
try {
const response = await fetch("/check_status/" + sid)
const data = await response.json()
if (data.status === "LoginSuccess") {
accessToken.value = data.access_token
refreshToken.value = data.refresh_token
document.getElementById("authSection").style.visibility = "hidden"
hasAccessToken.value = !!data.access_token
hasRefreshToken.value = !!data.refresh_token
message.success('登录成功')
initializeClipboard() // 在 token 设置后初始化 ClipboardJS
} else if (data.status === "ScanSuccess") {
setTimeout(() => checkStatus(sid), 2000)
} else if (data.status === "LoginFailed") {
message.error('登录失败,请刷新页面重试')
location.reload()
} else {
setTimeout(() => checkStatus(sid), 2000)
}
} catch (error) {
console.error("检查状态时出错:", error)
message.error('发生错误,请稍后重试')
}
}
// 初始化 ClipboardJS
function initializeClipboard() {
const accessTokenClipboard = new ClipboardJS('[data-clipboard-target="#accessToken"]')
accessTokenClipboard.on('success', () => {
message.success('已复制访问令牌')
})
accessTokenClipboard.on('error', () => {
message.error('复制失败')
})
const refreshTokenClipboard = new ClipboardJS('[data-clipboard-target="#refreshToken"]')
refreshTokenClipboard.on('success', () => {
message.success('已复制刷新令牌')
})
refreshTokenClipboard.on('error', () => {
message.error('复制失败')
})
}
const handleAuth = (url) => {
authorizing.value = true
window.open(url, '_blank')
}
onMounted(() => {
if (!hasGenerated.value) {
generateAuthUrl()
hasGenerated.value = true
isNoticeOpen.value = true
}
})
watch()
</script>
<style scoped>
</style>