优化界面

This commit is contained in:
我若为王 2024-12-05 18:19:22 +08:00
parent 0ff9a640ac
commit 6bffcde91f
3 changed files with 234 additions and 64 deletions

View File

@ -9,7 +9,7 @@
# Docker部署教程
```
docker run -d -p 3000:3000 ghcr.io/ilay1678/alipan-tv-token:latest
docker run --name=alipan-tv-token -d -p 3000:3000 ghcr.io/ilay1678/alipan-tv-token:latest
```
# vercel部署

View File

@ -31,3 +31,41 @@ body {
text-wrap: balance;
}
}
@keyframes fade-in {
from {
opacity: 0;
transform: translate(-50%, -20px);
}
to {
opacity: 1;
transform: translate(-50%, 0);
}
}
.animate-fade-in {
animation: fade-in 0.3s ease-out forwards;
}
@keyframes fade-in-out {
0% {
opacity: 0;
transform: translate(-50%, -20px);
}
10% {
opacity: 1;
transform: translate(-50%, 0);
}
90% {
opacity: 1;
transform: translate(-50%, 0);
}
100% {
opacity: 0;
transform: translate(-50%, -20px);
}
}
.animate-fade-in-out {
animation: fade-in-out 3s ease-out forwards;
}

View File

@ -1,22 +1,33 @@
'use client'
import { useEffect, useState, useRef } from 'react'
import ClipboardJS from 'clipboard';
export default function Home() {
// 添加状态变量
const [alertMsg, setAlertMsg] = useState('');
const [alertType, setAlertType] = useState('success'); // 可选值:'success''error'
const hasGenerated = useRef(false); // 新增
const [qrCodeSrc, setQrCodeSrc] = useState(''); // 新增,初始为空表示未加载
import ClipboardJS from 'clipboard'
async function generateQR() {
const response = await fetch("/generate_qr", {
method: "POST",
});
const data = await response.json();
// 更新二维码图片的 src
setQrCodeSrc(data.qr_link);
checkStatus(data.sid);
export default function Home() {
const [alertMsg, setAlertMsg] = useState('')
const [alertType, setAlertType] = useState('success')
const hasGenerated = useRef(false)
const [authUrl, setAuthUrl] = useState('') // 新增授权URL状态
const [isLoading, setIsLoading] = useState(true) // 新增加载状态
const [hasAccessToken, setHasAccessToken] = useState(false)
const [hasRefreshToken, setHasRefreshToken] = useState(false)
const [authorizing, setAuthorizing] = useState(false) // 新增授权中状态
const [showNotice, setShowNotice] = useState(true) // 新增弹窗控制状态
async function generateAuthUrl() {
try {
setIsLoading(true)
const response = await fetch("/generate_qr", {
method: "POST",
});
const data = await response.json();
// 生成授权URL
const url = `https://www.alipan.com/o/oauth/authorize?sid=${data.sid}`
setAuthUrl(url);
checkStatus(data.sid);
} finally {
setIsLoading(false)
}
}
async function checkStatus(sid) {
@ -24,19 +35,17 @@ export default function Home() {
const response = await fetch("/check_status/" + sid);
const data = await response.json();
if (data.status === "LoginSuccess") {
document.querySelector("h1").innerText = "获取成功";
document.getElementById("accessToken").value = data.access_token;
document.getElementById("refreshToken").value = data.refresh_token;
document.getElementById("tokens").style.display = "block";
document.getElementById("qrCodeContainer").style.display = "none";
document.getElementById("authSection").style.visibility = "hidden"; // 改为隐藏而不是display:none
setHasAccessToken(!!data.access_token)
setHasRefreshToken(!!data.refresh_token)
// 初始化复制功能
initializeClipboard();
} else if (data.status === "ScanSuccess") {
document.querySelector("h1").innerText = "扫码成功,等待手机端授权";
// 继续轮询
setTimeout(() => checkStatus(sid), 2000);
} else if (data.status === "LoginFailed") {
document.querySelector("h1").innerText = "登录失败,请刷新页面重试";
setAlertMsg("登录失败,请刷新页面重试");
setAlertType('error');
location.reload();
@ -75,61 +84,184 @@ export default function Home() {
});
}
// 新增处理点击授权的函数
const handleAuth = (url) => {
setAuthorizing(true)
window.open(url, '_blank')
}
useEffect(() => {
if (!hasGenerated.current) {
generateQR();
generateAuthUrl();
hasGenerated.current = true;
}
}, []); // 依赖项为空数组
}, []);
// 添加消息自动清除的 Effect
useEffect(() => {
if (alertMsg) {
const timer = setTimeout(() => {
setAlertMsg('');
}, 3000);
return () => clearTimeout(timer);
}
}, [alertMsg]);
return (
<main className="flex min-h-screen flex-col items-center justify-center bg-gray-100">
{/* 添加卡片容器 */}
<div className="bg-white shadow-lg rounded-lg p-8">
{/* 提示组件 */}
{alertMsg && (
<div className={`mb-4 p-4 text-white rounded ${alertType === 'success' ? 'bg-green-500' : 'bg-red-500'}`}>
<>
{showNotice && (
<div className="fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
<div className="bg-white rounded-lg max-w-md w-full p-6 space-y-4">
<h2 className="text-xl font-bold text-gray-800">使用须知</h2>
<p className="text-gray-600 text-sm leading-relaxed">
本工具能帮助你一键获取阿里云盘TV版的刷新令牌完全免费TV接口能绕过三方应用权益包的速率限制但前提你得是SVIP
</p>
<div className="flex justify-center pt-2">
<button
onClick={() => setShowNotice(false)}
className="min-w-[120px] bg-blue-500 text-white py-2 px-6 rounded hover:bg-blue-600 transition-colors"
>
知道了
</button>
</div>
</div>
</div>
)}
{alertMsg && (
<div className="fixed top-4 left-1/2 transform -translate-x-1/2 z-50 w-auto min-w-[200px] max-w-[90%] animate-fade-in-out">
<div className={`px-6 py-3 rounded-lg shadow-lg text-white text-center ${
alertType === 'success' ? 'bg-green-500' : 'bg-red-500'
}`}>
{alertMsg}
</div>
)}
<h1 className="text-2xl font-bold text-gray-800 mb-6 text-center">扫描二维码登录</h1>
<div id="qrCodeContainer" className="flex justify-center mb-6">
{qrCodeSrc ? (
<img
id="qrCode"
src={qrCodeSrc}
alt="二维码"
className="w-64 h-64" // 设置固定宽高,与占位符一致
/>
) : (
<div className="w-64 h-64 flex items-center justify-center bg-gray-200">
<span className="text-gray-500">二维码加载中...</span>
</div>
)}
</div>
<div id="tokens" className="hidden">
<div className="mb-4">
<label htmlFor="accessToken" className="block text-gray-700 font-medium mb-2">访问令牌:</label>
<div className="flex">
<input type="text" id="accessToken" className="flex-1 p-2 border border-gray-300 rounded-l" readOnly />
<button data-clipboard-target="#accessToken"
className="px-4 bg-blue-500 text-white rounded-r hover:bg-blue-600">
复制
</button>
</div>
)}
<main className="flex min-h-screen flex-col items-center justify-center bg-gray-100 p-4">
<div className="bg-white shadow-lg rounded-lg p-8 w-full max-w-3xl">
<div className="flex justify-between items-center mb-6">
<h1 className="text-2xl font-bold text-gray-800">阿里云盘连接</h1>
{/* 将 Docker 标移到这里 */}
<a
href="https://ghcr.io/ilay1678/alipan-tv-token"
target="_blank"
rel="noopener noreferrer"
className="text-gray-600 hover:text-blue-500 transition-colors"
title="Docker Image"
>
<svg className="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 className="mb-4">
<label htmlFor="refreshToken" className="block text-gray-700 font-medium mb-2">刷新令牌:</label>
<div className="flex">
<input type="text" id="refreshToken" className="flex-1 p-2 border border-gray-300 rounded-l" readOnly />
<button data-clipboard-target="#refreshToken"
className="px-4 bg-blue-500 text-white rounded-r hover:bg-blue-600">
复制
</button>
<div className="space-y-8">
<div className="space-y-2">
<div className="relative">
<textarea
id="accessToken"
className="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"
className={`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'
}`}
title="复制访问令牌"
disabled={!hasAccessToken}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={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 className="space-y-2">
<div className="relative">
<textarea
id="refreshToken"
className="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"
className={`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'
}`}
title="复制刷新令牌"
disabled={!hasRefreshToken}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={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" className="h-[52px]"> {/* 固定高度 */}
{isLoading ? (
<div className="flex justify-center items-center h-full">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
<span className="ml-3 text-gray-600">正在获取授权链接...</span>
</div>
) : authUrl && (
<button
onClick={() => handleAuth(authUrl)}
disabled={authorizing}
className={`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'}`}
>
{authorizing ? (
<div className="flex items-center justify-center">
<div className="animate-spin rounded-full h-5 w-5 border-2 border-white border-t-transparent mr-2"></div>
授权中...
</div>
) : (
<div className="flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={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>
授权登录
</div>
)}
</button>
)}
</div>
</div>
</div>
</div>
</main>
</main>
</>
)
}