国内市场双十一活动仓库
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.

543 lines
15 KiB

3 months ago
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>管理后台</title>
  7. <style>
  8. /* 基础样式 */
  9. * {
  10. margin: 0;
  11. padding: 0;
  12. box-sizing: border-box;
  13. font-family: "Microsoft YaHei", sans-serif;
  14. }
  15. body {
  16. background-color: #f5f7fa;
  17. color: #333;
  18. }
  19. .container {
  20. display: flex;
  21. min-height: 100vh;
  22. }
  23. /* 侧边栏样式 */
  24. .sidebar {
  25. width: 220px;
  26. background-color: #2c3e50;
  27. color: #fff;
  28. padding: 20px 0;
  29. }
  30. .sidebar-logo {
  31. text-align: center;
  32. padding: 0 20px 20px;
  33. border-bottom: 1px solid rgba(255,255,255,0.1);
  34. margin-bottom: 20px;
  35. }
  36. .sidebar-logo h2 {
  37. font-size: 18px;
  38. margin-top: 10px;
  39. }
  40. .sidebar-menu {
  41. list-style: none;
  42. }
  43. .sidebar-menu li a {
  44. display: flex;
  45. align-items: center;
  46. padding: 12px 20px;
  47. color: rgba(255,255,255,0.8);
  48. text-decoration: none;
  49. transition: all 0.3s;
  50. }
  51. .sidebar-menu li a:hover,
  52. .sidebar-menu li a.active {
  53. background-color: #34495e;
  54. color: #fff;
  55. }
  56. .sidebar-menu li a i {
  57. margin-right: 10px;
  58. font-size: 16px;
  59. }
  60. /* 主内容区样式 */
  61. .main-content {
  62. flex: 1;
  63. padding: 20px;
  64. overflow-y: auto;
  65. }
  66. .page-header {
  67. display: flex;
  68. justify-content: space-between;
  69. align-items: center;
  70. margin-bottom: 20px;
  71. padding-bottom: 15px;
  72. border-bottom: 1px solid #eee;
  73. }
  74. .page-header h2 {
  75. font-size: 20px;
  76. font-weight: 600;
  77. color: #333;
  78. }
  79. .btn {
  80. padding: 6px 12px;
  81. border: 1px solid #ddd;
  82. border-radius: 4px;
  83. background-color: #fff;
  84. cursor: pointer;
  85. color: #333;
  86. text-decoration: none;
  87. }
  88. .btn-primary {
  89. background-color: #3498db;
  90. color: #fff;
  91. border-color: #3498db;
  92. }
  93. .btn-danger {
  94. background-color: #e74c3c;
  95. color: #fff;
  96. border-color: #e74c3c;
  97. }
  98. /* 查询区域样式 */
  99. .search-area {
  100. display: flex;
  101. align-items: center;
  102. gap: 10px;
  103. margin-bottom: 20px;
  104. flex-wrap: wrap; /* 适配小屏幕 */
  105. }
  106. .search-area input,
  107. .search-area select {
  108. padding: 6px 10px;
  109. border: 1px solid #ddd;
  110. border-radius: 4px;
  111. outline: none;
  112. }
  113. .search-area .date-picker {
  114. display: flex;
  115. align-items: center;
  116. gap: 5px;
  117. }
  118. /* 表格样式 */
  119. .table-container {
  120. background-color: #fff;
  121. border-radius: 4px;
  122. box-shadow: 0 2px 12px rgba(0,0,0,0.1);
  123. overflow: hidden;
  124. }
  125. .data-table {
  126. width: 100%;
  127. border-collapse: collapse;
  128. }
  129. .data-table th,
  130. .data-table td {
  131. padding: 12px 15px;
  132. text-align: left;
  133. border-bottom: 1px solid #f0f0f0;
  134. }
  135. .data-table th {
  136. background-color: #f9fafb;
  137. font-weight: 600;
  138. color: #666;
  139. }
  140. .data-table tbody tr:hover {
  141. background-color: #f5f7fa;
  142. }
  143. /* 分页样式 */
  144. .pagination {
  145. display: flex;
  146. justify-content: space-between;
  147. align-items: center;
  148. padding: 15px;
  149. border-top: 1px solid #f0f0f0;
  150. }
  151. .pagination-info {
  152. color: #666;
  153. font-size: 14px;
  154. }
  155. .pagination-list {
  156. display: flex;
  157. list-style: none;
  158. padding: 0;
  159. margin: 0;
  160. }
  161. .pagination-list li {
  162. margin: 0 2px;
  163. }
  164. .pagination-list a,
  165. .pagination-list span {
  166. display: inline-block;
  167. width: 45px;
  168. height: 45px;
  169. line-height: 45px;
  170. text-align: center;
  171. border: 1px solid #ddd;
  172. border-radius: 4px;
  173. text-decoration: none;
  174. color: #333;
  175. font-size: 14px;
  176. box-sizing: border-box;
  177. }
  178. .pagination-list a {
  179. cursor: pointer;
  180. }
  181. .pagination-list a:hover,
  182. .pagination-list a.active {
  183. background-color: #3498db;
  184. color: #fff;
  185. border-color: #3498db;
  186. }
  187. .pagination-list span {
  188. background-color: #f5f5f5;
  189. color: #999;
  190. cursor: not-allowed;
  191. }
  192. .pagination-jump {
  193. display: flex;
  194. align-items: center;
  195. font-size: 14px;
  196. gap: 5px;
  197. }
  198. .pagination-jump input {
  199. width: 50px;
  200. height: 32px;
  201. margin: 0 5px;
  202. padding: 0 5px;
  203. border: 1px solid #ddd;
  204. border-radius: 4px;
  205. text-align: center;
  206. box-sizing: border-box;
  207. }
  208. .pagination-jump button {
  209. padding: 6px 12px;
  210. border: 1px solid #ddd;
  211. border-radius: 4px;
  212. background-color: #fff;
  213. cursor: pointer;
  214. height: 32px;
  215. box-sizing: border-box;
  216. }
  217. /* 加载中样式 */
  218. .loading {
  219. text-align: center;
  220. padding: 50px 0;
  221. color: #666;
  222. }
  223. .loading i {
  224. font-size: 24px;
  225. margin-bottom: 10px;
  226. animation: spin 1s linear infinite;
  227. }
  228. @keyframes spin {
  229. from { transform: rotate(0deg); }
  230. to { transform: rotate(360deg); }
  231. }
  232. </style>
  233. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
  234. </head>
  235. <body>
  236. <div class="container">
  237. <div class="sidebar">
  238. <div class="sidebar-logo">
  239. <i class="fa fa-line-chart" style="font-size: 24px;"></i>
  240. <h2>后台管理系统</h2>
  241. </div>
  242. <ul class="sidebar-menu">
  243. <li><a href="#" class="active"><i class="fa fa-file-text-o"></i> 落地页管理</a></li>
  244. </ul>
  245. </div>
  246. <!-- 主内容区 -->
  247. <div class="main-content">
  248. <div class="page-header">
  249. <div class="page-header h2">详情</div>
  250. <a href="adminConfig.html" class="btn">返回上一级页面</a>
  251. </div>
  252. <!-- 查询区域 -->
  253. <div class="search-area">
  254. <label class="date-picker">
  255. 打开网页时间
  256. <input type="date" id="startTime" placeholder="请选择开始时间" />
  257. <input type="date" id="endTime" placeholder="请选择结束时间" />
  258. </label>
  259. <div>
  260. <label for="statusSelect">收下状态</label>
  261. <select id="statusSelect">
  262. <option value="">请选择状态</option>
  263. <option value="1"></option>
  264. <option value="0"></option>
  265. </select>
  266. </div>
  267. <button id="searchBtn" class="btn btn-primary">查询</button>
  268. <button class="btn btn-danger">导出</button>
  269. </div>
  270. <!-- 数据表格 -->
  271. <div class="table-container">
  272. <table class="data-table">
  273. <thead>
  274. <tr>
  275. <th>序号</th>
  276. <th>打开网页时间</th>
  277. <th>收下状态</th>
  278. </tr>
  279. </thead>
  280. <tbody id="tableBody">
  281. <tr>
  282. <td colspan="3" class="loading"> <!-- 注意:表格列数是3,colspan改为3 -->
  283. <i class="fa fa-spinner"></i>
  284. <p>加载中...</p>
  285. </td>
  286. </tr>
  287. </tbody>
  288. </table>
  289. <!-- 分页控件 -->
  290. <div class="pagination" id="paginationContainer">
  291. </div>
  292. </div>
  293. </div>
  294. </div>
  295. <script type="module">
  296. // 导入API函数(假设接口定义)
  297. import { getLandingDetailApi } from './src/api/member.js';
  298. // DOM元素
  299. const tableBody = document.getElementById('tableBody');
  300. const paginationContainer = document.getElementById('paginationContainer');
  301. const searchBtn = document.getElementById('searchBtn');
  302. const startTimeInput = document.getElementById('startTime');
  303. const endTimeInput = document.getElementById('endTime');
  304. const statusSelect = document.getElementById('statusSelect');
  305. // 分页参数
  306. let currentPage = 1;
  307. const pageSize = 20;
  308. let totalCount = 0;
  309. let totalPages = 0;
  310. // 初始化页面:从URL获取页码,请求后端数据
  311. async function initPage() {
  312. // 从URL参数获取当前页码(如 ?page=2)
  313. const urlParams = new URLSearchParams(window.location.search);
  314. const pageParam = urlParams.get('page');
  315. if (pageParam && !isNaN(pageParam)) {
  316. currentPage = parseInt(pageParam);
  317. }
  318. // 从后端请求数据(替换模拟数据)
  319. await fetchDataFromBackend();
  320. }
  321. // 核心:从后端API请求数据
  322. async function fetchDataFromBackend() {
  323. // 显示加载状态
  324. tableBody.innerHTML = `
  325. <tr>
  326. <td colspan="3" class="loading">
  327. <i class="fa fa-spinner"></i>
  328. <p>加载中...</p>
  329. </td>
  330. </tr>
  331. `;
  332. paginationContainer.innerHTML = '';
  333. try {
  334. // 1. 构造请求参数(分页+查询条件)
  335. const requestParams = {
  336. page: currentPage, // 当前页码
  337. size: pageSize, // 每页条数
  338. startTime: startTimeInput.value || '', // 开始时间(查询条件)
  339. endTime: endTimeInput.value || '', // 结束时间(查询条件)
  340. receiveStatus: statusSelect.value || '' // 收下状态(查询条件)
  341. };
  342. // 2. 调用导入的API函数
  343. const result = await getLandingDetailApi(requestParams);
  344. // 3. 处理API返回结果
  345. if (result.code === 200) {
  346. const { list, total } = result.data;
  347. totalCount = total;
  348. totalPages = Math.ceil(totalCount / pageSize);
  349. renderTable(list);
  350. renderPagination();
  351. } else {
  352. renderEmptyState('获取数据失败');
  353. }
  354. } catch (error) {
  355. // 捕获异常
  356. console.error('请求数据异常:', error);
  357. renderEmptyState('网络错误,请稍后重试');
  358. }
  359. }
  360. // 渲染表格数据
  361. function renderTable(dataList) {
  362. if (!dataList || dataList.length === 0) {
  363. renderEmptyState('暂无符合条件的数据');
  364. return;
  365. }
  366. let html = '';
  367. dataList.forEach((item, index) => {
  368. // 计算序号:(当前页-1)*每页条数 + 索引+1
  369. const serialNumber = (currentPage - 1) * pageSize + index + 1;
  370. // 注意:item的字段名需与后端返回的字段一致
  371. html += `
  372. <tr>
  373. <td>${serialNumber}</td>
  374. <td>${formatDate(item.openTime || '')}</td>
  375. <td>${item.receiveStatus === '1' ? '是' : item.receiveStatus === '0' ? '否' : ''}</td>
  376. </tr>
  377. `;
  378. });
  379. tableBody.innerHTML = html;
  380. }
  381. // 渲染空状态
  382. function renderEmptyState(message) {
  383. tableBody.innerHTML = `
  384. <tr>
  385. <td colspan="3" style="text-align: center; padding: 30px;">
  386. <i class="fa fa-inbox" style="font-size: 24px; color: #ddd; margin-bottom: 10px;"></i>
  387. <p>${message}</p>
  388. </td>
  389. </tr>
  390. `;
  391. paginationContainer.innerHTML = '';
  392. }
  393. // 渲染分页控件
  394. function renderPagination() {
  395. if (totalCount === 0) return;
  396. // 生成页码列表
  397. const pageNumbers = [];
  398. let startPage = Math.max(1, currentPage - 2);
  399. let endPage = Math.min(totalPages, currentPage + 2);
  400. if (endPage - startPage < 4 && totalPages >= 5) {
  401. if (startPage === 1) endPage = 5;
  402. else if (endPage === totalPages) startPage = totalPages - 4;
  403. }
  404. for (let i = startPage; i <= endPage; i++) {
  405. pageNumbers.push(i);
  406. }
  407. // 分页HTML
  408. const html = `
  409. <div class="pagination-info">
  410. 共 ${totalCount} 条记录,当前第 ${currentPage} / ${totalPages} 页
  411. </div>
  412. <ul class="pagination-list">
  413. <li>
  414. ${currentPage === 1
  415. ? `<span>首页</span>`
  416. : `<a href="?page=1">首页</a>`
  417. }
  418. </li>
  419. <li>
  420. ${currentPage > 1
  421. ? `<a href="?page=${currentPage - 1}">上一页</a>`
  422. : `<span>上一页</span>`
  423. }
  424. </li>
  425. ${pageNumbers.map(num => `
  426. <li>
  427. <a href="?page=${num}" class="${num === currentPage ? 'active' : ''}">
  428. ${num}
  429. </a>
  430. </li>
  431. `).join('')}
  432. <li>
  433. ${currentPage < totalPages
  434. ? `<a href="?page=${currentPage + 1}">下一页</a>`
  435. : `<span>下一页</span>`
  436. }
  437. </li>
  438. <li>
  439. ${currentPage === totalPages
  440. ? `<span>尾页</span>`
  441. : `<a href="?page=${totalPages}">尾页</a>`
  442. }
  443. </li>
  444. </ul>
  445. <div class="pagination-jump">
  446. <span>跳至</span>
  447. <input type="number" min="1" max="${totalPages}" value="${currentPage}" id="jumpPageInput">
  448. <span></span>
  449. <button id="jumpBtn">确定</button>
  450. </div>
  451. `;
  452. paginationContainer.innerHTML = html;
  453. // 绑定跳转事件
  454. document.getElementById('jumpBtn').addEventListener('click', handlePageJump);
  455. document.getElementById('jumpPageInput').addEventListener('keypress', (e) => {
  456. if (e.key === 'Enter') handlePageJump();
  457. });
  458. }
  459. // 处理页码跳转
  460. function handlePageJump() {
  461. const pageInput = document.getElementById('jumpPageInput');
  462. const page = parseInt(pageInput.value);
  463. if (page && !isNaN(page) && page >= 1 && page <= totalPages && page !== currentPage) {
  464. window.location.href = `?page=${page}`;
  465. } else {
  466. alert('请输入有效的页码');
  467. }
  468. }
  469. // 查询按钮事件:点击后重新请求数据
  470. searchBtn.addEventListener('click', async () => {
  471. currentPage = 1; // 重置为第一页
  472. await fetchDataFromBackend(); // 重新请求后端数据
  473. });
  474. // 工具函数:格式化日期(适配后端返回的时间格式)
  475. function formatDate(dateString) {
  476. if (!dateString) return '';
  477. const date = new Date(dateString);
  478. // 处理无效日期
  479. if (isNaN(date.getTime())) return dateString;
  480. // 格式化显示:年-月-日 时:分:秒
  481. return date.toLocaleString('zh-CN', {
  482. year: 'numeric',
  483. month: '2-digit',
  484. day: '2-digit',
  485. hour: '2-digit',
  486. minute: '2-digit',
  487. second: '2-digit'
  488. }).replace(/\//g, '-');
  489. }
  490. // 工具函数:HTML转义(防止XSS攻击)
  491. function escapeHtml(str) {
  492. if (!str) return '';
  493. return str
  494. .replace(/&/g, '&amp;')
  495. .replace(/</g, '&lt;')
  496. .replace(/>/g, '&gt;')
  497. .replace(/"/g, '&quot;')
  498. .replace(/'/g, '&#039;');
  499. }
  500. // 页面加载时初始化
  501. window.addEventListener('DOMContentLoaded', initPage);
  502. </script>
  503. </body>
  504. </html>