Kamixitong/app/web/templates/user/products.html
2025-11-22 16:48:45 +08:00

244 lines
9.0 KiB
HTML

{% extends "user/base.html" %}
{% block title %}产品中心 - {{ config.SITE_NAME or '软件授权管理系统' }}{% endblock %}
{% block extra_css %}
<style>
.product-card {
transition: transform 0.3s ease;
border: none;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
.product-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 20px rgba(0,0,0,0.1);
}
.product-image {
height: 200px;
object-fit: cover;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
}
.search-filters {
background: #f8f9fa;
border-radius: 10px;
padding: 1.5rem;
margin-bottom: 2rem;
}
</style>
{% endblock %}
{% block content %}
<div class="container py-4">
<div class="row">
<div class="col-12">
<h1 class="mb-4">产品中心</h1>
<!-- 搜索和筛选区 -->
<div class="search-filters">
<div class="row g-3">
<div class="col-md-4">
<input type="text" class="form-control" id="searchInput" placeholder="搜索产品名称...">
</div>
<div class="col-md-3">
<select class="form-select" id="statusFilter">
<option value="">所有状态</option>
<option value="1">已发布</option>
<option value="0">未发布</option>
</select>
</div>
<div class="col-md-3">
<button class="btn btn-primary w-100" id="searchBtn">
<i class="fas fa-search me-1"></i>搜索
</button>
</div>
</div>
</div>
<!-- 产品列表 -->
<div class="row" id="productsContainer">
<!-- 产品项将通过JavaScript动态加载 -->
<div class="col-12 text-center py-5">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">加载中...</span>
</div>
<p class="mt-2">正在加载产品列表...</p>
</div>
</div>
<!-- 分页 -->
<nav aria-label="产品分页" class="mt-4">
<ul class="pagination justify-content-center" id="pagination">
<!-- 分页按钮将通过JavaScript动态生成 -->
</ul>
</nav>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
// 产品列表页面JavaScript
document.addEventListener('DOMContentLoaded', function() {
console.log('产品列表页面加载完成');
// 初始化产品列表
loadProducts();
// 搜索按钮事件
document.getElementById('searchBtn').addEventListener('click', function() {
loadProducts();
});
// 回车搜索
document.getElementById('searchInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
loadProducts();
}
});
});
// 加载产品列表
function loadProducts(page = 1) {
const searchInput = document.getElementById('searchInput').value;
const statusFilter = document.getElementById('statusFilter').value;
// 构建查询参数
const params = new URLSearchParams();
params.append('page', page);
if (searchInput) params.append('keyword', searchInput);
if (statusFilter) params.append('status', statusFilter);
// 显示加载状态
document.getElementById('productsContainer').innerHTML = `
<div class="col-12 text-center py-5">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">加载中...</span>
</div>
<p class="mt-2">正在加载产品列表...</p>
</div>
`;
// 调用API获取产品列表
apiRequest(`/api/v1/user/products?${params.toString()}`)
.then(data => {
if (data.success) {
renderProducts(data.data.products, data.data.pagination);
} else {
showNotification('加载产品列表失败: ' + data.message, 'error');
}
})
.catch(error => {
showNotification('加载产品列表失败,请稍后重试', 'error');
console.error('加载产品列表失败:', error);
});
}
// 渲染产品列表
function renderProducts(products, pagination) {
const container = document.getElementById('productsContainer');
if (products.length === 0) {
container.innerHTML = `
<div class="col-12 text-center py-5">
<i class="fas fa-box-open fa-3x text-muted mb-3"></i>
<h4 class="text-muted">暂无产品</h4>
<p class="text-muted">当前没有符合条件的产品</p>
</div>
`;
document.getElementById('pagination').innerHTML = '';
return;
}
// 生成产品卡片HTML
let productsHtml = '';
products.forEach(product => {
// 处理图片路径,如果没有图片则使用默认图片
const imagePath = product.image_path || '/static/images/product-default.png';
productsHtml += `
<div class="col-lg-4 col-md-6 mb-4">
<div class="card product-card h-100">
<img src="${imagePath}"
class="card-img-top product-image"
alt="${product.product_name}">
<div class="card-body d-flex flex-column">
<h5 class="card-title">${product.product_name}</h5>
<p class="card-text flex-grow-1">${product.description || '暂无描述'}</p>
<div class="mt-auto">
<div class="d-flex justify-content-between align-items-center">
<span class="text-muted">版本: ${product.latest_version || '1.0.0'}</span>
<span class="badge ${product.status === 1 ? 'bg-success' : 'bg-secondary'}">
${product.status === 1 ? '已发布' : '未发布'}
</span>
</div>
<div class="mt-3">
<a href="/index/products/${product.product_id}" class="btn btn-primary w-100">
<i class="fas fa-info-circle me-1"></i>查看详情
</a>
</div>
</div>
</div>
</div>
</div>
`;
});
container.innerHTML = productsHtml;
// 渲染分页
renderPagination(pagination);
}
// 渲染分页
function renderPagination(pagination) {
const paginationContainer = document.getElementById('pagination');
if (pagination.total_pages <= 1) {
paginationContainer.innerHTML = '';
return;
}
let paginationHtml = '';
// 上一页
if (pagination.current_page > 1) {
paginationHtml += `
<li class="page-item">
<a class="page-link" href="#" onclick="loadProducts(${pagination.current_page - 1}); return false;">
<i class="fas fa-chevron-left"></i>
</a>
</li>
`;
}
// 页码
for (let i = Math.max(1, pagination.current_page - 2);
i <= Math.min(pagination.total_pages, pagination.current_page + 2);
i++) {
paginationHtml += `
<li class="page-item ${i === pagination.current_page ? 'active' : ''}">
<a class="page-link" href="#" onclick="loadProducts(${i}); return false;">${i}</a>
</li>
`;
}
// 下一页
if (pagination.current_page < pagination.total_pages) {
paginationHtml += `
<li class="page-item">
<a class="page-link" href="#" onclick="loadProducts(${pagination.current_page + 1}); return false;">
<i class="fas fa-chevron-right"></i>
</a>
</li>
`;
}
paginationContainer.innerHTML = paginationHtml;
}
</script>
{% endblock %}