You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
544 lines
15 KiB
544 lines
15 KiB
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>管理后台</title>
|
|
<style>
|
|
/* 基础样式 */
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
font-family: "Microsoft YaHei", sans-serif;
|
|
}
|
|
body {
|
|
background-color: #f5f7fa;
|
|
color: #333;
|
|
}
|
|
.container {
|
|
display: flex;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
/* 侧边栏样式 */
|
|
.sidebar {
|
|
width: 220px;
|
|
background-color: #2c3e50;
|
|
color: #fff;
|
|
padding: 20px 0;
|
|
}
|
|
.sidebar-logo {
|
|
text-align: center;
|
|
padding: 0 20px 20px;
|
|
border-bottom: 1px solid rgba(255,255,255,0.1);
|
|
margin-bottom: 20px;
|
|
}
|
|
.sidebar-logo h2 {
|
|
font-size: 18px;
|
|
margin-top: 10px;
|
|
}
|
|
.sidebar-menu {
|
|
list-style: none;
|
|
}
|
|
.sidebar-menu li a {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 12px 20px;
|
|
color: rgba(255,255,255,0.8);
|
|
text-decoration: none;
|
|
transition: all 0.3s;
|
|
}
|
|
.sidebar-menu li a:hover,
|
|
.sidebar-menu li a.active {
|
|
background-color: #34495e;
|
|
color: #fff;
|
|
}
|
|
.sidebar-menu li a i {
|
|
margin-right: 10px;
|
|
font-size: 16px;
|
|
}
|
|
|
|
/* 主内容区样式 */
|
|
.main-content {
|
|
flex: 1;
|
|
padding: 20px;
|
|
overflow-y: auto;
|
|
}
|
|
.page-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
padding-bottom: 15px;
|
|
border-bottom: 1px solid #eee;
|
|
}
|
|
.page-header h2 {
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
.btn {
|
|
padding: 6px 12px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
background-color: #fff;
|
|
cursor: pointer;
|
|
color: #333;
|
|
text-decoration: none;
|
|
}
|
|
.btn-primary {
|
|
background-color: #3498db;
|
|
color: #fff;
|
|
border-color: #3498db;
|
|
}
|
|
.btn-danger {
|
|
background-color: #e74c3c;
|
|
color: #fff;
|
|
border-color: #e74c3c;
|
|
}
|
|
|
|
/* 查询区域样式 */
|
|
.search-area {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
margin-bottom: 20px;
|
|
flex-wrap: wrap; /* 适配小屏幕 */
|
|
}
|
|
.search-area input,
|
|
.search-area select {
|
|
padding: 6px 10px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
outline: none;
|
|
}
|
|
.search-area .date-picker {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
}
|
|
|
|
/* 表格样式 */
|
|
.table-container {
|
|
background-color: #fff;
|
|
border-radius: 4px;
|
|
box-shadow: 0 2px 12px rgba(0,0,0,0.1);
|
|
overflow: hidden;
|
|
}
|
|
.data-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
.data-table th,
|
|
.data-table td {
|
|
padding: 12px 15px;
|
|
text-align: left;
|
|
border-bottom: 1px solid #f0f0f0;
|
|
}
|
|
.data-table th {
|
|
background-color: #f9fafb;
|
|
font-weight: 600;
|
|
color: #666;
|
|
}
|
|
.data-table tbody tr:hover {
|
|
background-color: #f5f7fa;
|
|
}
|
|
|
|
/* 分页样式 */
|
|
.pagination {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 15px;
|
|
border-top: 1px solid #f0f0f0;
|
|
}
|
|
.pagination-info {
|
|
color: #666;
|
|
font-size: 14px;
|
|
}
|
|
.pagination-list {
|
|
display: flex;
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
.pagination-list li {
|
|
margin: 0 2px;
|
|
}
|
|
.pagination-list a,
|
|
.pagination-list span {
|
|
display: inline-block;
|
|
width: 45px;
|
|
height: 45px;
|
|
line-height: 45px;
|
|
text-align: center;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
text-decoration: none;
|
|
color: #333;
|
|
font-size: 14px;
|
|
box-sizing: border-box;
|
|
}
|
|
.pagination-list a {
|
|
cursor: pointer;
|
|
}
|
|
.pagination-list a:hover,
|
|
.pagination-list a.active {
|
|
background-color: #3498db;
|
|
color: #fff;
|
|
border-color: #3498db;
|
|
}
|
|
.pagination-list span {
|
|
background-color: #f5f5f5;
|
|
color: #999;
|
|
cursor: not-allowed;
|
|
}
|
|
.pagination-jump {
|
|
display: flex;
|
|
align-items: center;
|
|
font-size: 14px;
|
|
gap: 5px;
|
|
}
|
|
.pagination-jump input {
|
|
width: 50px;
|
|
height: 32px;
|
|
margin: 0 5px;
|
|
padding: 0 5px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
text-align: center;
|
|
box-sizing: border-box;
|
|
}
|
|
.pagination-jump button {
|
|
padding: 6px 12px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
background-color: #fff;
|
|
cursor: pointer;
|
|
height: 32px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* 加载中样式 */
|
|
.loading {
|
|
text-align: center;
|
|
padding: 50px 0;
|
|
color: #666;
|
|
}
|
|
.loading i {
|
|
font-size: 24px;
|
|
margin-bottom: 10px;
|
|
animation: spin 1s linear infinite;
|
|
}
|
|
@keyframes spin {
|
|
from { transform: rotate(0deg); }
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
</style>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="sidebar">
|
|
<div class="sidebar-logo">
|
|
<i class="fa fa-line-chart" style="font-size: 24px;"></i>
|
|
<h2>后台管理系统</h2>
|
|
</div>
|
|
<ul class="sidebar-menu">
|
|
<li><a href="#" class="active"><i class="fa fa-file-text-o"></i> 落地页管理</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- 主内容区 -->
|
|
<div class="main-content">
|
|
<div class="page-header">
|
|
<div class="page-header h2">详情</div>
|
|
<a href="adminConfig.html" class="btn">返回上一级页面</a>
|
|
</div>
|
|
|
|
<!-- 查询区域 -->
|
|
<div class="search-area">
|
|
<label class="date-picker">
|
|
打开网页时间
|
|
<input type="date" id="startTime" placeholder="请选择开始时间" />
|
|
至
|
|
<input type="date" id="endTime" placeholder="请选择结束时间" />
|
|
</label>
|
|
<div>
|
|
<label for="statusSelect">收下状态</label>
|
|
<select id="statusSelect">
|
|
<option value="">请选择状态</option>
|
|
<option value="1">是</option>
|
|
<option value="0">否</option>
|
|
</select>
|
|
</div>
|
|
<button id="searchBtn" class="btn btn-primary">查询</button>
|
|
<button class="btn btn-danger">导出</button>
|
|
</div>
|
|
|
|
<!-- 数据表格 -->
|
|
<div class="table-container">
|
|
<table class="data-table">
|
|
<thead>
|
|
<tr>
|
|
<th>序号</th>
|
|
<th>打开网页时间</th>
|
|
<th>收下状态</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="tableBody">
|
|
<tr>
|
|
<td colspan="3" class="loading"> <!-- 注意:表格列数是3,colspan改为3 -->
|
|
<i class="fa fa-spinner"></i>
|
|
<p>加载中...</p>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<!-- 分页控件 -->
|
|
<div class="pagination" id="paginationContainer">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="module">
|
|
// 导入API函数(假设接口定义)
|
|
import { getLandingDetailApi } from './src/api/member.js';
|
|
|
|
// DOM元素
|
|
const tableBody = document.getElementById('tableBody');
|
|
const paginationContainer = document.getElementById('paginationContainer');
|
|
const searchBtn = document.getElementById('searchBtn');
|
|
const startTimeInput = document.getElementById('startTime');
|
|
const endTimeInput = document.getElementById('endTime');
|
|
const statusSelect = document.getElementById('statusSelect');
|
|
|
|
// 分页参数
|
|
let currentPage = 1;
|
|
const pageSize = 20;
|
|
let totalCount = 0;
|
|
let totalPages = 0;
|
|
|
|
// 初始化页面:从URL获取页码,请求后端数据
|
|
async function initPage() {
|
|
// 从URL参数获取当前页码(如 ?page=2)
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const pageParam = urlParams.get('page');
|
|
if (pageParam && !isNaN(pageParam)) {
|
|
currentPage = parseInt(pageParam);
|
|
}
|
|
|
|
// 从后端请求数据(替换模拟数据)
|
|
await fetchDataFromBackend();
|
|
}
|
|
|
|
// 核心:从后端API请求数据
|
|
async function fetchDataFromBackend() {
|
|
// 显示加载状态
|
|
tableBody.innerHTML = `
|
|
<tr>
|
|
<td colspan="3" class="loading">
|
|
<i class="fa fa-spinner"></i>
|
|
<p>加载中...</p>
|
|
</td>
|
|
</tr>
|
|
`;
|
|
paginationContainer.innerHTML = '';
|
|
|
|
try {
|
|
// 1. 构造请求参数(分页+查询条件)
|
|
const requestParams = {
|
|
page: currentPage, // 当前页码
|
|
size: pageSize, // 每页条数
|
|
startTime: startTimeInput.value || '', // 开始时间(查询条件)
|
|
endTime: endTimeInput.value || '', // 结束时间(查询条件)
|
|
receiveStatus: statusSelect.value || '' // 收下状态(查询条件)
|
|
};
|
|
|
|
// 2. 调用导入的API函数
|
|
const result = await getLandingDetailApi(requestParams);
|
|
|
|
// 3. 处理API返回结果
|
|
if (result.code === 200) {
|
|
const { list, total } = result.data;
|
|
totalCount = total;
|
|
totalPages = Math.ceil(totalCount / pageSize);
|
|
|
|
renderTable(list);
|
|
renderPagination();
|
|
} else {
|
|
renderEmptyState('获取数据失败');
|
|
}
|
|
|
|
} catch (error) {
|
|
// 捕获异常
|
|
console.error('请求数据异常:', error);
|
|
renderEmptyState('网络错误,请稍后重试');
|
|
}
|
|
}
|
|
|
|
// 渲染表格数据
|
|
function renderTable(dataList) {
|
|
if (!dataList || dataList.length === 0) {
|
|
renderEmptyState('暂无符合条件的数据');
|
|
return;
|
|
}
|
|
|
|
let html = '';
|
|
dataList.forEach((item, index) => {
|
|
// 计算序号:(当前页-1)*每页条数 + 索引+1
|
|
const serialNumber = (currentPage - 1) * pageSize + index + 1;
|
|
|
|
// 注意:item的字段名需与后端返回的字段一致
|
|
html += `
|
|
<tr>
|
|
<td>${serialNumber}</td>
|
|
<td>${formatDate(item.openTime || '')}</td>
|
|
<td>${item.receiveStatus === '1' ? '是' : item.receiveStatus === '0' ? '否' : ''}</td>
|
|
</tr>
|
|
`;
|
|
});
|
|
|
|
tableBody.innerHTML = html;
|
|
}
|
|
|
|
// 渲染空状态
|
|
function renderEmptyState(message) {
|
|
tableBody.innerHTML = `
|
|
<tr>
|
|
<td colspan="3" style="text-align: center; padding: 30px;">
|
|
<i class="fa fa-inbox" style="font-size: 24px; color: #ddd; margin-bottom: 10px;"></i>
|
|
<p>${message}</p>
|
|
</td>
|
|
</tr>
|
|
`;
|
|
paginationContainer.innerHTML = '';
|
|
}
|
|
|
|
// 渲染分页控件
|
|
function renderPagination() {
|
|
if (totalCount === 0) return;
|
|
|
|
// 生成页码列表
|
|
const pageNumbers = [];
|
|
let startPage = Math.max(1, currentPage - 2);
|
|
let endPage = Math.min(totalPages, currentPage + 2);
|
|
|
|
if (endPage - startPage < 4 && totalPages >= 5) {
|
|
if (startPage === 1) endPage = 5;
|
|
else if (endPage === totalPages) startPage = totalPages - 4;
|
|
}
|
|
|
|
for (let i = startPage; i <= endPage; i++) {
|
|
pageNumbers.push(i);
|
|
}
|
|
|
|
// 分页HTML
|
|
const html = `
|
|
<div class="pagination-info">
|
|
共 ${totalCount} 条记录,当前第 ${currentPage} / ${totalPages} 页
|
|
</div>
|
|
<ul class="pagination-list">
|
|
<li>
|
|
${currentPage === 1
|
|
? `<span>首页</span>`
|
|
: `<a href="?page=1">首页</a>`
|
|
}
|
|
</li>
|
|
<li>
|
|
${currentPage > 1
|
|
? `<a href="?page=${currentPage - 1}">上一页</a>`
|
|
: `<span>上一页</span>`
|
|
}
|
|
</li>
|
|
${pageNumbers.map(num => `
|
|
<li>
|
|
<a href="?page=${num}" class="${num === currentPage ? 'active' : ''}">
|
|
${num}
|
|
</a>
|
|
</li>
|
|
`).join('')}
|
|
<li>
|
|
${currentPage < totalPages
|
|
? `<a href="?page=${currentPage + 1}">下一页</a>`
|
|
: `<span>下一页</span>`
|
|
}
|
|
</li>
|
|
<li>
|
|
${currentPage === totalPages
|
|
? `<span>尾页</span>`
|
|
: `<a href="?page=${totalPages}">尾页</a>`
|
|
}
|
|
</li>
|
|
</ul>
|
|
<div class="pagination-jump">
|
|
<span>跳至</span>
|
|
<input type="number" min="1" max="${totalPages}" value="${currentPage}" id="jumpPageInput">
|
|
<span>页</span>
|
|
<button id="jumpBtn">确定</button>
|
|
</div>
|
|
`;
|
|
|
|
paginationContainer.innerHTML = html;
|
|
|
|
// 绑定跳转事件
|
|
document.getElementById('jumpBtn').addEventListener('click', handlePageJump);
|
|
document.getElementById('jumpPageInput').addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter') handlePageJump();
|
|
});
|
|
}
|
|
|
|
// 处理页码跳转
|
|
function handlePageJump() {
|
|
const pageInput = document.getElementById('jumpPageInput');
|
|
const page = parseInt(pageInput.value);
|
|
|
|
if (page && !isNaN(page) && page >= 1 && page <= totalPages && page !== currentPage) {
|
|
window.location.href = `?page=${page}`;
|
|
} else {
|
|
alert('请输入有效的页码');
|
|
}
|
|
}
|
|
|
|
// 查询按钮事件:点击后重新请求数据
|
|
searchBtn.addEventListener('click', async () => {
|
|
currentPage = 1; // 重置为第一页
|
|
await fetchDataFromBackend(); // 重新请求后端数据
|
|
});
|
|
|
|
// 工具函数:格式化日期(适配后端返回的时间格式)
|
|
function formatDate(dateString) {
|
|
if (!dateString) return '';
|
|
const date = new Date(dateString);
|
|
// 处理无效日期
|
|
if (isNaN(date.getTime())) return dateString;
|
|
// 格式化显示:年-月-日 时:分:秒
|
|
return date.toLocaleString('zh-CN', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit'
|
|
}).replace(/\//g, '-');
|
|
}
|
|
|
|
// 工具函数:HTML转义(防止XSS攻击)
|
|
function escapeHtml(str) {
|
|
if (!str) return '';
|
|
return str
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|
|
|
|
// 页面加载时初始化
|
|
window.addEventListener('DOMContentLoaded', initPage);
|
|
</script>
|
|
</body>
|
|
</html>
|