Files
ns2.0/templates/wishlist.html

1069 lines
24 KiB
HTML
Executable File
Raw Permalink 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.

{% extends "base.html" %}
{% block head %}
<!-- 引入 QRCode.js -->
<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script>
{% endblock %}
{% block content %}
<div class="coming-apps-page">
<div class="header">
<a href="{{ url_for('more') }}" class="back-link" title="返回">
<i class="fas fa-arrow-left"></i>
</a>
<h1>心愿单</h1>
<button class="add-btn" onclick="showAddDialog()">
<i class="fas fa-plus"></i>
</button>
</div>
<!-- 添加提示消息 -->
<div id="toast" class="developing-tip">
<span id="toastMessage"></span>
</div>
<div class="wishlist-container">
<!-- 添加排行榜链接 -->
<div class="leaderboard-section">
<a href="{{ url_for('invite_leaderboard') }}" class="leaderboard-link">
<i class="fas fa-trophy"></i>
邀请排行榜
</a>
</div>
<!-- 添加邮件通知提示 -->
<div class="notification-tip">
<div class="tip-content">
<i class="fas fa-envelope"></i>
<span>
{% if session.huawei_user.email %}
应用上架后将通过邮箱 {{ session.huawei_user.email }} 通知您
{% else %}
绑定邮箱后可以收到应用上架通知
<button class="bind-email-btn" onclick="window.location.href='{{ url_for('user_profile') }}'">
去绑定
</button>
{% endif %}
</span>
</div>
</div>
<!-- 添加邀请提示 -->
<div class="notification-tip invite-tip">
<div class="tip-content">
<i class="fas fa-gift"></i>
<span>
{% if session.huawei_user.unlocked_features %}
您已成功邀请3位好友已解锁20个心愿单名额
{% else %}
邀请3位好友使用即可解锁20个心愿单名额已邀请 <span id="inviteCount">0</span>/3 位)
{% endif %}
<button class="invite-btn" onclick="showInviteDialog()">
立即邀请
</button>
</span>
</div>
</div>
<div id="wishlist-items">
<!-- 这里会通过 JavaScript 动态加载心愿单内容 -->
</div>
</div>
</div>
<!-- 添加应用弹窗 -->
<div id="addDialog" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>添加心愿应用</h3>
<button class="close-btn" onclick="closeDialog()">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-tip">
<i class="fas fa-exclamation-circle"></i>
<span>请正确输入应用名称,否则无法收到上架通知</span>
</div>
<input type="text"
id="appName"
class="app-input"
placeholder="输入应用名称"
maxlength="50">
<div class="modal-actions">
<button class="cancel-btn" onclick="closeDialog()">取消</button>
<button class="confirm-btn" onclick="addToWishlist()">添加</button>
</div>
</div>
</div>
<!-- 添加邀请弹窗 -->
<div id="inviteDialog" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>邀请好友</h3>
<button class="close-btn" onclick="closeInviteDialog()">
<i class="fas fa-times"></i>
</button>
</div>
<div class="invite-info">
<p>已邀请 <span id="inviteCount">0</span> 位好友</p>
<p>邀请链接:</p>
<div class="invite-link">
<input type="text" id="inviteUrl" readonly>
<button onclick="copyInviteUrl()">复制</button>
</div>
</div>
</div>
</div>
<style>
/* 使用与 coming 页面相同的 header 样式 */
.coming-apps-page {
max-width: 1200px;
margin: 0 auto;
padding: 20px 15px;
}
.header {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 30px;
background: white;
padding: 10px 15px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
}
.back-link {
color: #666;
text-decoration: none;
padding: 8px;
border-radius: 50%;
background: #f5f5f7;
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
}
.back-link:hover {
background: #e5e5e7;
color: #333;
}
.header h1 {
margin: 0;
font-size: 20px;
color: #333;
font-weight: 500;
flex: 1;
}
.add-btn {
padding: 8px;
border: none;
border-radius: 50%;
background: #f5f5f7;
color: #666;
cursor: pointer;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.add-btn:hover {
background: #e5e5e7;
color: #333;
}
.wishlist-container {
margin-top: 50px;
}
.wishlist-item {
background: white;
border-radius: 12px;
padding: 15px;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.wishlist-item-name {
font-size: 16px;
color: #333;
}
.delete-btn {
padding: 8px;
border: none;
background: transparent;
color: #ff4d4f;
cursor: pointer;
opacity: 1;
transition: opacity 0.3s ease;
border-radius: 50%;
}
.delete-btn:hover {
background: rgba(255, 77, 79, 0.1);
}
.empty-tip {
text-align: center;
color: #999;
padding: 30px;
background: white;
border-radius: 12px;
margin-top: 20px;
}
/* 暗色模式适配 */
[data-theme="dark"] .header {
background: #242424;
}
[data-theme="dark"] .header h1 {
color: #fff;
}
[data-theme="dark"] .back-link,
[data-theme="dark"] .add-btn {
background: #333;
color: #ccc;
}
[data-theme="dark"] .back-link:hover,
[data-theme="dark"] .add-btn:hover {
background: #444;
color: #fff;
}
[data-theme="dark"] .wishlist-item {
background: #242424;
}
[data-theme="dark"] .wishlist-item-name {
color: #fff;
}
[data-theme="dark"] .empty-tip {
background: #242424;
color: #666;
}
footer,
.footer {
display: none !important;
}
/* 弹窗样式优化 */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
align-items: center;
justify-content: center;
animation: modalFadeIn 0.3s ease;
}
.modal-content {
background: white;
border-radius: 16px;
padding: 20px;
max-width: 400px;
width: 90%;
position: relative;
}
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 15px;
}
.modal-header h3 {
margin: 0;
font-size: 18px;
font-weight: 500;
color: #333;
}
.close-btn {
padding: 8px;
border: none;
background: transparent;
color: #999;
cursor: pointer;
border-radius: 50%;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.close-btn:hover {
background: #f5f5f5;
color: #666;
}
.app-input {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 8px;
margin-bottom: 20px;
font-size: 14px;
transition: all 0.3s ease;
}
.app-input:focus {
border-color: #1890ff;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.1);
outline: none;
}
.modal-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
}
.cancel-btn,
.confirm-btn {
padding: 8px 20px;
border: none;
border-radius: 6px;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
}
.cancel-btn {
background: #f5f5f5;
color: #666;
}
.cancel-btn:hover {
background: #e8e8e8;
}
.confirm-btn {
background: #1890ff;
color: white;
}
.confirm-btn:hover {
background: #40a9ff;
}
@keyframes modalFadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes modalSlideIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 暗色模式适配 */
[data-theme="dark"] .modal-content {
background: #242424;
border: 1px solid #333;
}
[data-theme="dark"] .modal-header {
border-bottom-color: #333;
}
[data-theme="dark"] .modal-header h3 {
color: #fff;
}
[data-theme="dark"] .invite-info {
color: #ccc;
}
[data-theme="dark"] .invite-link {
background: #1a1a1a;
border-color: #333;
}
[data-theme="dark"] .invite-link input {
background: #1a1a1a;
color: #fff;
border-color: #333;
}
[data-theme="dark"] .invite-link button {
background: #333;
color: #fff;
border-color: #444;
}
[data-theme="dark"] .invite-link button:hover {
background: #444;
}
[data-theme="dark"] .invite-qrcode {
background: #1a1a1a;
border: 1px solid #333;
padding: 10px;
border-radius: 8px;
}
.invite-info {
text-align: center;
}
.invite-info p {
margin: 12px 0;
color: #666;
font-size: 14px;
}
.invite-link {
display: flex;
gap: 8px;
margin: 16px 0;
padding: 8px;
background: #f5f5f7;
border-radius: 8px;
border: 1px solid #eee;
}
.invite-link input {
flex: 1;
border: none;
background: transparent;
padding: 4px 8px;
font-size: 14px;
}
.invite-link button {
padding: 4px 12px;
border-radius: 4px;
border: 1px solid #ddd;
background: white;
color: #666;
cursor: pointer;
transition: all 0.3s ease;
}
.invite-link button:hover {
background: #f5f5f7;
color: #333;
}
.invite-qrcode {
width: 148px;
height: 148px;
margin: 20px auto;
background: white;
padding: 10px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.invite-qrcode img {
width: 100%;
height: 100%;
}
/* 邮件通知提示样式 */
.notification-tip {
background: rgba(24, 144, 255, 0.1);
border-radius: 12px;
padding: 15px;
margin-bottom: 20px;
}
.tip-content {
display: flex;
align-items: center;
gap: 12px;
color: #1890ff;
font-size: 14px;
}
.tip-content i {
font-size: 18px;
}
.bind-email-btn {
border: none;
background: #1890ff;
color: white;
padding: 4px 12px;
border-radius: 4px;
margin-left: 8px;
cursor: pointer;
font-size: 12px;
transition: all 0.3s ease;
}
.bind-email-btn:hover {
background: #40a9ff;
}
/* 暗色模式适配 */
[data-theme="dark"] .notification-tip {
background: rgba(24, 144, 255, 0.1);
}
[data-theme="dark"] .tip-content {
color: #40a9ff;
}
[data-theme="dark"] .bind-email-btn {
background: #1890ff;
}
[data-theme="dark"] .bind-email-btn:hover {
background: #40a9ff;
}
.modal-tip {
margin: 0 0 15px;
padding: 12px 15px;
background: #fff2f0;
border-radius: 8px;
color: #ff4d4f;
font-size: 14px;
display: flex;
align-items: center;
gap: 10px;
line-height: 1.4;
}
.modal-tip i {
font-size: 16px;
flex-shrink: 0;
}
/* 暗色模式适配 */
[data-theme="dark"] .modal-tip {
background: rgba(255, 77, 79, 0.1);
color: #ff7875;
}
/* 提示消息样式 */
.developing-tip {
position: fixed;
bottom: 100px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 10px 20px;
border-radius: 25px;
font-size: 14px;
z-index: 1000;
opacity: 0;
transition: opacity 0.3s ease, transform 0.3s ease;
pointer-events: none;
transform: translate(-50%, 20px);
}
[data-theme="dark"] .developing-tip {
background: rgba(255, 255, 255, 0.9);
color: black;
}
.developing-tip.show {
opacity: 1;
transform: translate(-50%, 0);
}
/* 添加动画效果 */
@keyframes tipAppear {
0% {
opacity: 0;
transform: translate(-50%, 20px);
}
20% {
opacity: 1;
transform: translate(-50%, 0);
}
80% {
opacity: 1;
transform: translate(-50%, 0);
}
100% {
opacity: 0;
transform: translate(-50%, -20px);
}
}
.developing-tip.show {
animation: tipAppear 2s ease forwards;
}
.item-actions {
display: flex;
align-items: center;
gap: 12px;
}
.notified-tag {
display: flex;
align-items: center;
gap: 4px;
padding: 4px 8px;
background: rgba(82, 196, 26, 0.1);
color: #52c41a;
border-radius: 4px;
font-size: 12px;
}
.notified-tag i {
font-size: 12px;
}
/* 暗色模式适配 */
[data-theme="dark"] .notified-tag {
background: rgba(82, 196, 26, 0.1);
color: #73d13d;
}
/* 添加最大数量限制提示样式 */
.limit-tip {
text-align: center;
color: #ff4d4f;
padding: 12px;
background: rgba(255, 77, 79, 0.1);
border-radius: 8px;
margin-top: 15px;
font-size: 14px;
}
/* 暗色模式适配 */
[data-theme="dark"] .limit-tip {
background: rgba(255, 77, 79, 0.1);
color: #ff7875;
}
/* 添加邀请相关样式 */
.invite-tip {
background: rgba(82, 196, 26, 0.1);
margin-top: 10px;
}
.invite-tip .tip-content {
color: #52c41a;
}
.invite-btn {
border: none;
background: #52c41a;
color: white;
padding: 4px 12px;
border-radius: 4px;
margin-left: 8px;
cursor: pointer;
font-size: 12px;
transition: all 0.3s ease;
}
.invite-btn:hover {
background: #73d13d;
}
.invite-info {
padding: 20px;
text-align: center;
}
.invite-link {
display: flex;
gap: 10px;
margin: 15px 0;
}
.invite-link input {
flex: 1;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.invite-link button {
padding: 8px 16px;
background: #1890ff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.invite-qrcode {
margin-top: 20px;
}
/* 暗色模式适配 */
[data-theme="dark"] .invite-tip {
background: rgba(82, 196, 26, 0.1);
}
[data-theme="dark"] .invite-tip .tip-content {
color: #73d13d;
}
[data-theme="dark"] .invite-link input {
background: #333;
border-color: #444;
color: #fff;
}
.leaderboard-link {
display: inline-flex;
align-items: center;
gap: 4px;
color: #52c41a;
text-decoration: none;
padding: 4px 12px;
border-radius: 4px;
background: rgba(82, 196, 26, 0.1);
transition: all 0.3s ease;
}
.leaderboard-link:hover {
background: rgba(82, 196, 26, 0.2);
}
[data-theme="dark"] .leaderboard-link {
color: #73d13d;
background: rgba(82, 196, 26, 0.2);
}
[data-theme="dark"] .leaderboard-link:hover {
background: rgba(82, 196, 26, 0.3);
}
/* 排行榜区域样式 */
.leaderboard-section {
margin-bottom: 15px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
overflow: hidden;
}
.leaderboard-section .leaderboard-link {
width: 100%;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
color: #6366f1;
text-decoration: none;
padding: 8px 16px;
border-radius: 8px;
background: rgba(99, 102, 241, 0.1);
transition: all 0.3s ease;
font-size: 14px;
box-sizing: border-box;
}
.leaderboard-section .leaderboard-link:hover {
background: rgba(99, 102, 241, 0.2);
}
[data-theme="dark"] .leaderboard-section .leaderboard-link {
color: #818cf8;
background: rgba(99, 102, 241, 0.2);
}
[data-theme="dark"] .leaderboard-section .leaderboard-link:hover {
background: rgba(99, 102, 241, 0.3);
}
</style>
<script>
// Toast 提示函数
function showToast(message) {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toastMessage');
toastMessage.textContent = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 2000);
}
// 加载心愿单
function loadWishlist() {
fetch('/user/wishlist/list')
.then(response => response.json())
.then(data => {
const container = document.getElementById('wishlist-items');
if (data.success) {
if (data.items.length === 0) {
container.innerHTML = `
<div class="empty-tip">
<i class="fas fa-inbox"></i>
<p>还没有添加任何应用</p>
</div>
`;
} else {
container.innerHTML = data.items.map(item => `
<div class="wishlist-item">
<div class="wishlist-item-name">${item.app_name}</div>
<div class="item-actions">
${item.notified ? `
<div class="notified-tag">
<i class="fas fa-check"></i>
已上架
</div>
` : ''}
<button class="delete-btn" onclick="deleteItem(${item.id})" title="删除">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
`).join('');
}
} else {
container.innerHTML = `
<div class="error-tip">
加载失败,请稍后重试
</div>
`;
}
})
.catch(error => {
console.error('Load wishlist failed:', error);
document.getElementById('wishlist-items').innerHTML = `
<div class="error-tip">
加载失败,请稍后重试
</div>
`;
});
}
// 显示添加弹窗
function showAddDialog() {
// 检查当前心愿单数量和限制
fetch('/user/wishlist/list')
.then(response => response.json())
.then(data => {
if (data.success) {
const limit = data.unlocked ? 20 : 5;
if (data.items.length >= limit) {
if (limit === 5) {
showToast('当前最多添加5个应用邀请3位好友可提升至20个');
} else {
showToast('已达到心愿单上限20个');
}
return;
}
// 显示添加弹窗
const dialog = document.getElementById('addDialog');
const input = document.getElementById('appName');
dialog.style.display = 'flex';
input.value = '';
input.focus();
} else {
showToast(data.error || '加载失败');
}
})
.catch(error => {
console.error('Load wishlist failed:', error);
showToast('加载失败,请稍后重试');
});
}
// 关闭弹窗
function closeDialog() {
const dialog = document.getElementById('addDialog');
dialog.style.display = 'none';
}
// 添加到心愿单
function addToWishlist() {
const input = document.getElementById('appName');
const appName = input.value.trim();
if (!appName) {
showToast('请输入应用名称');
return;
}
// 检查应用名称长度
if (appName.length > 50) {
showToast('应用名称过长');
return;
}
fetch('/user/wishlist/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
app_name: appName
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
closeDialog();
loadWishlist();
showToast('添加成功');
} else {
// 如果是限制相关的错误,显示更友好的提示
if (data.error.includes('邀请3位好友')) {
showToast('当前最多添加5个应用邀请3位好友可提升至20个');
} else if (data.error.includes('已达到心愿单上限')) {
showToast('已达到心愿单上限20个');
} else {
showToast(data.error || '添加失败');
}
}
})
.catch(error => {
console.error('Add to wishlist failed:', error);
showToast('添加失败,请稍后重试');
});
}
// 删除心愿单项目
function deleteItem(id) {
if (!confirm('确定要删除这个应用吗?')) return;
fetch(`/user/wishlist/delete/${id}`, {
method: 'POST'
})
.then(response => response.json())
.then(data => {
if (data.success) {
loadWishlist();
showToast('删除成功');
} else {
showToast(data.error || '删除失败');
}
})
.catch(error => {
console.error('Delete wishlist item failed:', error);
showToast('删除失败,请稍后重试');
});
}
// 添加键盘事件处理
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeDialog();
}
if (e.key === 'Enter' && document.getElementById('addDialog').style.display === 'flex') {
addToWishlist();
}
});
// 点击遮罩层关闭弹窗
document.getElementById('addDialog').addEventListener('click', function(e) {
if (e.target === this) {
closeDialog();
}
});
// 页面加载时获取心愿单
document.addEventListener('DOMContentLoaded', loadWishlist);
// 获取邀请信息
function loadInviteInfo() {
fetch('/user/invite_code')
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('inviteCount').textContent = data.invite_count;
document.getElementById('inviteUrl').value = data.invite_url;
// 更新邀请提示文本
const tipContent = document.querySelector('.invite-tip .tip-content span');
if (data.unlocked) {
tipContent.innerHTML = `
您已成功邀请3位好友已解锁20个心愿单名额
<button class="invite-btn" onclick="showInviteDialog()">
立即邀请
</button>
`;
} else {
tipContent.innerHTML = `
邀请3位好友使用即可解锁20个心愿单名额已邀请 ${data.invite_count}/3 位)
<button class="invite-btn" onclick="showInviteDialog()">
立即邀请
</button>
`;
}
// 生成二维码
new QRCode(document.getElementById('inviteQrcode'), {
text: data.invite_url,
width: 128,
height: 128
});
}
});
}
function showInviteDialog() {
const dialog = document.getElementById('inviteDialog');
dialog.style.display = 'flex';
loadInviteInfo();
}
function closeInviteDialog() {
document.getElementById('inviteDialog').style.display = 'none';
}
function copyInviteUrl() {
const input = document.getElementById('inviteUrl');
input.select();
document.execCommand('copy');
showToast('邀请链接已复制');
}
// 页面加载时获取心愿单和邀请信息
document.addEventListener('DOMContentLoaded', () => {
loadWishlist();
loadInviteInfo();
});
</script>
{% endblock %}
{% block footer %}{% endblock %}