mirror of
https://github.com/NeteaseCloudMusicApiEnhanced/api-enhanced.git
synced 2026-08-12 08:50:38 +00:00
241 lines
6.7 KiB
HTML
241 lines
6.7 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh">
|
|
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<link rel="icon" href="docs/netease.png" />
|
|
<link rel="stylesheet" href="/static/shell.css" />
|
|
<title>更新头像</title>
|
|
<style>
|
|
body {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 1.25rem;
|
|
}
|
|
.shell-header { text-align: center; }
|
|
.avatar-wrapper {
|
|
position: relative;
|
|
width: 160px;
|
|
height: 160px;
|
|
margin: 0 auto 2rem;
|
|
}
|
|
.avatar {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 9999px;
|
|
object-fit: cover;
|
|
border: 3px solid var(--gray-5);
|
|
background: var(--gray-4);
|
|
}
|
|
.avatar-wrapper.loading .avatar { opacity: 0.5; }
|
|
.loading-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 9999px;
|
|
background: color-mix(in srgb, var(--background) 90%, transparent);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
opacity: 0;
|
|
transition: opacity 0.2s ease;
|
|
pointer-events: none;
|
|
}
|
|
.avatar-wrapper.loading .loading-overlay { opacity: 1; }
|
|
.spinner {
|
|
width: 2.5rem;
|
|
height: 2.5rem;
|
|
border: 3px solid var(--gray-4);
|
|
border-top-color: var(--foreground);
|
|
border-radius: 9999px;
|
|
animation: spin 0.8s linear infinite;
|
|
}
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
.upload-btn {
|
|
display: inline-block;
|
|
position: relative;
|
|
padding: 0.75rem 1.75rem;
|
|
background: var(--primary);
|
|
color: var(--primary-foreground);
|
|
font-family: var(--font-mono);
|
|
font-size: 0.9375rem;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: opacity var(--transition);
|
|
border: none;
|
|
}
|
|
.upload-btn:hover { opacity: 0.85; }
|
|
.upload-btn input[type="file"] {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
opacity: 0;
|
|
cursor: pointer;
|
|
}
|
|
.hint {
|
|
margin-top: 1.25rem;
|
|
font-size: 0.75rem;
|
|
color: var(--muted-foreground);
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div class="shell-card shell-container shell-narrow" style="text-align:center;padding:2.5rem">
|
|
<header class="shell-header">
|
|
<h1>更新头像</h1>
|
|
<p class="sub">选择一张图片作为您的新头像</p>
|
|
</header>
|
|
|
|
<div class="avatar-wrapper" id="avatarWrapper">
|
|
<img id="avatar" class="avatar" src="" alt="头像" />
|
|
<div class="loading-overlay">
|
|
<div class="spinner"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="shell-flex shell-flex--center">
|
|
<label class="upload-btn">
|
|
选择图片
|
|
<input id="file" type="file" accept="image/*" />
|
|
</label>
|
|
</div>
|
|
|
|
<div class="shell-flex shell-flex--center shell-mt-4">
|
|
<a class="shell-btn shell-btn--ghost shell-btn--sm" href="/qrlogin-nocookie.html">
|
|
还没有登录?点击登录
|
|
</a>
|
|
</div>
|
|
|
|
<p class="hint">支持 JPG、PNG 格式,建议尺寸 200x200</p>
|
|
|
|
<div class="shell-flex shell-flex--center shell-mt-4">
|
|
<a class="shell-btn shell-btn--outline shell-btn--sm" href="/">返回首页</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="toast" class="toast"></div>
|
|
|
|
<script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script>
|
|
<script>
|
|
main()
|
|
|
|
async function main() {
|
|
const fileInput = document.querySelector('input[type="file"]');
|
|
const avatarWrapper = document.getElementById('avatarWrapper');
|
|
|
|
fileInput.addEventListener('change', function(e) {
|
|
const file = this.files[0];
|
|
if (file) {
|
|
upload(file);
|
|
}
|
|
}, false);
|
|
|
|
try {
|
|
showToast('正在加载头像...', 'info');
|
|
avatarWrapper.classList.add('loading');
|
|
const res = await axios({
|
|
url: `/user/detail?uid=32953014×tamp=${Date.now()}`,
|
|
withCredentials: true
|
|
});
|
|
document.querySelector('#avatar').src = res.data.profile.avatarUrl;
|
|
hideToast();
|
|
} catch (error) {
|
|
hideToast();
|
|
showToast('加载头像失败,请刷新页面重试', 'error');
|
|
console.error('加载头像失败:', error);
|
|
} finally {
|
|
avatarWrapper.classList.remove('loading');
|
|
}
|
|
}
|
|
|
|
async function upload(file) {
|
|
const avatarWrapper = document.getElementById('avatarWrapper');
|
|
|
|
if (!file.type.startsWith('image/')) {
|
|
showToast('请选择图片文件', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
showToast('正在上传头像...', 'info');
|
|
avatarWrapper.classList.add('loading');
|
|
|
|
var formData = new FormData();
|
|
formData.append('imgFile', file);
|
|
const imgSize = await getImgSize(file);
|
|
|
|
const res = await axios({
|
|
method: 'post',
|
|
url: `/avatar/upload?cookie=${localStorage.getItem('cookie')}&imgSize=${imgSize.width}&imgX=0&imgY=0×tamp=${Date.now()}`,
|
|
headers: {
|
|
'Content-Type': 'multipart/form-data',
|
|
},
|
|
data: formData,
|
|
});
|
|
|
|
document.querySelector('#avatar').src = res.data.data.url;
|
|
showToast('头像更新成功!', 'success');
|
|
} catch (error) {
|
|
console.error('上传失败:', error);
|
|
const errorMsg = error.response?.data?.message || error.message || '上传失败,请重试';
|
|
showToast(errorMsg, 'error');
|
|
} finally {
|
|
avatarWrapper.classList.remove('loading');
|
|
}
|
|
}
|
|
|
|
function getImgSize(file) {
|
|
return new Promise((resolve, reject) => {
|
|
let reader = new FileReader();
|
|
reader.readAsDataURL(file);
|
|
reader.onload = function(theFile) {
|
|
let image = new Image();
|
|
image.src = theFile.target.result;
|
|
image.onload = function() {
|
|
resolve({
|
|
width: this.width,
|
|
height: this.height,
|
|
});
|
|
};
|
|
image.onerror = function() {
|
|
reject(new Error('图片加载失败'));
|
|
};
|
|
};
|
|
reader.onerror = function() {
|
|
reject(new Error('文件读取失败'));
|
|
};
|
|
});
|
|
}
|
|
|
|
function showToast(message, type = 'info') {
|
|
const toast = document.getElementById('toast');
|
|
toast.textContent = message;
|
|
toast.className = `toast ${type}`;
|
|
|
|
requestAnimationFrame(() => {
|
|
toast.classList.add('show');
|
|
});
|
|
|
|
setTimeout(() => {
|
|
toast.classList.remove('show');
|
|
}, 3000);
|
|
}
|
|
|
|
function hideToast() {
|
|
const toast = document.getElementById('toast');
|
|
toast.classList.remove('show');
|
|
}
|
|
</script>
|
|
</body>
|
|
|
|
</html>
|