初始化鸿蒙应用展示平台项目 - 前后端分离架构
This commit is contained in:
475
templates/coming.html
Executable file
475
templates/coming.html
Executable file
@@ -0,0 +1,475 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="coming-apps-page">
|
||||
<div id="toast" class="developing-tip">
|
||||
<span id="toastMessage"></span>
|
||||
</div>
|
||||
|
||||
<div class="header">
|
||||
<a href="{{ url_for('explore') }}" class="back-link" title="返回探索">
|
||||
<i class="fas fa-arrow-left"></i>
|
||||
</a>
|
||||
<h1>即将上线</h1>
|
||||
</div>
|
||||
|
||||
<div class="apps-grid">
|
||||
{% if coming_apps %}
|
||||
{% for app in coming_apps %}
|
||||
<div class="app-tile">
|
||||
<div class="app-tile-content">
|
||||
<div class="app-tile-icon">
|
||||
{% if 'http' in app.icon_path %}
|
||||
<img src="{{ app.icon_path }}" alt="{{ app.name }}">
|
||||
{% else %}
|
||||
<img src="{{ url_for('static', filename='uploads/' + app.icon_path) }}" alt="{{ app.name }}">
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="app-tile-info">
|
||||
<div class="app-tile-header">
|
||||
<h3>{{ app.name }}</h3>
|
||||
<button class="add-reminder-btn" onclick="toggleWishlist('{{ app.name }}')" title="添加提醒" data-app-name="{{ app.name }}">
|
||||
<i class="fas fa-bell"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="app-tile-meta">
|
||||
<span class="coming-soon-tag">即将上线</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="no-apps-message">暂无即将上线应用</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.coming-apps-page {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 60px 15px 20px 15px;
|
||||
transform: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.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);
|
||||
transform: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.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;
|
||||
transform: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
background: #e5e5e7;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
font-family: "SimHei", "黑体", sans-serif;
|
||||
transform: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.apps-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.app-tile {
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.app-tile-content {
|
||||
padding: 15px;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.app-tile-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.app-tile-icon img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 16px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.app-tile-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.app-tile-header {
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.app-tile-header h3 {
|
||||
margin: 0 0 6px 0;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.coming-soon-tag {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
color: #0066cc;
|
||||
background: rgba(0, 102, 204, 0.1);
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.no-apps-message {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #666;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.app-tile-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.add-reminder-btn {
|
||||
border: none;
|
||||
background: rgba(0, 102, 204, 0.1);
|
||||
color: #0066cc;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
margin-left: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.add-reminder-btn:hover {
|
||||
background: rgba(0, 102, 204, 0.2);
|
||||
color: #0066cc;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.add-reminder-btn.active {
|
||||
background: #0066cc;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.add-reminder-btn.active:hover {
|
||||
background: #0052a3;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.add-reminder-btn i {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
/* 暗色模式样式 */
|
||||
[data-theme="dark"] .add-reminder-btn {
|
||||
background: rgba(94, 158, 255, 0.1);
|
||||
color: #5E9EFF;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .add-reminder-btn:hover {
|
||||
background: rgba(94, 158, 255, 0.2);
|
||||
color: #5E9EFF;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .add-reminder-btn.active {
|
||||
background: #5E9EFF;
|
||||
color: white;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .add-reminder-btn.active:hover {
|
||||
background: #4b8fef;
|
||||
color: white;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .coming-apps-page {
|
||||
background: #1a1a1a;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .header {
|
||||
background: #242424;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .header h1 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .back-link {
|
||||
color: #ccc;
|
||||
background: #333;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .back-link:hover {
|
||||
background: #444;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .app-tile {
|
||||
background: #242424;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .app-tile-header h3 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .no-apps-message {
|
||||
background: #242424;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .coming-soon-tag {
|
||||
background: rgba(94, 158, 255, 0.1);
|
||||
color: #5E9EFF;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.apps-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// 存储心愿单应用列表
|
||||
let wishlistApps = new Set();
|
||||
|
||||
// 加载心愿单
|
||||
function loadWishlist() {
|
||||
fetch('/user/wishlist/list')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// 清空并重新填充心愿单集合
|
||||
wishlistApps.clear();
|
||||
data.items.forEach(item => wishlistApps.add(item.app_name));
|
||||
|
||||
// 更新所有按钮状态
|
||||
updateAllButtonStates();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Load wishlist failed:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// 更新所有按钮状态
|
||||
function updateAllButtonStates() {
|
||||
document.querySelectorAll('.add-reminder-btn').forEach(btn => {
|
||||
const appName = btn.dataset.appName;
|
||||
updateButtonState(btn, wishlistApps.has(appName));
|
||||
});
|
||||
}
|
||||
|
||||
// 更新单个按钮状态
|
||||
function updateButtonState(button, isActive) {
|
||||
const icon = button.querySelector('i');
|
||||
if (isActive) {
|
||||
button.classList.add('active');
|
||||
button.title = '取消提醒';
|
||||
icon.className = 'fas fa-check-circle';
|
||||
} else {
|
||||
button.classList.remove('active');
|
||||
button.title = '添加提醒';
|
||||
icon.className = 'fas fa-bell';
|
||||
}
|
||||
}
|
||||
|
||||
// 切换心愿单状态
|
||||
function toggleWishlist(appName) {
|
||||
const button = document.querySelector(`.add-reminder-btn[data-app-name="${appName}"]`);
|
||||
const isRemoving = wishlistApps.has(appName);
|
||||
|
||||
if (isRemoving) {
|
||||
// 获取项目ID并删除
|
||||
fetch('/user/wishlist/list')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const item = data.items.find(item => item.app_name === appName);
|
||||
if (item) {
|
||||
deleteFromWishlist(item.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
addToWishlist(appName);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加到心愿单
|
||||
function addToWishlist(appName) {
|
||||
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) {
|
||||
wishlistApps.add(appName);
|
||||
updateAllButtonStates();
|
||||
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 deleteFromWishlist(itemId) {
|
||||
fetch(`/user/wishlist/delete/${itemId}`, {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
loadWishlist(); // 重新加载心愿单以更新状态
|
||||
showToast('已取消提醒');
|
||||
} else {
|
||||
showToast(data.error || '取消失败');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Delete from wishlist failed:', error);
|
||||
showToast('取消失败,请稍后重试');
|
||||
});
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 返回按钮处理
|
||||
document.querySelector('.back-link').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
window.history.back();
|
||||
});
|
||||
|
||||
// 页面加载时获取心愿单
|
||||
document.addEventListener('DOMContentLoaded', loadWishlist);
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user