Browse Source

落地页管理

milestone-20251020-双11活动
liruiqiang 3 months ago
parent
commit
a4c4a37a94
  1. 594
      adminConfig.html
  2. 9
      src/api/member.js

594
adminConfig.html

@ -1,14 +1,584 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<h1>mzy</h1>
<script type="module" src="/src/main.js">
</script>
</body>
<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;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #eee;
}
.header-title {
font-size: 20px;
font-weight: 600;
}
.user-info {
display: flex;
align-items: center;
}
.user-info img {
width: 36px;
height: 36px;
border-radius: 50%;
margin-right: 10px;
}
/* 功能区样式 */
.function-bar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.search-box {
display: flex;
}
.search-box input {
width: 300px;
padding: 8px 15px;
border: 1px solid #ddd;
border-radius: 4px 0 0 4px;
outline: none;
}
.search-box button {
background-color: #3498db;
color: #fff;
border: none;
padding: 0 15px;
border-radius: 0 4px 4px 0;
cursor: pointer;
}
.add-btn {
background-color: #2ecc71;
color: #fff;
border: none;
padding: 8px 20px;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
}
.add-btn i {
margin-right: 5px;
}
.add-btn:hover {
background-color: #27ae60;
}
/* 表格样式 */
.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;
}
.status {
display: inline-block;
padding: 3px 8px;
border-radius: 4px;
font-size: 12px;
}
.status-active {
background-color: rgba(46, 204, 113, 0.1);
color: #2ecc71;
}
.status-inactive {
background-color: rgba(231, 76, 60, 0.1);
color: #e74c3c;
}
.action-btn {
margin-right: 8px;
color: #3498db;
text-decoration: none;
font-size: 14px;
cursor: pointer;
}
.action-btn.delete {
color: #e74c3c;
}
.action-btn:hover {
text-decoration: underline;
}
/* 分页样式 */
.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;
}
/* 核心:确保a和span统一尺寸和居中 */
.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;
}
/* 激活和hover状态 */
.pagination-list a:hover,
.pagination-list a.active {
background-color: #3498db;
color: #fff;
border-color: #3498db;
}
/* 禁用状态(span标签) */
.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="header">
<div class="header-title">落地页管理</div>
</div>
<!-- 功能区 -->
<div class="function-bar">
<button class="add-btn">
<i class="fa fa-plus"></i> 新增落地页
</button>
</div>
<!-- 数据表格 -->
<div class="table-container">
<table class="data-table">
<thead>
<tr>
<th>序号</th>
<th>活动名称</th>
<th>活动简介</th>
<th>活动时间</th>
<th>编辑时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tableBody">
<tr>
<td colspan="6" class="loading">
<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 { getLandingListApi } from './src/api/member.js';
// DOM元素
const tableBody = document.getElementById('tableBody');
const paginationContainer = document.getElementById('paginationContainer');
// 分页参数
let currentPage = 1;
const pageSize = 10;
let totalCount = 0;
let totalPages = 0;
// 模拟数据
const mockData = Array.from({ length: 15 }, (_, index) => ({
id: index + 1,
title: `双十${index + 1}促销活动`,
desc: `这是第${index + 1}个落地页活动,主要推广新品上市和优惠折扣`,
activityTime: `2023-11-${(index % 20) + 10} 00:00:00 - 2023-11-${(index % 20) + 20} 23:59:59`,
updateTime: `2023-11-${(index % 20) + 5} ${10 + index}:${index * 5}:00`
}));
// 初始化页面
async function initPage() {
const urlParams = new URLSearchParams(window.location.search);
const pageParam = urlParams.get('page');
if (pageParam && !isNaN(pageParam)) {
currentPage = parseInt(pageParam);
}
// 获取列表数据
// await fetchLandingList();
await fetchMockLandingList();
}
// 新增:使用模拟数据获取列表(替代真实API调用)
async function fetchMockLandingList() {
// 模拟网络延迟
await new Promise(resolve => setTimeout(resolve, 800));
// 计算分页数据
totalCount = mockData.length;
totalPages = Math.ceil(totalCount / pageSize);
// 截取当前页的数据(数组切片)
const startIndex = (currentPage - 1) * pageSize;
const endIndex = startIndex + pageSize;
const currentPageData = mockData.slice(startIndex, endIndex);
// 渲染表格数据
renderTable(currentPageData);
// 渲染分页控件
renderPagination();
}
// 从后端获取落地页列表
async function fetchLandingList() {
try {
// 调用API接口,传递分页参数
const response = await getLandingListApi({
page: currentPage,
size: pageSize
});
if (response.code === 200 && response.data) {
const { list: landingPages, total } = response.data;
totalCount = total;
totalPages = Math.ceil(totalCount / pageSize);
// 渲染表格数据
renderTable(landingPages);
// 渲染分页控件
renderPagination();
} else {
renderEmptyState('获取数据失败');
}
} catch (error) {
console.error('获取列表失败:', error);
renderEmptyState('网络错误,请重试');
}
}
// 渲染表格数据
function renderTable(landingPages) {
if (!landingPages || landingPages.length === 0) {
renderEmptyState('暂无数据');
return;
}
let html = '';
landingPages.forEach((page, index) => {
// 计算序号(当前页-1)*每页条数 + 索引+1
const serialNumber = (currentPage - 1) * pageSize + index + 1;
html += `
<tr>
<td>${serialNumber}</td>
<td>${escapeHtml(page.title || '')}</td>
<td>${escapeHtml(page.desc || '无简介')}</td>
<td>${formatDate(page.activityTime || '')}</td>
<td>${formatDate(page.updateTime || '')}</td>
<td>
<a class="action-btn">编辑</a>
<a href="adminDetail.html" class="action-btn">详情</a>
</td>
</tr>
`;
});
tableBody.innerHTML = html;
}
// 渲染空状态
function renderEmptyState(message) {
tableBody.innerHTML = `
<tr>
<td colspan="6" 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;
// 生成页码列表(显示当前页前后2页)
const pageNumbers = [];
let startPage = Math.max(1, currentPage - 2);
let endPage = Math.min(totalPages, currentPage + 2);
// 确保至少显示5个页码(如果总页数够的话)
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('请输入有效的页码');
}
}
// 工具函数:格式化日期
function formatDate(dateString) {
if (!dateString) return '';
const date = new Date(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, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}
// 页面加载时初始化
window.addEventListener('DOMContentLoaded', initPage);
</script>
</body>
</html> </html>

9
src/api/member.js

@ -21,3 +21,12 @@ export function acceptCardApi(data) {
data: data, data: data,
}); });
} }
// 获取落地页活动列表
export function getLandingListApi(data) {
return request({
url: `${API_BASE_URL}/api/getLanding`,
method: "post",
data: data,
});
}
Loading…
Cancel
Save